diff --git a/drivers/net/ipq9574/ipq9574_aquantia_phy.h b/drivers/net/ipq9574/ipq9574_aquantia_phy.h index 6999a732b4..9ddd6c2740 100644 --- a/drivers/net/ipq9574/ipq9574_aquantia_phy.h +++ b/drivers/net/ipq9574/ipq9574_aquantia_phy.h @@ -38,8 +38,6 @@ #define AQUANTIA_CTRL_RESTART_AUTONEGOTIATION 0x0200 #define AQ_PHY_AUTO_STATUS_REG 0x70001 -#define PORT_LINK_DOWN 0 -#define PORT_LINK_UP 1 #define AQ_PHY_LINK_STATUS_REG 0x7c800 #define SPEED_5G 5 diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index b4160e84f0..593ecf9f92 100755 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -21,6 +21,9 @@ #define IPQ9574_PHY_MAX 6 #define IPQ6018_PHY_MAX 5 #define DEVSOC_PHY_MAX 2 + +#define QCA8084_MAX_PORTS 6 + #define MDIO_CTRL_0_REG 0x00090040 #define MDIO_CTRL_0_DIV(x) (x << 0) #define MDIO_CTRL_0_MODE (1 << 8) @@ -29,6 +32,8 @@ #define MDIO_CTRL_0_GPHY(x) (x << 13) #define MDIO_CTRL_0_RES1(x) (x << 17) +#define PORT_LINK_DOWN 0 +#define PORT_LINK_UP 1 #define GP_PULL_DOWN 1 #define GP_OE_EN (1 << 9) #define GP_VM_EN (1 << 11) @@ -145,6 +150,8 @@ enum phy_mode { typedef struct { u32 phy_address; u32 phy_type; + u32 forced_speed; + u32 forced_duplex; }phy_info_t; struct phy_ops { diff --git a/drivers/net/ipq_common/ipq_qca8084.c b/drivers/net/ipq_common/ipq_qca8084.c index 2a7be7633f..3802145a05 100644 --- a/drivers/net/ipq_common/ipq_qca8084.c +++ b/drivers/net/ipq_common/ipq_qca8084.c @@ -14,21 +14,28 @@ #include "ipq_qca8081.h" #include "ipq_qca8084.h" #include "ipq_qca8084_clk.h" +#include "ipq_qca8084_interface_ctrl.h" +#include #include +#include #include +DECLARE_GLOBAL_DATA_PTR; #ifdef DEBUG #define pr_debug(fmt, args...) printf(fmt, ##args); #else #define pr_debug(fmt, args...) #endif +extern uint32_t ipq_mii_read(uint32_t reg); +extern void ipq_mii_write(uint32_t reg, uint32_t val); extern int ipq_mdio_read(int mii_id, int regnum, ushort *data); extern int ipq_mdio_write(int mii_id, int regnum, u16 data); extern void qca8084_interface_uqxgmii_mode_set(void); -extern void qca8084_gcc_clock_init(void); +extern void qca8084_gcc_clock_init(qca8084_work_mode_t clk_mode, u32 pbmp); +extern void qca8084_gcc_port_clk_parent_set(qca8084_work_mode_t clk_mode, uint32_t qca8084_port_id); extern u8 qca8081_phy_get_link_status(u32 dev_id, u32 phy_id); extern u32 qca8081_phy_get_duplex(u32 dev_id, u32 phy_id, fal_port_duplex_t *duplex); extern u32 qca8081_phy_get_speed(u32 dev_id, u32 phy_id, fal_port_speed_t *speed); @@ -41,6 +48,19 @@ extern void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask, uint8_t enable); extern void qca8084_port_clk_reset(uint32_t qca8084_port_id, uint8_t mask); extern void qca8084_uniphy_uqxgmii_function_reset(uint32_t qca8084_port_id); +extern void qca8084_uniphy_sgmii_function_reset(u32 uniphy_index); +extern void qca8084_interface_sgmii_mode_set(u32 uniphy_index, u32 + qca8084_port_id, mac_config_t *config); +extern void qca8084_clk_reset(const char *clock_id); + +static int qca8084_reg_field_get(u32 reg_addr, u32 bit_offset, + u32 field_len, u8 value[]); +static int qca8084_reg_field_set(u32 reg_addr, u32 bit_offset, + u32 field_len, const u8 value[]); + +bool qca8084_port_txfc_forcemode[QCA8084_MAX_PORTS] = {}; +bool qca8084_port_rxfc_forcemode[QCA8084_MAX_PORTS] = {}; + u16 qca8084_phy_reg_read(u32 phy_addr, u32 reg_id) { @@ -167,6 +187,49 @@ void qca8084_phy_uqxgmii_speed_fixup(uint32_t phy_addr, uint32_t qca8084_port_id qca8084_phy_ipg_config(phy_addr, new_speed); } +void qca8084_phy_sgmii_speed_fixup (u32 phy_addr, + u32 link, fal_port_speed_t new_speed) +{ + /*disable ethphy3 and uniphy0 clock*/ + pr_debug("disable ethphy3 and uniphy0 clock\n"); + qca8084_port_clk_en_set(PORT4, + QCA8084_CLK_TYPE_EPHY, false); + qca8084_port_clk_en_set(PORT5, + QCA8084_CLK_TYPE_UNIPHY, false); + + /*set gmii clock for ethphy3 and uniphy0*/ + pr_debug("set speed clock for uniphy3 and uniphy0\n"); + qca8084_port_speed_clock_set(PORT4, new_speed); + + /*uniphy and ethphy gmii clock enable/disable*/ + pr_debug("uniphy and ethphy GMII clock enable/disable\n"); + if(link) + { + pr_debug("enable ethphy3 and uniphy0 clock\n"); + qca8084_port_clk_en_set(PORT4, + QCA8084_CLK_TYPE_EPHY, true); + qca8084_port_clk_en_set(PORT5, + QCA8084_CLK_TYPE_UNIPHY, true); + } + + /*uniphy and ethphy gmii reset and release*/ + pr_debug("uniphy and ethphy GMII interface reset and release\n"); + qca8084_port_clk_reset(PORT4, + QCA8084_CLK_TYPE_EPHY); + + qca8084_port_clk_reset(PORT5, + QCA8084_CLK_TYPE_UNIPHY); + + /*uniphy and ethphy ipg_tune reset, function reset*/ + pr_debug("uniphy and ethphy ipg_tune reset, function reset\n"); + qca8084_uniphy_sgmii_function_reset(QCA8084_UNIPHY_SGMII_0); + + /*do ethphy function reset*/ + pr_debug("do ethphy function reset\n"); + qca8084_phy_function_reset(phy_addr); + + return; +} void qca8084_phy_interface_mode_set(void) { pr_debug("Configure QCA8084 as PORT_UQXGMII..\n"); @@ -174,7 +237,7 @@ void qca8084_phy_interface_mode_set(void) qca8084_interface_uqxgmii_mode_set(); /*init clock for PORT_UQXGMII*/ - qca8084_gcc_clock_init(); + qca8084_gcc_clock_init(QCA8084_PHY_UQXGMII_MODE, 0); /*init pinctrl for phy mode to be added later*/ } @@ -278,3 +341,1100 @@ void ipq_qca8084_phy_hw_init(struct phy_ops **ops, u32 phy_addr) /* invert ADC clock edge as falling edge to fix link issue */ qca8084_phy_adc_edge_set(phy_addr, ADC_FALLING); } + +/***************************** QCA8084 Pinctrl APIs *************************/ +/**************************************************************************** + * + * 1) PINs default Setting + * + ****************************************************************************/ +#ifdef IN_PINCTRL_DEF_CONFIG +static u64 pin_configs[] = { + QCA8084_PIN_CONFIG_OUTPUT_ENABLE, + QCA8084_PIN_CONFIG_BIAS_PULL_DOWN, +}; +#endif + +static struct qca8084_pinctrl_setting qca8084_pin_settings[] = { + /*PINs default MUX Setting*/ + QCA8084_PIN_SETTING_MUX(0, QCA8084_PIN_FUNC_INTN_WOL), + QCA8084_PIN_SETTING_MUX(1, QCA8084_PIN_FUNC_INTN), + QCA8084_PIN_SETTING_MUX(2, QCA8084_PIN_FUNC_P0_LED_0), + QCA8084_PIN_SETTING_MUX(3, QCA8084_PIN_FUNC_P1_LED_0), + QCA8084_PIN_SETTING_MUX(4, QCA8084_PIN_FUNC_P2_LED_0), + QCA8084_PIN_SETTING_MUX(5, QCA8084_PIN_FUNC_P3_LED_0), + QCA8084_PIN_SETTING_MUX(6, QCA8084_PIN_FUNC_PPS_IN), + QCA8084_PIN_SETTING_MUX(7, QCA8084_PIN_FUNC_TOD_IN), + QCA8084_PIN_SETTING_MUX(8, QCA8084_PIN_FUNC_RTC_REFCLK_IN), + QCA8084_PIN_SETTING_MUX(9, QCA8084_PIN_FUNC_P0_PPS_OUT), + QCA8084_PIN_SETTING_MUX(10, QCA8084_PIN_FUNC_P1_PPS_OUT), + QCA8084_PIN_SETTING_MUX(11, QCA8084_PIN_FUNC_P2_PPS_OUT), + QCA8084_PIN_SETTING_MUX(12, QCA8084_PIN_FUNC_P3_PPS_OUT), + QCA8084_PIN_SETTING_MUX(13, QCA8084_PIN_FUNC_P0_TOD_OUT), + QCA8084_PIN_SETTING_MUX(14, QCA8084_PIN_FUNC_P0_CLK125_TDI), + QCA8084_PIN_SETTING_MUX(15, QCA8084_PIN_FUNC_P0_SYNC_CLKO_PTP), + QCA8084_PIN_SETTING_MUX(16, QCA8084_PIN_FUNC_P0_LED_1), + QCA8084_PIN_SETTING_MUX(17, QCA8084_PIN_FUNC_P1_LED_1), + QCA8084_PIN_SETTING_MUX(18, QCA8084_PIN_FUNC_P2_LED_1), + QCA8084_PIN_SETTING_MUX(19, QCA8084_PIN_FUNC_P3_LED_1), + QCA8084_PIN_SETTING_MUX(20, QCA8084_PIN_FUNC_MDC_M), + QCA8084_PIN_SETTING_MUX(21, QCA8084_PIN_FUNC_MDC_M), + +#ifdef IN_PINCTRL_DEF_CONFIG + /*PINs default Config Setting*/ + QCA8084_PIN_SETTING_CONFIG(0, pin_configs), + QCA8084_PIN_SETTING_CONFIG(1, pin_configs), + QCA8084_PIN_SETTING_CONFIG(2, pin_configs), + QCA8084_PIN_SETTING_CONFIG(3, pin_configs), + QCA8084_PIN_SETTING_CONFIG(4, pin_configs), + QCA8084_PIN_SETTING_CONFIG(5, pin_configs), + QCA8084_PIN_SETTING_CONFIG(6, pin_configs), + QCA8084_PIN_SETTING_CONFIG(7, pin_configs), + QCA8084_PIN_SETTING_CONFIG(8, pin_configs), + QCA8084_PIN_SETTING_CONFIG(9, pin_configs), + QCA8084_PIN_SETTING_CONFIG(10, pin_configs), + QCA8084_PIN_SETTING_CONFIG(11, pin_configs), + QCA8084_PIN_SETTING_CONFIG(12, pin_configs), + QCA8084_PIN_SETTING_CONFIG(13, pin_configs), + QCA8084_PIN_SETTING_CONFIG(14, pin_configs), + QCA8084_PIN_SETTING_CONFIG(15, pin_configs), + QCA8084_PIN_SETTING_CONFIG(16, pin_configs), + QCA8084_PIN_SETTING_CONFIG(17, pin_configs), + QCA8084_PIN_SETTING_CONFIG(18, pin_configs), + QCA8084_PIN_SETTING_CONFIG(19, pin_configs), + QCA8084_PIN_SETTING_CONFIG(20, pin_configs), + QCA8084_PIN_SETTING_CONFIG(21, pin_configs), +#endif +}; + +/**************************************************************************** + * + * 2) PINs Operations + * + ****************************************************************************/ +int qca8084_gpio_set_bit(u32 pin, u32 value) +{ + int rv = 0; + + QCA8084_REG_FIELD_SET(TLMM_GPIO_IN_OUTN, pin, GPIO_OUTE, (u8 *) (&value)); + pr_debug("[%s] select pin:%d value:%d\n", __func__, pin, value); + + return rv; +} + +int qca8084_gpio_get_bit(u32 pin, u32 *data) +{ + int rv = 0; + + QCA8084_REG_FIELD_GET(TLMM_GPIO_IN_OUTN, pin, GPIO_IN, (u8 *) (data)); + pr_debug("[%s] select pin:%d value:%d\n", __func__, pin, *data); + + return rv; +} + +int qca8084_gpio_pin_mux_set(u32 pin, u32 func) +{ + int rv = 0; + + pr_debug("[%s] select pin:%d func:%d\n", __func__, pin, func); + QCA8084_REG_FIELD_SET(TLMM_GPIO_CFGN, pin, FUNC_SEL, (u8 *) (&func)); + + return rv; +} + +int qca8084_gpio_pin_cfg_set_bias(u32 pin, enum qca8084_pin_config_param bias) +{ + int rv = 0; + u32 data = 0; + + switch (bias) + { + case QCA8084_PIN_CONFIG_BIAS_DISABLE: + data = QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DISABLE; + break; + case QCA8084_PIN_CONFIG_BIAS_PULL_DOWN: + data = QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DOWN; + break; + case QCA8084_PIN_CONFIG_BIAS_BUS_HOLD: + data = QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_BUS_HOLD; + break; + case QCA8084_PIN_CONFIG_BIAS_PULL_UP: + data = QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_UP; + break; + default: + printf("[%s] doesn't support bias:%d\n", __func__, bias); + return -1; + } + + QCA8084_REG_FIELD_SET(TLMM_GPIO_CFGN, pin, GPIO_PULL, + (u8 *) (&data)); + pr_debug("[%s]pin:%d bias:%d", __func__, pin, bias); + + return rv; +} + +int qca8084_gpio_pin_cfg_get_bias(u32 pin, enum qca8084_pin_config_param *bias) +{ + int rv = 0; + u32 data = 0; + + QCA8084_REG_FIELD_GET(TLMM_GPIO_CFGN, pin, GPIO_PULL, + (u8 *) (&data)); + switch (data) + { + case QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DISABLE: + *bias = QCA8084_PIN_CONFIG_BIAS_DISABLE; + break; + case QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DOWN: + *bias = QCA8084_PIN_CONFIG_BIAS_PULL_DOWN; + break; + case QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_BUS_HOLD: + *bias = QCA8084_PIN_CONFIG_BIAS_BUS_HOLD; + break; + case QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_UP: + *bias = QCA8084_PIN_CONFIG_BIAS_PULL_UP; + break; + default: + printf("[%s] doesn't support bias:%d\n", __func__, data); + return -1; + } + pr_debug("[%s]pin:%d bias:%d", __func__, pin, *bias); + + return rv; +} + +int qca8084_gpio_pin_cfg_set_drvs(u32 pin, u32 drvs) +{ + int rv = 0; + + if((drvs < QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_2_MA) || + (drvs > QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_16_MA)) { + printf("[%s] doesn't support drvs:%d\n", __func__, drvs); + return -1; + } + + QCA8084_REG_FIELD_SET(TLMM_GPIO_CFGN, pin, DRV_STRENGTH, + (u8 *) (&drvs)); + pr_debug("[%s]%d", __func__, pin); + + return rv; +} + +int qca8084_gpio_pin_cfg_get_drvs(u32 pin, u32 *drvs) +{ + int rv = 0; + + QCA8084_REG_FIELD_GET(TLMM_GPIO_CFGN, pin, DRV_STRENGTH, + (u8 *) (drvs)); + pr_debug("[%s]%d", __func__, pin); + + return rv; +} + +int qca8084_gpio_pin_cfg_set_oe(u32 pin, bool oe) +{ + int rv = 0; + + pr_debug("[%s]%d oe:%d", __func__, pin, oe); + + QCA8084_REG_FIELD_SET(TLMM_GPIO_CFGN, pin, GPIO_OEA, + (u8 *) (&oe)); + + return rv; +} + +int qca8084_gpio_pin_cfg_get_oe(u32 pin, bool *oe) +{ + int rv = 0; + u32 data = 0; + + QCA8084_REG_FIELD_GET(TLMM_GPIO_CFGN, pin, GPIO_OEA, + (u8 *) (&data)); + *oe = data ? true : false; + + pr_debug("[%s]%d oe:%d", __func__, pin, *oe); + + return rv; +} + +static inline enum qca8084_pin_config_param pinconf_to_config_param(unsigned long config) +{ + return (enum qca8084_pin_config_param) (config & 0xffUL); +} + +static inline u32 pinconf_to_config_argument(unsigned long config) +{ + return (u32) ((config >> 8) & 0xffffffUL); +} + +static int qca8084_gpio_pin_cfg_set(u32 pin, + u64 *configs, u32 num_configs) +{ + enum qca8084_pin_config_param param; + u32 i, arg; + int rv = 0; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case QCA8084_PIN_CONFIG_BIAS_BUS_HOLD: + case QCA8084_PIN_CONFIG_BIAS_DISABLE: + case QCA8084_PIN_CONFIG_BIAS_PULL_DOWN: + case QCA8084_PIN_CONFIG_BIAS_PULL_UP: + rv = qca8084_gpio_pin_cfg_set_bias(pin, param); + break; + + case QCA8084_PIN_CONFIG_DRIVE_STRENGTH: + rv = qca8084_gpio_pin_cfg_set_drvs(pin, arg); + break; + + case QCA8084_PIN_CONFIG_OUTPUT: + rv = qca8084_gpio_pin_cfg_set_oe(pin, true); + rv = qca8084_gpio_set_bit(pin, arg); + break; + + case QCA8084_PIN_CONFIG_INPUT_ENABLE: + rv = qca8084_gpio_pin_cfg_set_oe(pin, false); + break; + + case QCA8084_PIN_CONFIG_OUTPUT_ENABLE: + rv = qca8084_gpio_pin_cfg_set_oe(pin, true); + break; + + default: + printf("%s %d doesn't support:%d \n", __func__, __LINE__, param); + return -1; + } + } + + return rv; +} + + +/**************************************************************************** + * + * 3) PINs Init + * + ****************************************************************************/ +int qca8084_pinctrl_clk_gate_set(bool gate_en) +{ + int rv = 0; + + QCA8084_REG_FIELD_SET(TLMM_CLK_GATE_EN, 0, AHB_HCLK_EN, + (u8 *) (&gate_en)); + QCA8084_REG_FIELD_SET(TLMM_CLK_GATE_EN, 0, SUMMARY_INTR_EN, + (u8 *) (&gate_en)); + QCA8084_REG_FIELD_SET(TLMM_CLK_GATE_EN, 0, CRIF_READ_EN, + (u8 *) (&gate_en)); + + pr_debug("[%s] gate_en:%d", __func__, gate_en); + + return rv; +} + +static int qca8084_pinctrl_rev_check(void) +{ + int rv = 0; + u32 version_id = 0, mfg_id = 0, start_bit = 0; + + QCA8084_REG_FIELD_GET(TLMM_HW_REVISION_NUMBER, 0, VERSION_ID, + (u8 *) (&version_id)); + QCA8084_REG_FIELD_GET(TLMM_HW_REVISION_NUMBER, 0, MFG_ID, + (u8 *) (&mfg_id)); + QCA8084_REG_FIELD_GET(TLMM_HW_REVISION_NUMBER, 0, START_BIT, + (u8 *) (&start_bit)); + + pr_debug("[%s] version_id:0x%x mfg_id:0x%x start_bit:0x%x", + __func__, version_id, mfg_id, start_bit); + + if((version_id == 0x0) && (mfg_id == 0x70) && (start_bit == 0x1)) { + pr_debug(" Pinctrl Version Check Pass\n"); + } else { + printf("Error: Pinctrl Version Check Fail\n"); + rv = -1; + } + + return rv; +} + +static int qca8084_pinctrl_hw_init(void) +{ + int rv = 0; + + rv = qca8084_pinctrl_clk_gate_set(true); + rv = qca8084_pinctrl_rev_check(); + + return rv; +} + +static int qca8084_pinctrl_setting_init(const struct qca8084_pinctrl_setting *pin_settings, + u32 num_setting) +{ + int rv = 0; + u32 i; + + for(i = 0; i < num_setting; i++) { + const struct qca8084_pinctrl_setting *setting = &pin_settings[i]; + if (setting->type == QCA8084_PIN_MAP_TYPE_MUX_GROUP) { + rv = qca8084_gpio_pin_mux_set(setting->data.mux.pin, setting->data.mux.func); + + } else if (setting->type == QCA8084_PIN_MAP_TYPE_CONFIGS_PIN) { + rv = qca8084_gpio_pin_cfg_set(setting->data.configs.pin, + setting->data.configs.configs, + setting->data.configs.num_configs); + } + } + + return rv; +} + +int ipq_qca8084_pinctrl_init(void) +{ + qca8084_pinctrl_hw_init(); + qca8084_pinctrl_setting_init(qca8084_pin_settings, ARRAY_SIZE(qca8084_pin_settings)); + return 0; +} + +/******************************************************************************************/ +/************************* New Code *******************************************************/ +/******************************************************************************************/ + +static int qca8084_reg_field_get(u32 reg_addr, u32 bit_offset, + u32 field_len, u8 value[]) +{ + u32 reg_val = ipq_mii_read(reg_addr); + + *((u32 *) value) = SW_REG_2_FIELD(reg_val, bit_offset, field_len); + return 0; +} + +static int qca8084_reg_field_set(u32 reg_addr, u32 bit_offset, + u32 field_len, const u8 value[]) +{ + u32 field_val = *((u32 *) value); + u32 reg_val = ipq_mii_read(reg_addr); + + SW_REG_SET_BY_FIELD_U32(reg_val, field_val, bit_offset, field_len); + + ipq_mii_write(reg_addr, reg_val); + return 0; +} + +static inline void ipq_qca8084_switch_reset(void) +{ + /* Reset switch core */ + qca8084_clk_reset(QCA8084_SWITCH_CORE_CLK); + + /* Reset MAC ports */ + qca8084_clk_reset(QCA8084_MAC0_TX_CLK); + qca8084_clk_reset(QCA8084_MAC0_RX_CLK); + qca8084_clk_reset(QCA8084_MAC1_TX_CLK); + qca8084_clk_reset(QCA8084_MAC1_RX_CLK); + qca8084_clk_reset(QCA8084_MAC2_TX_CLK); + qca8084_clk_reset(QCA8084_MAC2_RX_CLK); + qca8084_clk_reset(QCA8084_MAC3_TX_CLK); + qca8084_clk_reset(QCA8084_MAC3_RX_CLK); + qca8084_clk_reset(QCA8084_MAC4_TX_CLK); + qca8084_clk_reset(QCA8084_MAC4_RX_CLK); + qca8084_clk_reset(QCA8084_MAC5_TX_CLK); + qca8084_clk_reset(QCA8084_MAC5_RX_CLK); + return; +} + +static void ipq_qca8084_work_mode_set(qca8084_work_mode_t work_mode) +{ + u32 data = 0; + + data = ipq_mii_read(WORK_MODE_OFFSET); + data &= ~QCA8084_WORK_MODE_MASK; + data |= work_mode; + + ipq_mii_write(WORK_MODE_OFFSET, data); + return; +} + +static void ipq_qca8084_work_mode_get(qca8084_work_mode_t *work_mode) +{ + u32 data = 0; + + data = ipq_mii_read(WORK_MODE_OFFSET); + pr_debug("work mode reg is 0x%x\n", data); + + *work_mode = data & QCA8084_WORK_MODE_MASK; + return; +} + +static int ipq_qca8084_work_mode_init(int mac_mode0, int mac_mode1) +{ + int ret = 0; + + switch (mac_mode0) { + case EPORT_WRAPPER_SGMII_PLUS: + case EPORT_WRAPPER_SGMII_CHANNEL0: + break; + default: + /** not supported */ + printf("%s %d Error: Unsupported mac_mode0 \n", __func__, __LINE__); + return -1; + } + + switch (mac_mode1) { + case EPORT_WRAPPER_SGMII_PLUS: + case EPORT_WRAPPER_SGMII_CHANNEL0: + ipq_qca8084_work_mode_set(QCA8084_SWITCH_MODE); + break; + case EPORT_WRAPPER_MAX: + ipq_qca8084_work_mode_set(QCA8084_SWITCH_BYPASS_PORT5_MODE); + default: + printf("%s %d Error: Unsupported mac_mode1 \n", __func__, __LINE__); + return -1; + } + + return ret; +} + +static int chip_ver_get(void) +{ + int ret = 0; + u8 chip_ver; + u32 reg_val = ipq_mii_read(0); + + chip_ver = (reg_val & 0xFF00) >> 8; + + /*qca8084_start*/ + switch (chip_ver) { + case QCA_VER_QCA8084: + ret = CHIP_QCA8084; + break; + default: + printf("Error: Unsupported chip \n"); + ret = -1; + break; + } + + return ret; +} + + +bool qca8084_port_phy_connected(u32 port_id) +{ + u32 cpu_bmp = 0x1; + if ((cpu_bmp & BIT(port_id)) || (port_id == PORT1) || + (port_id == PORT5)) + return false; + + return true; +} + + +static void qca8084_port_txmac_status_set(u32 port_id, bool enable) +{ + u32 reg, force, val = 0, tmp; + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®)); + + if (true == enable) + { + val = 1; + } + else if (false == enable) + { + val = 0; + } + tmp = reg; + + /* for those ports without PHY device we set MAC register */ + if (false == qca8084_port_phy_connected(port_id)) + { + SW_SET_REG_BY_FIELD(PORT_STATUS, LINK_EN, 0, reg); + SW_SET_REG_BY_FIELD(PORT_STATUS, TXMAC_EN, val, reg); + } + else + { + SW_GET_FIELD_BY_REG(PORT_STATUS, LINK_EN, force, reg); + if (force) + { + /* link isn't in force mode so can't set */ + printf("%s %d Error: SW disable \n", __func__, __LINE__); + return; + } + else + { + SW_SET_REG_BY_FIELD(PORT_STATUS, TXMAC_EN, val, reg); + } + } + + if (tmp == reg) + return; + + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®)); + return; +} + +static void qca8084_port_rxmac_status_set(u32 port_id, bool enable) +{ + u32 reg = 0, force, val = 0, tmp; + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®)); + + if (true == enable) + { + val = 1; + } + else if (false == enable) + { + val = 0; + } + tmp = reg; + + /* for those ports without PHY device we set MAC register */ + if (false == qca8084_port_phy_connected(port_id)) + { + SW_SET_REG_BY_FIELD(PORT_STATUS, LINK_EN, 0, reg); + SW_SET_REG_BY_FIELD(PORT_STATUS, RXMAC_EN, val, reg); + } + else + { + SW_GET_FIELD_BY_REG(PORT_STATUS, LINK_EN, force, reg); + if (force) + { + /* link isn't in force mode so can't set */ + printf("%s %d Error: SW disable \n", __func__, __LINE__); + return; + } + else + { + SW_SET_REG_BY_FIELD(PORT_STATUS, RXMAC_EN, val, reg); + } + } + if (tmp == reg) + return; + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®)); + return; +} + +static void qca8084_port_rxfc_status_set(u32 port_id, bool enable) +{ + u32 val = 0, reg, tmp; + + if (true == enable) + { + val = 1; + } + else if (false == enable) + { + val = 0; + } + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®)); + tmp = reg; + + SW_SET_REG_BY_FIELD(PORT_STATUS, RX_FLOW_EN, val, reg); + + if ( tmp == reg) + return; + + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®)); + return; +} + +static void qca8084_port_txfc_status_set(u32 port_id, bool enable) +{ + u32 val, reg = 0, tmp; + + if (true == enable) + { + val = 1; + } + else if (false == enable) + { + val = 0; + } + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®)); + tmp = reg; + + SW_SET_REG_BY_FIELD(PORT_STATUS, TX_FLOW_EN, val, reg); + SW_SET_REG_BY_FIELD(PORT_STATUS, TX_HALF_FLOW_EN, val, reg); + + if (tmp == reg) + return; + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®)); + + return; +} + +static void qca8084_port_flowctrl_set(u32 port_id, bool enable) +{ + qca8084_port_txfc_status_set(port_id, enable); + qca8084_port_rxfc_status_set(port_id, enable); + return; +} + +static void qca8084_port_flowctrl_forcemode_set(u32 port_id, bool enable) +{ + qca8084_port_txfc_forcemode[port_id] = enable; + qca8084_port_rxfc_forcemode[port_id] = enable; + return; +} + +static void header_type_set(bool enable, u32 type) +{ + u32 reg = 0; + + QCA8084_REG_ENTRY_GET(HEADER_CTL, 0, (u8 *) (®)); + + if (true == enable) + { + if (0xffff < type) + { + printf("%s %d Error: Bad param \n", __func__, __LINE__); + return; + } + SW_SET_REG_BY_FIELD(HEADER_CTL, TYPE_LEN, 1, reg); + SW_SET_REG_BY_FIELD(HEADER_CTL, TYPE_VAL, type, reg); + } + else if (false == enable) + { + SW_SET_REG_BY_FIELD(HEADER_CTL, TYPE_LEN, 0, reg); + SW_SET_REG_BY_FIELD(HEADER_CTL, TYPE_VAL, 0, reg); + } + + QCA8084_REG_ENTRY_SET(HEADER_CTL, 0, (u8 *) (®)); + return; +} + +static void port_rxhdr_mode_set(u32 port_id, port_header_mode_t mode) +{ + u32 val = 0; + if (FAL_NO_HEADER_EN == mode) + { + val = 0; + } + else if (FAL_ONLY_MANAGE_FRAME_EN == mode) + { + val = 1; + } + else if (FAL_ALL_TYPE_FRAME_EN == mode) + { + val = 2; + } + else + { + printf("%s %d Error: Bad param \n", __func__, __LINE__); + return; + } + + QCA8084_REG_FIELD_SET(PORT_HDR_CTL, port_id, RXHDR_MODE,(u8 *) (&val)); + return; +} + +static void port_txhdr_mode_set(u32 port_id, port_header_mode_t mode) +{ + u32 val = 0; + if (FAL_NO_HEADER_EN == mode) + { + val = 0; + } + else if (FAL_ONLY_MANAGE_FRAME_EN == mode) + { + val = 1; + } + else if (FAL_ALL_TYPE_FRAME_EN == mode) + { + val = 2; + } + else + { + printf("%s %d Error: Bad param \n", __func__, __LINE__); + return; + } + + QCA8084_REG_FIELD_SET(PORT_HDR_CTL, port_id, TXHDR_MODE, (u8 *) (&val)); + return; +} + + +int qca8084_phy_get_status(u32 phy_id, struct port_phy_status *phy_status) +{ + u16 phy_data; + + phy_data = qca8084_phy_reg_read(phy_id, QCA8084_PHY_SPEC_STATUS); + + /*get phy link status*/ + if (phy_data & QCA8084_STATUS_LINK_PASS) { + phy_status->link_status = true; + } + else { + phy_status->link_status = false; + + /*when link down, phy speed is set as 10M*/ + phy_status->speed = FAL_SPEED_10; + return 0; + } + + /*get phy speed*/ + switch (phy_data & QCA8084_STATUS_SPEED_MASK) { + case QCA8084_STATUS_SPEED_2500MBS: + phy_status->speed = FAL_SPEED_2500; + break; + case QCA8084_STATUS_SPEED_1000MBS: + phy_status->speed = FAL_SPEED_1000; + break; + case QCA8084_STATUS_SPEED_100MBS: + phy_status->speed = FAL_SPEED_100; + break; + case QCA8084_STATUS_SPEED_10MBS: + phy_status->speed = FAL_SPEED_10; + break; + default: + return -1; + } + + /*get phy duplex*/ + if (phy_data & QCA8084_STATUS_FULL_DUPLEX) { + phy_status->duplex = FAL_FULL_DUPLEX; + } else { + phy_status->duplex = FAL_HALF_DUPLEX; + } + + /* get phy flowctrl resolution status */ + if (phy_data & QCA8084_PHY_RX_FLOWCTRL_STATUS) { + phy_status->rx_flowctrl = true; + } else { + phy_status->rx_flowctrl = false; + } + + if (phy_data & QCA8084_PHY_TX_FLOWCTRL_STATUS) { + phy_status->tx_flowctrl = true; + } else { + phy_status->tx_flowctrl = false; + } + + return 0; +} + + +static void qca8084_port_mac_dupex_set(u32 port_id, u32 duplex) +{ + u32 reg_val = 0, tmp; + u32 duplex_val; + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®_val)); + tmp = reg_val; + + if (FAL_HALF_DUPLEX == duplex) { + duplex_val = QCA8084_PORT_HALF_DUPLEX; + } else { + duplex_val = QCA8084_PORT_FULL_DUPLEX; + } + SW_SET_REG_BY_FIELD(PORT_STATUS, DUPLEX_MODE, duplex_val, reg_val); + + if (tmp == reg_val) + return; + + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®_val)); + return; +} + +static void qca8084_port_duplex_set(u32 port_id, fal_port_duplex_t duplex, + phy_info_t * phy_info) +{ + /* for those ports without PHY device we set MAC register */ + if (false == qca8084_port_phy_connected(port_id)) + { + qca8084_port_mac_dupex_set(port_id, duplex); + } + else + { + printf("%s %d Error: Duplex/Speed set for QCA8084 PORT1-4" + "is not implemented \n", __func__, __LINE__); + } + return; +} + +static void qca8084_port_mac_speed_set(u32 port_id, u32 speed) +{ + u32 reg_val = 0, tmp; + u32 speed_val; + + QCA8084_REG_ENTRY_GET(PORT_STATUS, port_id, (u8 *) (®_val)); + tmp = reg_val; + + if (FAL_SPEED_10 == speed) { + speed_val = QCA8084_PORT_SPEED_10M; + } else if (FAL_SPEED_100 == speed) { + speed_val = QCA8084_PORT_SPEED_100M; + } else if (FAL_SPEED_1000 == speed) { + speed_val = QCA8084_PORT_SPEED_1000M; + } else if (FAL_SPEED_2500 == speed) { + speed_val = QCA8084_PORT_SPEED_2500M; + } else { + printf("%s %d Bad param \n",__func__, __LINE__); + return; + } + SW_SET_REG_BY_FIELD(PORT_STATUS, SPEED_MODE, speed_val, reg_val); + + if (tmp == reg_val) + return; + + QCA8084_REG_ENTRY_SET(PORT_STATUS, port_id, (u8 *) (®_val)); + return; +} + +static void qca8084_port_speed_set(u32 port_id, fal_port_speed_t speed, + phy_info_t * phy_info) +{ + /* for those ports without PHY device we set MAC register */ + if (false == qca8084_port_phy_connected(port_id)) + { + qca8084_port_mac_speed_set(port_id, speed); + } + else + { + printf("%s %d Error: Duplex/Speed set for QCA8084 PORT1-4" + "is not implemented \n", __func__, __LINE__); + } + return; +} + +static int _qca8084_interface_mode_init(u32 port_id, u32 mac_mode, + phy_info_t * phy_info) +{ + u32 uniphy_index = 0; + mac_config_t config; + u32 force_speed = FAL_SPEED_BUTT; + qca8084_work_mode_t work_mode = QCA8084_SWITCH_MODE; + + if (phy_info->forced_speed) { + force_speed = phy_info->forced_speed; + + qca8084_port_speed_set(port_id, force_speed, phy_info); + + qca8084_port_duplex_set(port_id, FAL_FULL_DUPLEX, phy_info); + + /* The clock parent need to be configured before initializing + * the interface mode. */ + ipq_qca8084_work_mode_get(&work_mode); + qca8084_gcc_port_clk_parent_set(work_mode, port_id); + } + + + if(mac_mode == EPORT_WRAPPER_SGMII_PLUS) + config.mac_mode = QCA8084_MAC_MODE_SGMII_PLUS; + else if(mac_mode == EPORT_WRAPPER_SGMII_CHANNEL0) + config.mac_mode = QCA8084_MAC_MODE_SGMII; + else { + printf("%s %d Unsupported mac mode \n", __func__, __LINE__); + return -1; + } + + /*get uniphy index*/ + if(port_id == PORT0) + uniphy_index = QCA8084_UNIPHY_SGMII_1; + else if(port_id == PORT5) + uniphy_index = QCA8084_UNIPHY_SGMII_0; + else { + printf("%s %d Unsupported mac_mode \n", __func__, __LINE__); + return -1; + } + + config.clock_mode = QCA8084_INTERFACE_CLOCK_MAC_MODE; + config.auto_neg = !(phy_info->forced_speed); + config.force_speed = force_speed; + + qca8084_interface_sgmii_mode_set(uniphy_index, port_id, &config); + + /*do sgmii function reset*/ + pr_debug("ipg_tune reset and function reset\n"); + qca8084_uniphy_sgmii_function_reset(uniphy_index); + return 0; +} + +static int ipq_qca8084_interface_mode_init(u32 mac_mode0, u32 mac_mode1, phy_info_t * phy_info[]) +{ + int ret = 0; + + ret = _qca8084_interface_mode_init(PORT0, mac_mode0, phy_info[PORT0]); + if (ret < 0) + return ret; + + ret = _qca8084_interface_mode_init(PORT5, mac_mode1, phy_info[PORT5]); + if (ret < 0) + return ret; + + if (phy_info[PORT0]->forced_speed) { + qca8084_port_txmac_status_set(PORT0, true); + qca8084_port_rxmac_status_set(PORT0, true); + } + + if (phy_info[PORT5]->forced_speed) { + qca8084_port_txmac_status_set(PORT5, true); + qca8084_port_rxmac_status_set(PORT5, true); + } + return ret; +} + + +void port_link_update(u32 port_id, struct port_phy_status phy_status) +{ + /* configure gcc uniphy and mac speed frequency*/ + qca8084_port_speed_clock_set(port_id, phy_status.speed); + + /* configure mac speed and duplex */ + qca8084_port_mac_speed_set(port_id, phy_status.speed); + qca8084_port_mac_dupex_set(port_id, phy_status.duplex); + pr_debug("mht port %d link %d update speed %d duplex %d\n", + port_id, phy_status.speed, + phy_status.speed, phy_status.duplex); + if (phy_status.link_status == PORT_LINK_UP) + { + /* sync mac flowctrl */ + if (qca8084_port_txfc_forcemode[port_id] != true) { + qca8084_port_txfc_status_set(port_id, phy_status.tx_flowctrl); + pr_debug("mht port %d link up update txfc %d\n", + port_id, phy_status.tx_flowctrl); + } + if (qca8084_port_rxfc_forcemode[port_id] != true) { + qca8084_port_rxfc_status_set(port_id, phy_status.rx_flowctrl); + pr_debug("mht port %d link up update rxfc %d\n", + port_id, phy_status.rx_flowctrl); + } + if (port_id != PORT5) { + /* enable eth phy clock */ + qca8084_port_clk_en_set(port_id, QCA8084_CLK_TYPE_EPHY, true); + } + } + if (port_id != PORT5) { + if (phy_status.link_status == PORT_LINK_DOWN) { + /* disable eth phy clock */ + qca8084_port_clk_en_set(port_id, QCA8084_CLK_TYPE_EPHY, false); + } + /* reset eth phy clock */ + qca8084_port_clk_reset(port_id, QCA8084_CLK_TYPE_EPHY); + /* reset eth phy fifo */ + qca8084_phy_function_reset(port_id); + } + return; +} + +void qca_switch_init(u32 port_bmp, u32 cpu_bmp, phy_info_t * phy_info[]) +{ + int i = 0; + + port_bmp |= cpu_bmp; + while (port_bmp) { + pr_debug("configuring port: %d \n", i); + if (port_bmp & 1) { + qca8084_port_txmac_status_set(i, false); + qca8084_port_rxmac_status_set(i, false); + + if (cpu_bmp & BIT(i)) { + qca8084_port_flowctrl_set(i, false); + qca8084_port_flowctrl_forcemode_set(i, true); + + header_type_set(true, QCA8084_HEADER_TYPE_VAL); + port_rxhdr_mode_set(i, FAL_ONLY_MANAGE_FRAME_EN); + port_txhdr_mode_set(i, FAL_NO_HEADER_EN); + } else { + qca8084_port_flowctrl_set(i, true); + qca8084_port_flowctrl_forcemode_set(i, false); + } + } + port_bmp >>=1; + i++; + } + return; +} +/**************************************************************************/ +void ipq_qca8084_link_update(u32 port_id) +{ + struct port_phy_status phy_status = {0}; + int rv = qca8084_phy_get_status(port_id, &phy_status); + if (rv < 0) { + printf("%s %d failed get phy status of idx %d \n", + __func__, __LINE__, port_id); + return; + } + + if (phy_status.link_status == PORT_LINK_DOWN) { + /* enable mac rx function */ + qca8084_port_rxmac_status_set(port_id, false); + /* enable mac tx function */ + qca8084_port_txmac_status_set(port_id, false); + /* update gcc, mac speed, mac duplex and phy stauts */ + port_link_update(port_id, phy_status); + } + + if (phy_status.link_status == PORT_LINK_UP) { + /* update gcc, mac speed, mac duplex and phy stauts */ + port_link_update(port_id, phy_status); + /* enable mac tx function */ + qca8084_port_txmac_status_set(port_id, true); + /* enable mac rx function */ + qca8084_port_rxmac_status_set(port_id, true); + } + return; +} + +int ipq_qca8084_hw_init(phy_info_t * phy_info[]) +{ + int ret = 0; + int mode0 = -1, mode1 = -1, node = -1; + qca8084_work_mode_t work_mode; + u32 port_bmp = 0x3e, cpu_bmp = 0x1; + + int chip_type = chip_ver_get(); + + if (chip_type != CHIP_QCA8084) { + printf("Error: Unsupported chip_type \n"); + return -1; + } + + node = fdt_path_offset(gd->fdt_blob, "/ess-switch/qca8084_swt_info"); + mode0 = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode0", -1); + if (mode0 < 0) { + printf("Error: switch_mac_mode0 not specified in dts\n"); + return mode0; + } + + mode1 = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode1", -1); + if (mode1 < 0) { + printf("Error: switch_mac_mode1 not specified in dts\n"); + return mode1; + } + + ipq_qca8084_switch_reset(); + + ret = ipq_qca8084_work_mode_init(mode0, mode1); + if (ret < 0) + return ret; + + qca_switch_init(port_bmp, cpu_bmp, phy_info); + + ret = ipq_qca8084_interface_mode_init(mode0, mode1, phy_info); + if (ret < 0) + return ret; + + port_bmp |= cpu_bmp; + + ipq_qca8084_work_mode_get(&work_mode); + qca8084_gcc_clock_init(work_mode, port_bmp); + + ret = ipq_qca8084_pinctrl_init(); + return ret; +} + +void ipq_qca8084_switch_hw_reset(int gpio) +{ + unsigned int *switch_gpio_base = + (unsigned int *)GPIO_CONFIG_ADDR(gpio); + + writel(0x203, switch_gpio_base); + writel(0x0, GPIO_IN_OUT_ADDR(gpio)); + mdelay(500); + writel(0x2, GPIO_IN_OUT_ADDR(gpio)); +} + diff --git a/drivers/net/ipq_common/ipq_qca8084.h b/drivers/net/ipq_common/ipq_qca8084.h index 4f93c47e75..7e844654fd 100644 --- a/drivers/net/ipq_common/ipq_qca8084.h +++ b/drivers/net/ipq_common/ipq_qca8084.h @@ -14,6 +14,12 @@ #ifndef _QCA8084_PHY_H_ #define _QCA8084_PHY_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif + /*MII register*/ #define QCA8084_PHY_FIFO_CONTROL 0x19 @@ -63,10 +69,95 @@ #define QCA8084_DEBUG_PORT_DATA 30 #define QCA8084_PHY_CONTROL 0 +#define QCA8084_AUTONEG_ADVERT 4 +#define QCA8084_LINK_PARTNER_ABILITY 5 +#define QCA8084_1000BASET_CONTROL 9 +#define QCA8084_1000BASET_STATUS 10 +#define QCA8084_PHY_SPEC_STATUS 17 +#define QCA8084_CTRL_AUTONEGOTIATION_ENABLE 0x1000 #define QCA8084_CTRL_SOFTWARE_RESET 0x8000 + +#define QCA8084_STATUS_LINK_PASS 0x0400 #define PHY_INVALID_DATA 0xffff +#define QCA8084_PHY_MMD7_AUTONEGOTIATION_CONTROL 0x20 +#define QCA8084_PHY_MMD7_LP_2500M_ABILITY 0x21 + + /* Auto-Negotiation Advertisement register. offset:4 */ +#define QCA8084_ADVERTISE_SELECTOR_FIELD 0x0001 + + /* 10T Half Duplex Capable */ +#define QCA8084_ADVERTISE_10HALF 0x0020 + + /* 10T Full Duplex Capable */ +#define QCA8084_ADVERTISE_10FULL 0x0040 + + /* 100TX Half Duplex Capable */ +#define QCA8084_ADVERTISE_100HALF 0x0080 + + /* 100TX Full Duplex Capable */ +#define QCA8084_ADVERTISE_100FULL 0x0100 + + /* 100T4 Capable */ +#define QCA8084_ADVERTISE_100T4 0x0200 + + /* Pause operation desired */ +#define QCA8084_ADVERTISE_PAUSE 0x0400 + + /* Asymmetric Pause Direction bit */ +#define QCA8084_ADVERTISE_ASYM_PAUSE 0x0800 + + /* Remote Fault detected */ +#define QCA8084_ADVERTISE_REMOTE_FAULT 0x2000 + + /* 1000TX Half Duplex Capable */ +#define QCA8084_ADVERTISE_1000HALF 0x0100 + + /* 1000TX Full Duplex Capable */ +#define QCA8084_ADVERTISE_1000FULL 0x0200 + + /* 2500TX Full Duplex Capable */ +#define QCA8084_ADVERTISE_2500FULL 0x80 + +#define QCA8084_ADVERTISE_ALL \ + (QCA8084_ADVERTISE_10HALF | QCA8084_ADVERTISE_10FULL | \ + QCA8084_ADVERTISE_100HALF | QCA8084_ADVERTISE_100FULL | \ + QCA8084_ADVERTISE_1000FULL) + +#define QCA8084_ADVERTISE_MEGA_ALL \ + (QCA8084_ADVERTISE_10HALF | QCA8084_ADVERTISE_10FULL | \ + QCA8084_ADVERTISE_100HALF | QCA8084_ADVERTISE_100FULL | \ + QCA8084_ADVERTISE_PAUSE | QCA8084_ADVERTISE_ASYM_PAUSE) + +/* FDX =1, half duplex =0 */ +#define QCA8084_CTRL_FULL_DUPLEX 0x0100 + + /* Restart auto negotiation */ +#define QCA8084_CTRL_RESTART_AUTONEGOTIATION 0x0200 + + /* 1=Duplex 0=Half Duplex */ +#define QCA8084_STATUS_FULL_DUPLEX 0x2000 +#define QCA8084_PHY_RX_FLOWCTRL_STATUS 0x4 +#define QCA8084_PHY_TX_FLOWCTRL_STATUS 0x8 + + /* Speed, bits 9:7 */ +#define QCA8084_STATUS_SPEED_MASK 0x380 + + + /* 000=10Mbs */ +#define QCA8084_STATUS_SPEED_10MBS 0x0000 + + /* 001=100Mbs */ +#define QCA8084_STATUS_SPEED_100MBS 0x80 + + /* 010=1000Mbs */ +#define QCA8084_STATUS_SPEED_1000MBS 0x100 + + /* 100=2500Mbs */ +#define QCA8084_STATUS_SPEED_2500MBS 0x200 + + #define QCA8084_MII_ADDR_C45 (1<<30) #define QCA8084_REG_C45_ADDRESS(dev_type, reg_num) (QCA8084_MII_ADDR_C45 | \ ((dev_type & 0x1f) << 16) | (reg_num & 0xffff)) @@ -77,4 +168,520 @@ typedef enum { } qca8084_adc_edge_t; +//phy autoneg adv +#define FAL_PHY_ADV_10T_HD 0x01 +#define FAL_PHY_ADV_10T_FD 0x02 +#define FAL_PHY_ADV_100TX_HD 0x04 +#define FAL_PHY_ADV_100TX_FD 0x08 +//#define FAL_PHY_ADV_1000T_HD 0x100 +#define FAL_PHY_ADV_1000T_FD 0x200 +#define FAL_PHY_ADV_1000BX_HD 0x400 +#define FAL_PHY_ADV_1000BX_FD 0x800 +#define FAL_PHY_ADV_2500T_FD 0x1000 +#define FAL_PHY_ADV_5000T_FD 0x2000 +#define FAL_PHY_ADV_10000T_FD 0x4000 +#define FAL_PHY_ADV_10G_R_FD 0x8000 + +#define FAL_DEFAULT_MAX_FRAME_SIZE 0x5ee + +#define FAL_PHY_ADV_PAUSE 0x10 +#define FAL_PHY_ADV_ASY_PAUSE 0x20 + + +/** Bit manipulation macros */ +#ifndef BITSM +#define BITSM(_s, _n) (((1UL << (_n)) - 1) << _s) #endif + +#define SW_BIT_MASK_U32(nr) (~(0xFFFFFFFF << (nr))) + +#define SW_FIELD_MASK_U32(offset, len) \ + ((SW_BIT_MASK_U32(len) << (offset))) + +#define SW_FIELD_MASK_NOT_U32(offset,len) \ + (~(SW_BIT_MASK_U32(len) << (offset))) + +#define SW_FIELD_2_REG(field_val, bit_offset) \ + (field_val << (bit_offset) ) + +#define SW_REG_2_FIELD(reg_val, bit_offset, field_len) \ + (((reg_val) >> (bit_offset)) & ((1 << (field_len)) - 1)) + +#define SW_FIELD_GET_BY_REG_U32(reg_value, field_value, bit_offset, field_len)\ + do { \ + (field_value) = \ + (((reg_value) >> (bit_offset)) & SW_BIT_MASK_U32(field_len)); \ + } while (0) + +#define SW_REG_SET_BY_FIELD_U32(reg_value, field_value, bit_offset, field_len)\ + do { \ + (reg_value) = \ + (((reg_value) & SW_FIELD_MASK_NOT_U32((bit_offset),(field_len))) \ + | (((field_value) & SW_BIT_MASK_U32(field_len)) << (bit_offset)));\ + } while (0) + +#define SW_GET_FIELD_BY_REG(reg, field, field_value, reg_value) \ + SW_FIELD_GET_BY_REG_U32(reg_value, field_value, reg##_##field##_BOFFSET, \ + reg##_##field##_BLEN) + +#define SW_SET_REG_BY_FIELD(reg, field, field_value, reg_value) \ + SW_REG_SET_BY_FIELD_U32(reg_value, field_value, reg##_##field##_BOFFSET, \ + reg##_##field##_BLEN) + +#define QCA8084_REG_ENTRY_GET(reg, index, value) \ + *((u32 *) value) = ipq_mii_read(reg##_OFFSET + ((u32)index) * reg##_E_OFFSET); + +#define QCA8084_REG_ENTRY_SET(reg, index, value) \ + ipq_mii_write(reg##_OFFSET + ((u32)index) * reg##_E_OFFSET, *((u32 *) value)); + +#define QCA8084_REG_FIELD_GET(reg, index, field, value) \ + do { \ + qca8084_reg_field_get(reg##_OFFSET + ((u32)index) * reg##_E_OFFSET,\ + reg##_##field##_BOFFSET, \ + reg##_##field##_BLEN, (u8*)value);\ + } while (0); + +#define QCA8084_REG_FIELD_SET(reg, index, field, value) \ + do { \ + qca8084_reg_field_set(reg##_OFFSET + ((u32)index) * reg##_E_OFFSET,\ + reg##_##field##_BOFFSET, \ + reg##_##field##_BLEN, (u8*)value);\ + } while (0); + + +/* Chip information */ +#define QCA_VER_QCA8084 0x17 +#define CHIP_QCA8084 0x13 + +/* Port Status Register */ +#define PORT_STATUS +#define PORT_STATUS_OFFSET 0x007c +#define PORT_STATUS_E_LENGTH 4 +#define PORT_STATUS_E_OFFSET 0x0004 +#define PORT_STATUS_NR_E 7 + +#define DUPLEX_MODE +#define PORT_STATUS_DUPLEX_MODE_BOFFSET 6 +#define PORT_STATUS_DUPLEX_MODE_BLEN 1 +#define PORT_STATUS_DUPLEX_MODE_FLAG HSL_RW + +#define SPEED_MODE +#define PORT_STATUS_SPEED_MODE_BOFFSET 0 +#define PORT_STATUS_SPEED_MODE_BLEN 2 +#define PORT_STATUS_SPEED_MODE_FLAG HSL_RW + +#define LINK_EN +#define PORT_STATUS_LINK_EN_BOFFSET 9 +#define PORT_STATUS_LINK_EN_BLEN 1 +#define PORT_STATUS_LINK_EN_FLAG HSL_RW + +#define RXMAC_EN +#define PORT_STATUS_RXMAC_EN_BOFFSET 3 +#define PORT_STATUS_RXMAC_EN_BLEN 1 +#define PORT_STATUS_RXMAC_EN_FLAG HSL_RW + +#define TXMAC_EN +#define PORT_STATUS_TXMAC_EN_BOFFSET 2 +#define PORT_STATUS_TXMAC_EN_BLEN 1 +#define PORT_STATUS_TXMAC_EN_FLAG HSL_RW + +#define RX_FLOW_EN +#define PORT_STATUS_RX_FLOW_EN_BOFFSET 5 +#define PORT_STATUS_RX_FLOW_EN_BLEN 1 +#define PORT_STATUS_RX_FLOW_EN_FLAG HSL_RW + +#define TX_FLOW_EN +#define PORT_STATUS_TX_FLOW_EN_BOFFSET 4 +#define PORT_STATUS_TX_FLOW_EN_BLEN 1 +#define PORT_STATUS_TX_FLOW_EN_FLAG HSL_RW + +#define TX_HALF_FLOW_EN +#define PORT_STATUS_TX_HALF_FLOW_EN_BOFFSET 7 +#define PORT_STATUS_TX_HALF_FLOW_EN_BLEN 1 +#define PORT_STATUS_TX_HALF_FLOW_EN_FLAG HSL_RW + +#define QCA8084_PORT_SPEED_10M 0 +#define QCA8084_PORT_SPEED_100M 1 +#define QCA8084_PORT_SPEED_1000M 2 +#define QCA8084_PORT_SPEED_2500M QCA8084_PORT_SPEED_1000M +#define QCA8084_PORT_HALF_DUPLEX 0 +#define QCA8084_PORT_FULL_DUPLEX 1 + +/* Header Ctl Register */ +#define HEADER_CTL +#define HEADER_CTL_OFFSET 0x0098 +#define HEADER_CTL_E_LENGTH 4 +#define HEADER_CTL_E_OFFSET 0x0004 +#define HEADER_CTL_NR_E 1 + +#define TYPE_LEN +#define HEADER_CTL_TYPE_LEN_BOFFSET 16 +#define HEADER_CTL_TYPE_LEN_BLEN 1 +#define HEADER_CTL_TYPE_LEN_FLAG HSL_RW + +#define TYPE_VAL +#define HEADER_CTL_TYPE_VAL_BOFFSET 0 +#define HEADER_CTL_TYPE_VAL_BLEN 16 +#define HEADER_CTL_TYPE_VAL_FLAG HSL_RW + + +/* Port Header Ctl Register */ +#define PORT_HDR_CTL +#define PORT_HDR_CTL_OFFSET 0x009c +#define PORT_HDR_CTL_E_LENGTH 4 +#define PORT_HDR_CTL_E_OFFSET 0x0004 +#define PORT_HDR_CTL_NR_E 7 + +#define RXHDR_MODE +#define PORT_HDR_CTL_RXHDR_MODE_BOFFSET 2 +#define PORT_HDR_CTL_RXHDR_MODE_BLEN 2 +#define PORT_HDR_CTL_RXHDR_MODE_FLAG HSL_RW + +#define TXHDR_MODE +#define PORT_HDR_CTL_TXHDR_MODE_BOFFSET 0 +#define PORT_HDR_CTL_TXHDR_MODE_BLEN 2 +#define PORT_HDR_CTL_TXHDR_MODE_FLAG HSL_RW + +#define QCA8084_HEADER_TYPE_VAL 0xaaaa + +typedef enum { + FAL_NO_HEADER_EN = 0, + FAL_ONLY_MANAGE_FRAME_EN, + FAL_ALL_TYPE_FRAME_EN +} port_header_mode_t; + +struct port_phy_status +{ + u32 link_status; + fal_port_speed_t speed; + fal_port_duplex_t duplex; + bool tx_flowctrl; + bool rx_flowctrl; +}; + + +/**************************************************************************** + * + * 1) PinCtrl/TLMM Register Definition + * + ****************************************************************************/ +/* TLMM_GPIO_CFGn */ +#define TLMM_GPIO_CFGN +#define TLMM_GPIO_CFGN_OFFSET 0xC400000 +#define TLMM_GPIO_CFGN_E_LENGTH 4 +#define TLMM_GPIO_CFGN_E_OFFSET 0x1000 +#define TLMM_GPIO_CFGN_NR_E 80 + +#define GPIO_HIHYS_EN +#define TLMM_GPIO_CFGN_GPIO_HIHYS_EN_BOFFSET 10 +#define TLMM_GPIO_CFGN_GPIO_HIHYS_EN_BLEN 1 +#define TLMM_GPIO_CFGN_GPIO_HIHYS_EN_FLAG HSL_RW + +#define GPIO_OEA +#define TLMM_GPIO_CFGN_GPIO_OEA_BOFFSET 9 +#define TLMM_GPIO_CFGN_GPIO_OEA_BLEN 1 +#define TLMM_GPIO_CFGN_GPIO_OEA_FLAG HSL_RW + +#define DRV_STRENGTH +#define TLMM_GPIO_CFGN_DRV_STRENGTH_BOFFSET 6 +#define TLMM_GPIO_CFGN_DRV_STRENGTH_BLEN 3 +#define TLMM_GPIO_CFGN_DRV_STRENGTH_FLAG HSL_RW + +enum QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH { + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_2_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_4_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_6_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_8_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_10_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_12_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_14_MA, + QCA8084_TLMM_GPIO_CFGN_DRV_STRENGTH_16_MA, +}; + +#define FUNC_SEL +#define TLMM_GPIO_CFGN_FUNC_SEL_BOFFSET 2 +#define TLMM_GPIO_CFGN_FUNC_SEL_BLEN 4 +#define TLMM_GPIO_CFGN_FUNC_SEL_FLAG HSL_RW + +#define GPIO_PULL +#define TLMM_GPIO_CFGN_GPIO_PULL_BOFFSET 0 +#define TLMM_GPIO_CFGN_GPIO_PULL_BLEN 2 +#define TLMM_GPIO_CFGN_GPIO_PULL_FLAG HSL_RW + +enum QCA8084_QCA8084_PIN_CONFIG_PARAM { + QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DISABLE, //Disables all pull + QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_DOWN, + QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_BUS_HOLD, //Weak Keepers + QCA8084_TLMM_GPIO_CFGN_GPIO_PULL_UP, +}; + + +/* TLMM_GPIO_IN_OUTn */ +#define TLMM_GPIO_IN_OUTN +#define TLMM_GPIO_IN_OUTN_OFFSET 0xC400004 +#define TLMM_GPIO_IN_OUTN_E_LENGTH 4 +#define TLMM_GPIO_IN_OUTN_E_OFFSET 0x1000 +#define TLMM_GPIO_IN_OUTN_NR_E 80 + +#define GPIO_OUTE +#define TLMM_GPIO_IN_OUTN_GPIO_OUTE_BOFFSET 1 +#define TLMM_GPIO_IN_OUTN_GPIO_OUTE_BLEN 1 +#define TLMM_GPIO_IN_OUTN_GPIO_OUTE_FLAG HSL_RW + +#define GPIO_IN +#define TLMM_GPIO_IN_OUTN_GPIO_IN_BOFFSET 0 +#define TLMM_GPIO_IN_OUTN_GPIO_IN_BLEN 1 +#define TLMM_GPIO_IN_OUTN_GPIO_IN_FLAG HSL_R + +/* TLMM_CLK_GATE_EN */ +#define TLMM_CLK_GATE_EN +#define TLMM_CLK_GATE_EN_OFFSET 0xC500000 +#define TLMM_CLK_GATE_EN_E_LENGTH 4 +#define TLMM_CLK_GATE_EN_E_OFFSET 0 +#define TLMM_CLK_GATE_EN_NR_E 1 + +#define AHB_HCLK_EN +#define TLMM_CLK_GATE_EN_AHB_HCLK_EN_BOFFSET 2 +#define TLMM_CLK_GATE_EN_AHB_HCLK_EN_BLEN 1 +#define TLMM_CLK_GATE_EN_AHB_HCLK_EN_FLAG HSL_RW + +#define SUMMARY_INTR_EN +#define TLMM_CLK_GATE_EN_SUMMARY_INTR_EN_BOFFSET 1 +#define TLMM_CLK_GATE_EN_SUMMARY_INTR_EN_BLEN 1 +#define TLMM_CLK_GATE_EN_SUMMARY_INTR_EN_FLAG HSL_RW + +#define CRIF_READ_EN +#define TLMM_CLK_GATE_EN_CRIF_READ_EN_BOFFSET 0 +#define TLMM_CLK_GATE_EN_CRIF_READ_EN_BLEN 1 +#define TLMM_CLK_GATE_EN_CRIF_READ_EN_FLAG HSL_RW + +/* TLMM_HW_REVISION_NUMBER */ +#define TLMM_HW_REVISION_NUMBER +#define TLMM_HW_REVISION_NUMBER_OFFSET 0xC510010 +#define TLMM_HW_REVISION_NUMBER_E_LENGTH 4 +#define TLMM_HW_REVISION_NUMBER_E_OFFSET 0 +#define TLMM_HW_REVISION_NUMBER_NR_E 1 + +#define VERSION_ID +#define TLMM_HW_REVISION_NUMBER_VERSION_ID_BOFFSET 28 +#define TLMM_HW_REVISION_NUMBER_VERSION_ID_BLEN 4 +#define TLMM_HW_REVISION_NUMBER_VERSION_ID_FLAG HSL_R + +#define PARTNUM +#define TLMM_HW_REVISION_NUMBER_PARTNUM_BOFFSET 12 +#define TLMM_HW_REVISION_NUMBER_PARTNUM_BLEN 16 +#define TLMM_HW_REVISION_NUMBER_PARTNUM_FLAG HSL_R + +#define MFG_ID +#define TLMM_HW_REVISION_NUMBER_MFG_ID_BOFFSET 1 +#define TLMM_HW_REVISION_NUMBER_MFG_ID_BLEN 11 +#define TLMM_HW_REVISION_NUMBER_MFG_ID_FLAG HSL_R + +#define START_BIT +#define TLMM_HW_REVISION_NUMBER_START_BIT_BOFFSET 0 +#define TLMM_HW_REVISION_NUMBER_START_BIT_BLEN 1 +#define TLMM_HW_REVISION_NUMBER_START_BIT_FLAG HSL_R + + +/**************************************************************************** + * + * 2) PINs Functions Selection GPIO_CFG[5:2] (FUNC_SEL) + * + ****************************************************************************/ +/*GPIO*/ +#define QCA8084_PIN_FUNC_GPIO0 0 +#define QCA8084_PIN_FUNC_GPIO1 0 +#define QCA8084_PIN_FUNC_GPIO2 0 +#define QCA8084_PIN_FUNC_GPIO3 0 +#define QCA8084_PIN_FUNC_GPIO4 0 +#define QCA8084_PIN_FUNC_GPIO5 0 +#define QCA8084_PIN_FUNC_GPIO6 0 +#define QCA8084_PIN_FUNC_GPIO7 0 +#define QCA8084_PIN_FUNC_GPIO8 0 +#define QCA8084_PIN_FUNC_GPIO9 0 +#define QCA8084_PIN_FUNC_GPIO10 0 +#define QCA8084_PIN_FUNC_GPIO11 0 +#define QCA8084_PIN_FUNC_GPIO12 0 +#define QCA8084_PIN_FUNC_GPIO13 0 +#define QCA8084_PIN_FUNC_GPIO14 0 +#define QCA8084_PIN_FUNC_GPIO15 0 +#define QCA8084_PIN_FUNC_GPIO16 0 +#define QCA8084_PIN_FUNC_GPIO17 0 +#define QCA8084_PIN_FUNC_GPIO18 0 +#define QCA8084_PIN_FUNC_GPIO19 0 +#define QCA8084_PIN_FUNC_GPIO20 0 +#define QCA8084_PIN_FUNC_GPIO21 0 + +/*MINIMUM CONCURRENCY SET FUNCTION*/ +#define QCA8084_PIN_FUNC_INTN_WOL 1 +#define QCA8084_PIN_FUNC_INTN 1 +#define QCA8084_PIN_FUNC_P0_LED_0 1 +#define QCA8084_PIN_FUNC_P1_LED_0 1 +#define QCA8084_PIN_FUNC_P2_LED_0 1 +#define QCA8084_PIN_FUNC_P3_LED_0 1 +#define QCA8084_PIN_FUNC_PPS_IN 1 +#define QCA8084_PIN_FUNC_TOD_IN 1 +#define QCA8084_PIN_FUNC_RTC_REFCLK_IN 1 +#define QCA8084_PIN_FUNC_P0_PPS_OUT 1 +#define QCA8084_PIN_FUNC_P1_PPS_OUT 1 +#define QCA8084_PIN_FUNC_P2_PPS_OUT 1 +#define QCA8084_PIN_FUNC_P3_PPS_OUT 1 +#define QCA8084_PIN_FUNC_P0_TOD_OUT 1 +#define QCA8084_PIN_FUNC_P0_CLK125_TDI 1 +#define QCA8084_PIN_FUNC_P0_SYNC_CLKO_PTP 1 +#define QCA8084_PIN_FUNC_P0_LED_1 1 +#define QCA8084_PIN_FUNC_P1_LED_1 1 +#define QCA8084_PIN_FUNC_P2_LED_1 1 +#define QCA8084_PIN_FUNC_P3_LED_1 1 +#define QCA8084_PIN_FUNC_MDC_M 1 +#define QCA8084_PIN_FUNC_MDO_M 1 + +/*ALT FUNCTION K*/ +#define QCA8084_PIN_FUNC_EVENT_TRG_I 2 +#define QCA8084_PIN_FUNC_P0_EVENT_TRG_O 2 +#define QCA8084_PIN_FUNC_P1_EVENT_TRG_O 2 +#define QCA8084_PIN_FUNC_P2_EVENT_TRG_O 2 +#define QCA8084_PIN_FUNC_P3_EVENT_TRG_O 2 +#define QCA8084_PIN_FUNC_P1_TOD_OUT 2 +#define QCA8084_PIN_FUNC_P1_CLK125_TDI 2 +#define QCA8084_PIN_FUNC_P1_SYNC_CLKO_PTP 2 +#define QCA8084_PIN_FUNC_P0_INTN_WOL 2 +#define QCA8084_PIN_FUNC_P1_INTN_WOL 2 +#define QCA8084_PIN_FUNC_P2_INTN_WOL 2 +#define QCA8084_PIN_FUNC_P3_INTN_WOL 2 + +/*ALT FUNCTION L*/ +#define QCA8084_PIN_FUNC_P2_TOD_OUT 3 +#define QCA8084_PIN_FUNC_P2_CLK125_TDI 3 +#define QCA8084_PIN_FUNC_P2_SYNC_CLKO_PTP 3 + +/*ALT FUNCTION M*/ +#define QCA8084_PIN_FUNC_P3_TOD_OUT 4 +#define QCA8084_PIN_FUNC_P3_CLK125_TDI 4 +#define QCA8084_PIN_FUNC_P3_SYNC_CLKO_PTP 4 + +/*ALT FUNCTION N*/ +#define QCA8084_PIN_FUNC_P0_LED_2 3 +#define QCA8084_PIN_FUNC_P1_LED_2 2 +#define QCA8084_PIN_FUNC_P2_LED_2 2 +#define QCA8084_PIN_FUNC_P3_LED_2 3 + +/*ALT FUNCTION O*/ + + +/*ALT FUNCTION DEBUG BUS OUT*/ +#define QCA8084_PIN_FUNC_DBG_OUT_CLK 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT0 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT1 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT12 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT13 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT2 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT3 4 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT4 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT5 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT6 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT7 5 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT8 5 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT9 5 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT10 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT11 3 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT14 2 +#define QCA8084_PIN_FUNC_DBG_BUS_OUT15 2 + + +/**************************************************************************** + * + * 2) PINs Functions Selection GPIO_CFG[5:2] (FUNC_SEL) + * + ****************************************************************************/ +struct qca8084_pinctrl_setting_mux { + u32 pin; + u32 func; +}; + +struct qca8084_pinctrl_setting_configs { + u32 pin; + u32 num_configs; + u64 *configs; +}; + +enum qca8084_pin_config_param { + QCA8084_PIN_CONFIG_BIAS_BUS_HOLD, + QCA8084_PIN_CONFIG_BIAS_DISABLE, + QCA8084_PIN_CONFIG_BIAS_HIGH_IMPEDANCE, + QCA8084_PIN_CONFIG_BIAS_PULL_DOWN, + QCA8084_PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, + QCA8084_PIN_CONFIG_BIAS_PULL_UP, + QCA8084_PIN_CONFIG_DRIVE_OPEN_DRAIN, + QCA8084_PIN_CONFIG_DRIVE_OPEN_SOURCE, + QCA8084_PIN_CONFIG_DRIVE_PUSH_PULL, + QCA8084_PIN_CONFIG_DRIVE_STRENGTH, + QCA8084_PIN_CONFIG_DRIVE_STRENGTH_UA, + QCA8084_PIN_CONFIG_INPUT_DEBOUNCE, + QCA8084_PIN_CONFIG_INPUT_ENABLE, + QCA8084_PIN_CONFIG_INPUT_SCHMITT, + QCA8084_PIN_CONFIG_INPUT_SCHMITT_ENABLE, + QCA8084_PIN_CONFIG_LOW_POWER_MODE, + QCA8084_PIN_CONFIG_OUTPUT_ENABLE, + QCA8084_PIN_CONFIG_OUTPUT, + QCA8084_PIN_CONFIG_POWER_SOURCE, + QCA8084_PIN_CONFIG_SLEEP_HARDWARE_STATE, + QCA8084_PIN_CONFIG_SLEW_RATE, + QCA8084_PIN_CONFIG_SKEW_DELAY, + QCA8084_PIN_CONFIG_PERSIST_STATE, + QCA8084_PIN_CONFIG_END = 0x7F, + QCA8084_PIN_CONFIG_MAX = 0xFF, +}; + +enum qca8084_pinctrl_map_type { + QCA8084_PIN_MAP_TYPE_INVALID, + QCA8084_PIN_MAP_TYPE_DUMMY_STATE, + QCA8084_PIN_MAP_TYPE_MUX_GROUP, + QCA8084_PIN_MAP_TYPE_CONFIGS_PIN, + QCA8084_PIN_MAP_TYPE_CONFIGS_GROUP, +}; + +struct qca8084_pinctrl_setting { + enum qca8084_pinctrl_map_type type; + union { + struct qca8084_pinctrl_setting_mux mux; + struct qca8084_pinctrl_setting_configs configs; + } data; +}; + +#define QCA8084_PIN_SETTING_MUX(pin_id, function) \ + { \ + .type = QCA8084_PIN_MAP_TYPE_MUX_GROUP, \ + .data.mux = { \ + .pin = pin_id, \ + .func = function \ + }, \ + } + +#define QCA8084_PIN_SETTING_CONFIG(pin_id, cfgs) \ + { \ + .type = QCA8084_PIN_MAP_TYPE_CONFIGS_PIN, \ + .data.configs = { \ + .pin = pin_id, \ + .configs = cfgs, \ + .num_configs = ARRAY_SIZE(cfgs) \ + }, \ + } + +int qca8084_gpio_set_bit( u32 pin, u32 value); +int qca8084_gpio_get_bit( u32 pin, u32 *data); +int qca8084_gpio_pin_mux_set( u32 pin, u32 func); +int qca8084_gpio_pin_cfg_set_bias( u32 pin, u32 bias); +int qca8084_gpio_pin_cfg_get_bias( u32 pin, u32 *bias); +int qca8084_gpio_pin_cfg_set_drvs( u32 pin, u32 drvs); +int qca8084_gpio_pin_cfg_get_drvs( u32 pin, u32 *drvs); +int qca8084_gpio_pin_cfg_set_oe( u32 pin, bool oe); +int qca8084_gpio_pin_cfg_get_oe( u32 pin, bool *oe); +int ipq_qca8084_pinctrl_init(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _QCA8084_PHY_H_ */ diff --git a/drivers/net/ipq_common/ipq_qca8084_clk.c b/drivers/net/ipq_common/ipq_qca8084_clk.c index 0cfebbeb6e..894fae8e4f 100644 --- a/drivers/net/ipq_common/ipq_qca8084_clk.c +++ b/drivers/net/ipq_common/ipq_qca8084_clk.c @@ -1073,14 +1073,17 @@ void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask, return; } -void qca8084_gcc_common_clk_parent_enable(void) +void qca8084_gcc_common_clk_parent_enable(qca8084_work_mode_t clk_mode) { /* Switch core */ qca8084_clk_parent_set(QCA8084_SWITCH_CORE_CLK, QCA8084_P_UNIPHY1_TX312P5M); qca8084_clk_rate_set(QCA8084_SWITCH_CORE_CLK, UQXGMII_SPEED_2500M_CLK); /* Disable switch core clock to save power in phy mode */ - qca8084_clk_disable(QCA8084_SWITCH_CORE_CLK); + if (QCA8084_PHY_UQXGMII_MODE == clk_mode || QCA8084_PHY_SGMII_UQXGMII_MODE == clk_mode) + qca8084_clk_disable(QCA8084_SWITCH_CORE_CLK); + else + qca8084_clk_enable(QCA8084_SWITCH_CORE_CLK); qca8084_clk_enable(QCA8084_APB_BRIDGE_CLK); @@ -1100,7 +1103,10 @@ void qca8084_gcc_common_clk_parent_enable(void) qca8084_clk_rate_set(QCA8084_SRDS0_SYS_CLK, QCA8084_SYS_CLK_RATE_25M); /* Disable serdes0 clock to save power in phy mode */ - qca8084_clk_disable(QCA8084_SRDS0_SYS_CLK); + if (QCA8084_PHY_UQXGMII_MODE == clk_mode || QCA8084_PHY_SGMII_UQXGMII_MODE == clk_mode) + qca8084_clk_disable(QCA8084_SRDS0_SYS_CLK); + else + qca8084_clk_enable(QCA8084_SRDS0_SYS_CLK); qca8084_clk_enable(QCA8084_SRDS1_SYS_CLK); qca8084_clk_enable(QCA8084_GEPHY0_SYS_CLK); @@ -1115,12 +1121,27 @@ void qca8084_gcc_common_clk_parent_enable(void) qca8084_clk_enable(QCA8084_SEC_CTRL_SENSE_CLK); } -void qca8084_gcc_port_clk_parent_set(uint32_t qca8084_port_id) +void qca8084_gcc_port_clk_parent_set(qca8084_work_mode_t clk_mode, uint32_t qca8084_port_id) { qca8084_clk_parent_t port_tx_parent, port_rx_parent; char *tx_clk_id, *rx_clk_id; - port_tx_parent = QCA8084_P_UNIPHY1_RX312P5M; + /* Initialize the clock parent with port 1, 2, 3, clock parent is same for these ports; + * the clock parent will be updated for port 0, 4, 5. + */ + switch(clk_mode) { + case QCA8084_SWITCH_MODE: + case QCA8084_SWITCH_BYPASS_PORT5_MODE: + port_tx_parent = QCA8084_P_UNIPHY1_TX312P5M; + break; + case QCA8084_PHY_UQXGMII_MODE: + case QCA8084_PHY_SGMII_UQXGMII_MODE: + port_tx_parent = QCA8084_P_UNIPHY1_RX312P5M; + break; + default: + pr_debug("Unsupported clock mode %d\n", clk_mode); + return; + } port_rx_parent = QCA8084_P_UNIPHY1_TX312P5M; switch (qca8084_port_id) { @@ -1143,8 +1164,24 @@ void qca8084_gcc_port_clk_parent_set(uint32_t qca8084_port_id) rx_clk_id = QCA8084_MAC3_RX_CLK; break; case PORT4: - port_tx_parent = QCA8084_P_UNIPHY1_RX312P5M; - port_rx_parent = QCA8084_P_UNIPHY1_TX312P5M; + switch(clk_mode) { + case QCA8084_SWITCH_BYPASS_PORT5_MODE: + case QCA8084_PHY_SGMII_UQXGMII_MODE: + port_tx_parent = QCA8084_P_UNIPHY0_RX; + port_rx_parent = QCA8084_P_UNIPHY0_TX; + break; + case QCA8084_SWITCH_MODE: + port_tx_parent = QCA8084_P_UNIPHY1_TX312P5M; + port_rx_parent = QCA8084_P_UNIPHY1_TX312P5M; + break; + case QCA8084_PHY_UQXGMII_MODE: + port_tx_parent = QCA8084_P_UNIPHY1_RX312P5M; + port_rx_parent = QCA8084_P_UNIPHY1_TX312P5M; + break; + default: + pr_debug("Unsupported clock mode %d\n", clk_mode); + return; + } tx_clk_id = QCA8084_MAC4_TX_CLK; rx_clk_id = QCA8084_MAC4_RX_CLK; break; @@ -1153,7 +1190,19 @@ void qca8084_gcc_port_clk_parent_set(uint32_t qca8084_port_id) port_rx_parent = QCA8084_P_UNIPHY0_RX; tx_clk_id = QCA8084_MAC5_TX_CLK; rx_clk_id = QCA8084_MAC5_RX_CLK; - qca8084_port5_uniphy0_clk_src_set(0); + switch (clk_mode) { + case QCA8084_SWITCH_BYPASS_PORT5_MODE: + case QCA8084_PHY_SGMII_UQXGMII_MODE: + qca8084_port5_uniphy0_clk_src_set(1); + break; + case QCA8084_SWITCH_MODE: + case QCA8084_PHY_UQXGMII_MODE: + qca8084_port5_uniphy0_clk_src_set(0); + break; + default: + pr_debug("Unsupported clock mode %d\n", clk_mode); + return; + } break; default: pr_debug("Unsupported qca8084_port_id %d\n", qca8084_port_id); @@ -1164,7 +1213,7 @@ void qca8084_gcc_port_clk_parent_set(uint32_t qca8084_port_id) qca8084_clk_parent_set(rx_clk_id, port_rx_parent); } -void qca8084_gcc_clock_init(void) +void qca8084_gcc_clock_init(qca8084_work_mode_t clk_mode, u32 pbmp) { uint32_t qca8084_port_id = 0; /* clock type mask value for 6 manhattan ports */ @@ -1173,13 +1222,51 @@ void qca8084_gcc_clock_init(void) uint8_t switch_flag = 0; qca8084_clk_parent_t uniphy_index = QCA8084_P_UNIPHY0_RX; - clk_mask[PORT1] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; - clk_mask[PORT2] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; - clk_mask[PORT3] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; - clk_mask[PORT4] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; + switch (clk_mode) { + case QCA8084_SWITCH_MODE: + case QCA8084_SWITCH_BYPASS_PORT5_MODE: + while (pbmp) { + if (pbmp & 1) { + if (qca8084_port_id == PORT0 || + qca8084_port_id == PORT5) { + clk_mask[qca8084_port_id] = QCA8084_CLK_TYPE_MAC | + QCA8084_CLK_TYPE_UNIPHY; + } else { + clk_mask[qca8084_port_id] = QCA8084_CLK_TYPE_MAC | + QCA8084_CLK_TYPE_EPHY; + } + } + pbmp >>= 1; + qca8084_port_id++; + } + + if (clk_mode == QCA8084_SWITCH_BYPASS_PORT5_MODE) { + /* For phy port 4 in switch bypass mode */ + clk_mask[PORT4] = QCA8084_CLK_TYPE_EPHY; + clk_mask[PORT5] = QCA8084_CLK_TYPE_UNIPHY; + } + + switch_flag = 1; + break; + case QCA8084_PHY_UQXGMII_MODE: + case QCA8084_PHY_SGMII_UQXGMII_MODE: + clk_mask[PORT1] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; + clk_mask[PORT2] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; + clk_mask[PORT3] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; + clk_mask[PORT4] = QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY; + if (clk_mode == QCA8084_PHY_SGMII_UQXGMII_MODE) { + /* For phy port4 in PHY bypass mode */ + clk_mask[PORT4] = QCA8084_CLK_TYPE_EPHY; + clk_mask[PORT5] = QCA8084_CLK_TYPE_UNIPHY; + } + break; + default: + pr_debug("Unsupported clock mode %d\n", clk_mode); + return; + } if (!gcc_common_clk_init) { - qca8084_gcc_common_clk_parent_enable(); + qca8084_gcc_common_clk_parent_enable(clk_mode); gcc_common_clk_init = 1; /* Initialize the uniphy raw clock, if the port4 is in bypass mode, the uniphy0 @@ -1199,12 +1286,16 @@ void qca8084_gcc_clock_init(void) qca8084_port_id = 0; while (qca8084_port_id < ARRAY_SIZE(clk_mask)) { if (clk_mask[qca8084_port_id] != 0) { - qca8084_gcc_port_clk_parent_set(qca8084_port_id); + qca8084_gcc_port_clk_parent_set(clk_mode, qca8084_port_id); if (clk_mask[qca8084_port_id] & QCA8084_CLK_TYPE_MAC) qca8084_port_clk_en_set(qca8084_port_id, QCA8084_CLK_TYPE_MAC, 1); if (clk_mask[qca8084_port_id] & QCA8084_CLK_TYPE_UNIPHY && switch_flag == 1) qca8084_port_clk_en_set(qca8084_port_id, QCA8084_CLK_TYPE_UNIPHY, 1); + pbmp |= BIT(qca8084_port_id); } qca8084_port_id++; } + + pr_debug("QCA8084 GCC CLK initialization with clock mode %d on port bmp 0x%x\n", + clk_mode, pbmp); } diff --git a/drivers/net/ipq_common/ipq_qca8084_clk.h b/drivers/net/ipq_common/ipq_qca8084_clk.h index 9ab4cb6051..13f4884aaf 100644 --- a/drivers/net/ipq_common/ipq_qca8084_clk.h +++ b/drivers/net/ipq_common/ipq_qca8084_clk.h @@ -96,6 +96,8 @@ #define QCA8084_GEPHY_P1_MDC_SW_RST "qca8084_gephy_p1_mdc_sw_rst" #define QCA8084_GEPHY_P0_MDC_SW_RST "qca8084_gephy_p0_mdc_sw_rst" + + typedef enum { QCA8084_P_XO, QCA8084_P_UNIPHY0_RX, @@ -180,4 +182,72 @@ struct clk_lookup { #define CBCR_CLK_RESET BIT(2) #define CBCR_CLK_ENABLE BIT(0) + +/* work mode */ +#define WORK_MODE +#define WORK_MODE_ID 0 +#define WORK_MODE_OFFSET 0xC90F030 +#define WORK_MODE_E_LENGTH 4 +#define WORK_MODE_E_OFFSET 0 +#define WORK_MODE_NR_E 1 + +/* port5 sel */ +#define WORK_MODE_PORT5_SEL +#define WORK_MODE_PORT5_SEL_BOFFSET 5 +#define WORK_MODE_PORT5_SEL_BLEN 1 +#define WORK_MODE_PORT5_SEL_FLAG HSL_RW + +/* phy3 sel1 */ +#define WORK_MODE_PHY3_SEL1 +#define WORK_MODE_PHY3_SEL1_BOFFSET 4 +#define WORK_MODE_PHY3_SEL1_BLEN 1 +#define WORK_MODE_PHY3_SEL1_FLAG HSL_RW + +/* phy3 sel0 */ +#define WORK_MODE_PHY3_SEL0 +#define WORK_MODE_PHY3_SEL0_BOFFSET 3 +#define WORK_MODE_PHY3_SEL0_BLEN 1 +#define WORK_MODE_PHY3_SEL0_FLAG HSL_RW + +/* phy2 sel */ +#define WORK_MODE_PHY2_SEL +#define WORK_MODE_PHY2_SEL_BOFFSET 2 +#define WORK_MODE_PHY2_SEL_BLEN 1 +#define WORK_MODE_PHY2_SEL_FLAG HSL_RW + +/* phy1 sel */ +#define WORK_MODE_PHY1_SEL +#define WORK_MODE_PHY1_SEL_BOFFSET 1 +#define WORK_MODE_PHY1_SEL_BLEN 1 +#define WORK_MODE_PHY1_SEL_FLAG HSL_RW + +/* phy0 sel */ +#define WORK_MODE_PHY0_SEL +#define WORK_MODE_PHY0_SEL_BOFFSET 0 +#define WORK_MODE_PHY0_SEL_BLEN 1 +#define WORK_MODE_PHY0_SEL_FLAG HSL_RW + +#define QCA8084_WORK_MODE_MASK \ + (BITSM(WORK_MODE_PHY0_SEL_BOFFSET, WORK_MODE_PORT5_SEL_BOFFSET + 1)) + +typedef enum { + QCA8084_SWITCH_MODE = + (BIT(WORK_MODE_PHY3_SEL1_BOFFSET)), + QCA8084_SWITCH_BYPASS_PORT5_MODE = + (BIT(WORK_MODE_PORT5_SEL_BOFFSET)), + QCA8084_PHY_UQXGMII_MODE = + (BIT(WORK_MODE_PORT5_SEL_BOFFSET) | + BIT(WORK_MODE_PHY3_SEL0_BOFFSET) | + BIT(WORK_MODE_PHY2_SEL_BOFFSET) | + BIT(WORK_MODE_PHY1_SEL_BOFFSET) | + BIT(WORK_MODE_PHY0_SEL_BOFFSET)), + QCA8084_PHY_SGMII_UQXGMII_MODE = + (BIT(WORK_MODE_PORT5_SEL_BOFFSET) | + BIT(WORK_MODE_PHY2_SEL_BOFFSET) | + BIT(WORK_MODE_PHY1_SEL_BOFFSET) | + BIT(WORK_MODE_PHY0_SEL_BOFFSET)), + QCA8084_WORK_MODE_MAX, +} qca8084_work_mode_t; + + #endif /* _QCA8084_CLK_H_ */ diff --git a/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.c b/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.c index 6fbde125c8..dd89b5adf6 100644 --- a/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.c +++ b/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.c @@ -38,6 +38,7 @@ extern void ipq_mii_update(uint32_t reg, uint32_t mask, uint32_t val); extern void qca8084_port_clk_rate_set(uint32_t qca8084_port_id, uint32_t rate); extern void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask, uint8_t enable); +extern void qca8084_uniphy_raw_clock_set(qca8084_clk_parent_t uniphy_clk, uint64_t rate); extern void qca8084_clk_assert(const char *clock_id); extern void qca8084_clk_deassert(const char *clock_id); extern void qca8084_port_clk_reset(uint32_t qca8084_port_id, uint8_t mask); @@ -502,3 +503,153 @@ void qca8084_interface_uqxgmii_mode_set(void) pr_debug("enable EEE for xpcs\n"); qca8084_uniphy_xpcs_8023az_enable(); } + + +void qca8084_uniphy_sgmii_function_reset(u32 uniphy_index) +{ + u32 uniphy_addr = 0; + + qca8084_serdes_addr_get(uniphy_index, &uniphy_addr); + + /*sgmii channel0 adpt reset*/ + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET, 0); + mdelay(1); + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET, + QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET); + /*ipg tune reset*/ + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_USXGMII_RESET, QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET, 0); + mdelay(1); + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_USXGMII_RESET, QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET, + QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET); + +} + +void qca8084_interface_sgmii_mode_set(u32 uniphy_index, u32 qca8084_port_id, mac_config_t *config) +{ + u32 uniphy_addr = 0, mode_ctrl = 0, speed_mode = 0; + u32 uniphy_port_id = 0, ethphy_clk_mask = 0; + u64 raw_clk = 0; + + /*get the uniphy address*/ + qca8084_serdes_addr_get(uniphy_index, &uniphy_addr); + + if(config->mac_mode == QCA8084_MAC_MODE_SGMII) + { + mode_ctrl = QCA8084_UNIPHY_MMD1_SGMII_MODE; + raw_clk = UNIPHY_CLK_RATE_125M; + } + else + { + mode_ctrl = QCA8084_UNIPHY_MMD1_SGMII_PLUS_MODE; + raw_clk = UNIPHY_CLK_RATE_312M; + } + + if(config->clock_mode == QCA8084_INTERFACE_CLOCK_MAC_MODE) + mode_ctrl |= QCA8084_UNIPHY_MMD1_SGMII_MAC_MODE; + else + { + mode_ctrl |= QCA8084_UNIPHY_MMD1_SGMII_PHY_MODE; + /*eththy clock should be accessed for phy mode*/ + ethphy_clk_mask = QCA8084_CLK_TYPE_EPHY; + } + + pr_debug("uniphy:%d,mode:%s,autoneg_en:%d,force_speed:%d,clk_mask:0x%x\n", + uniphy_index, (config->mac_mode == QCA8084_MAC_MODE_SGMII)?"sgmii":"sgmii plus", + config->auto_neg, config->force_speed, + ethphy_clk_mask); + + /*GMII interface clock disable*/ + pr_debug("GMII interface clock disable\n"); + qca8084_port_clk_en_set(qca8084_port_id, ethphy_clk_mask, 0); + + /*when access uniphy0 clock, port5 should be used, but for phy mode, + the port 4 connect to uniphy0, so need to change the port id*/ + if(uniphy_index == QCA8084_UNIPHY_SGMII_0) + uniphy_port_id = PORT5; + else + uniphy_port_id = qca8084_port_id; + qca8084_port_clk_en_set(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY, 0); + + /*uniphy1 xpcs reset, and configure raw clk*/ + if(uniphy_index == QCA8084_UNIPHY_SGMII_1) + { + pr_debug("uniphy1 xpcs reset, confiugre raw clock as:%lld\n", + raw_clk); + qca8084_clk_assert(QCA8084_UNIPHY_XPCS_RST); + qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY1_RX, raw_clk); + qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY1_TX, raw_clk); + } + else + { + pr_debug("uniphy0 configure raw clock as %lld\n", raw_clk); + qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY0_RX, raw_clk); + qca8084_uniphy_raw_clock_set(QCA8084_P_UNIPHY0_TX, raw_clk); + } + + /*configure SGMII mode or SGMII+ mode*/ + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_MODE_CTRL, QCA8084_UNIPHY_MMD1_SGMII_MODE_CTRL_MASK, + mode_ctrl); + + /*GMII datapass selection, 0 is for SGMII, 1 is for USXGMII*/ + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_GMII_DATAPASS_SEL, QCA8084_UNIPHY_MMD1_DATAPASS_MASK, QCA8084_UNIPHY_MMD1_DATAPASS_SGMII); + /*configue force or autoneg*/ + if(!config->auto_neg) + { + qca8084_port_speed_clock_set(qca8084_port_id, + config->force_speed); + switch (config->force_speed) + { + case FAL_SPEED_10: + speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE | + QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_10M; + break; + case FAL_SPEED_100: + speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE | + QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_100M; + break; + case FAL_SPEED_1000: + case FAL_SPEED_2500: + speed_mode = QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE | + QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_1G; + break; + default: + break; + } + } + else + { + speed_mode = QCA8084_UNIPHY_MMD1_CH0_AUTONEG_ENABLE; + } + qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1, + QCA8084_UNIPHY_MMD1_CHANNEL0_CFG, QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_MASK, speed_mode); + + /*GMII interface clock reset and release\n*/ + pr_debug("GMII interface clock reset and release\n"); + qca8084_port_clk_reset(qca8084_port_id, ethphy_clk_mask); + qca8084_port_clk_reset(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY); + + /*analog software reset and release*/ + pr_debug("analog software reset and release\n"); + qca8084_phy_modify_mii(uniphy_addr, + QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RESET); + mdelay(1); + qca8084_phy_modify_mii(uniphy_addr, + QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RELEASE); + + /*wait uniphy calibration done*/ + pr_debug("wait uniphy calibration done\n"); + qca8084_uniphy_calibration(uniphy_addr); + + /*GMII interface clock enable*/ + pr_debug("GMII interface clock enable\n"); + qca8084_port_clk_en_set(qca8084_port_id, ethphy_clk_mask, 1); + qca8084_port_clk_en_set(uniphy_port_id, QCA8084_CLK_TYPE_UNIPHY, 1); + + return; +} diff --git a/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.h b/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.h index 88eccce4f6..43dfeb7958 100644 --- a/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.h +++ b/drivers/net/ipq_common/ipq_qca8084_interface_ctrl.h @@ -129,6 +129,12 @@ #define QCA8084_UNIPHY_MMD_XPC_SPEED_10 0 #define QCA8084_UNIPHY_MMD_TX_IPG_CHECK_DISABLE 0x1 +#define UNIPHY_CLK_RATE_25M 25000000 +#define UNIPHY_CLK_RATE_50M 50000000 +#define UNIPHY_CLK_RATE_125M 125000000 +#define UNIPHY_CLK_RATE_312M 312500000 +#define UNIPHY_DEFAULT_RATE UNIPHY_CLK_RATE_125M + typedef enum { QCA8084_UNIPHY_MAC = QCA8084_UNIPHY_MMD1_SGMII_MAC_MODE, QCA8084_UNIPHY_PHY = QCA8084_UNIPHY_MMD1_SGMII_PHY_MODE, @@ -137,4 +143,29 @@ typedef enum { QCA8084_UNIPHY_UQXGMII = QCA8084_UNIPHY_MMD1_XPCS_MODE, } qca8084_uniphy_mode_t; +typedef enum { + QCA8084_INTERFACE_CLOCK_MAC_MODE = 0, + QCA8084_INTERFACE_CLOCK_PHY_MODE = 1, +} qca8084_clock_mode_t; + +typedef enum { + QCA8084_MAC_MODE_RGMII = 0, + QCA8084_MAC_MODE_GMII, + QCA8084_MAC_MODE_MII, + QCA8084_MAC_MODE_SGMII, + QCA8084_MAC_MODE_FIBER, + QCA8084_MAC_MODE_RMII, + QCA8084_MAC_MODE_SGMII_PLUS, + QCA8084_MAC_MODE_DEFAULT +} qca8084_mac_mode_t; + +typedef struct { + qca8084_mac_mode_t mac_mode; + qca8084_clock_mode_t clock_mode; + bool auto_neg; + u32 force_speed; + bool prbs_enable; + bool rem_phy_lpbk; +} mac_config_t; + #endif