blob: f3db8b83a791a5aa33525eee98fcc0ddcfb0e8fa [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 Airoha Inc.
* Author: Min Yao <min.yao@airoha.com>
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/of_platform.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of_address.h>
#include "an8855.h"
#include "an8855_regs.h"
/* AN8855 registers */
#define SCU_BASE 0x10000000
#define RG_RGMII_TXCK_C (SCU_BASE + 0x1d0)
#define HSGMII_AN_CSR_BASE 0x10220000
#define SGMII_REG_AN0 (HSGMII_AN_CSR_BASE + 0x000)
#define SGMII_REG_AN_13 (HSGMII_AN_CSR_BASE + 0x034)
#define SGMII_REG_AN_FORCE_CL37 (HSGMII_AN_CSR_BASE + 0x060)
#define HSGMII_CSR_PCS_BASE 0x10220000
#define RG_HSGMII_PCS_CTROL_1 (HSGMII_CSR_PCS_BASE + 0xa00)
#define RG_AN_SGMII_MODE_FORCE (HSGMII_CSR_PCS_BASE + 0xa24)
#define MULTI_SGMII_CSR_BASE 0x10224000
#define SGMII_STS_CTRL_0 (MULTI_SGMII_CSR_BASE + 0x018)
#define MSG_RX_CTRL_0 (MULTI_SGMII_CSR_BASE + 0x100)
#define MSG_RX_LIK_STS_0 (MULTI_SGMII_CSR_BASE + 0x514)
#define MSG_RX_LIK_STS_2 (MULTI_SGMII_CSR_BASE + 0x51c)
#define PHY_RX_FORCE_CTRL_0 (MULTI_SGMII_CSR_BASE + 0x520)
#define XFI_CSR_PCS_BASE 0x10225000
#define RG_USXGMII_AN_CONTROL_0 (XFI_CSR_PCS_BASE + 0xbf8)
#define MULTI_PHY_RA_CSR_BASE 0x10226000
#define RG_RATE_ADAPT_CTRL_0 (MULTI_PHY_RA_CSR_BASE + 0x000)
#define RATE_ADP_P0_CTRL_0 (MULTI_PHY_RA_CSR_BASE + 0x100)
#define MII_RA_AN_ENABLE (MULTI_PHY_RA_CSR_BASE + 0x300)
#define QP_DIG_CSR_BASE 0x1022a000
#define QP_CK_RST_CTRL_4 (QP_DIG_CSR_BASE + 0x310)
#define QP_DIG_MODE_CTRL_0 (QP_DIG_CSR_BASE + 0x324)
#define QP_DIG_MODE_CTRL_1 (QP_DIG_CSR_BASE + 0x330)
#define SERDES_WRAPPER_BASE 0x1022c000
#define USGMII_CTRL_0 (SERDES_WRAPPER_BASE + 0x000)
#define QP_PMA_TOP_BASE 0x1022e000
#define PON_RXFEDIG_CTRL_0 (QP_PMA_TOP_BASE + 0x100)
#define PON_RXFEDIG_CTRL_9 (QP_PMA_TOP_BASE + 0x124)
#define SS_LCPLL_PWCTL_SETTING_2 (QP_PMA_TOP_BASE + 0x208)
#define SS_LCPLL_TDC_FLT_2 (QP_PMA_TOP_BASE + 0x230)
#define SS_LCPLL_TDC_FLT_5 (QP_PMA_TOP_BASE + 0x23c)
#define SS_LCPLL_TDC_PCW_1 (QP_PMA_TOP_BASE + 0x248)
#define INTF_CTRL_8 (QP_PMA_TOP_BASE + 0x320)
#define INTF_CTRL_9 (QP_PMA_TOP_BASE + 0x324)
#define PLL_CTRL_0 (QP_PMA_TOP_BASE + 0x400)
#define PLL_CTRL_2 (QP_PMA_TOP_BASE + 0x408)
#define PLL_CTRL_3 (QP_PMA_TOP_BASE + 0x40c)
#define PLL_CTRL_4 (QP_PMA_TOP_BASE + 0x410)
#define PLL_CK_CTRL_0 (QP_PMA_TOP_BASE + 0x414)
#define RX_DLY_0 (QP_PMA_TOP_BASE + 0x614)
#define RX_CTRL_2 (QP_PMA_TOP_BASE + 0x630)
#define RX_CTRL_5 (QP_PMA_TOP_BASE + 0x63c)
#define RX_CTRL_6 (QP_PMA_TOP_BASE + 0x640)
#define RX_CTRL_7 (QP_PMA_TOP_BASE + 0x644)
#define RX_CTRL_8 (QP_PMA_TOP_BASE + 0x648)
#define RX_CTRL_26 (QP_PMA_TOP_BASE + 0x690)
#define RX_CTRL_42 (QP_PMA_TOP_BASE + 0x6d0)
#define QP_ANA_CSR_BASE 0x1022f000
#define RG_QP_RX_DAC_EN (QP_ANA_CSR_BASE + 0x00)
#define RG_QP_RXAFE_RESERVE (QP_ANA_CSR_BASE + 0x04)
#define RG_QP_CDR_LPF_MJV_LIM (QP_ANA_CSR_BASE + 0x0c)
#define RG_QP_CDR_LPF_SETVALUE (QP_ANA_CSR_BASE + 0x14)
#define RG_QP_CDR_PR_CKREF_DIV1 (QP_ANA_CSR_BASE + 0x18)
#define RG_QP_CDR_PR_KBAND_DIV_PCIE (QP_ANA_CSR_BASE + 0x1c)
#define RG_QP_CDR_FORCE_IBANDLPF_R_OFF (QP_ANA_CSR_BASE + 0x20)
#define RG_QP_TX_MODE_16B_EN (QP_ANA_CSR_BASE + 0x28)
#define RG_QP_PLL_IPLL_DIG_PWR_SEL (QP_ANA_CSR_BASE + 0x3c)
#define RG_QP_PLL_SDM_ORD (QP_ANA_CSR_BASE + 0x40)
#define ETHER_SYS_BASE 0x1028c800
#define RG_P5MUX_MODE (ETHER_SYS_BASE + 0x00)
#define RG_FORCE_CKDIR_SEL (ETHER_SYS_BASE + 0x04)
#define RG_SWITCH_MODE (ETHER_SYS_BASE + 0x08)
#define RG_FORCE_MAC5_SB (ETHER_SYS_BASE + 0x2c)
#define RG_GPHY_AFE_PWD (ETHER_SYS_BASE + 0x40)
#define RG_GPHY_SMI_ADDR (ETHER_SYS_BASE + 0x48)
#define CSR_RMII (ETHER_SYS_BASE + 0x70)
/* PHY EEE Register bitmap of define */
#define PHY_DEV07 0x07
#define PHY_DEV07_REG_03C 0x3c
/* PHY Extend Register 0x14 bitmap of define */
#define PHY_EXT_REG_14 0x14
/* Fields of PHY_EXT_REG_14 */
#define PHY_EN_DOWN_SHFIT BIT(4)
/* Unique fields of PMCR for AN8855 */
#define FORCE_TX_FC BIT(4)
#define FORCE_RX_FC BIT(5)
#define FORCE_DPX BIT(25)
#define FORCE_SPD BITS(28, 30)
#define FORCE_LNK BIT(24)
#define FORCE_MODE BIT(31)
#define CHIP_ID 0x10005000
#define CHIP_REV 0x10005004
static int an8855_set_hsgmii_mode(struct gsw_an8855 *gsw)
{
u32 val = 0;
/* PLL */
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
val &= ~(0x3 << 2);
val |= (0x1 << 2);
an8855_reg_write(gsw, QP_DIG_MODE_CTRL_1, val);
/* PLL - LPF */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0x3 << 0);
val |= (0x1 << 0);
val &= ~(0x7 << 2);
val |= (0x5 << 2);
val &= ~BITS(6, 7);
val &= ~(0x7 << 8);
val |= (0x3 << 8);
val |= BIT(29);
val &= ~BITS(12, 13);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - ICO */
val = an8855_reg_read(gsw, PLL_CTRL_4);
val |= BIT(2);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~BIT(14);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - CHP */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0xf << 16);
val |= (0x6 << 16);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - PFD */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0x3 << 20);
val |= (0x1 << 20);
val &= ~(0x3 << 24);
val |= (0x1 << 24);
val &= ~BIT(26);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - POSTDIV */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val |= BIT(22);
val &= ~BIT(27);
val &= ~BIT(28);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - SDM */
val = an8855_reg_read(gsw, PLL_CTRL_4);
val &= ~BITS(3, 4);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~BIT(30);
an8855_reg_write(gsw, PLL_CTRL_2, val);
val = an8855_reg_read(gsw, SS_LCPLL_PWCTL_SETTING_2);
val &= ~(0x3 << 16);
val |= (0x1 << 16);
an8855_reg_write(gsw, SS_LCPLL_PWCTL_SETTING_2, val);
an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_2, 0x7a000000);
an8855_reg_write(gsw, SS_LCPLL_TDC_PCW_1, 0x7a000000);
val = an8855_reg_read(gsw, SS_LCPLL_TDC_FLT_5);
val &= ~BIT(24);
an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_5, val);
val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
val &= ~BIT(8);
an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
/* PLL - SS */
val = an8855_reg_read(gsw, PLL_CTRL_3);
val &= ~BITS(0, 15);
an8855_reg_write(gsw, PLL_CTRL_3, val);
val = an8855_reg_read(gsw, PLL_CTRL_4);
val &= ~BITS(0, 1);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_3);
val &= ~BITS(16, 31);
an8855_reg_write(gsw, PLL_CTRL_3, val);
/* PLL - TDC */
val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
val &= ~BIT(9);
an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
val = an8855_reg_read(gsw, RG_QP_PLL_SDM_ORD);
val |= BIT(3);
val |= BIT(4);
an8855_reg_write(gsw, RG_QP_PLL_SDM_ORD, val);
val = an8855_reg_read(gsw, RG_QP_RX_DAC_EN);
val &= ~(0x3 << 16);
val |= (0x2 << 16);
an8855_reg_write(gsw, RG_QP_RX_DAC_EN, val);
/* TCL Disable (only for Co-SIM) */
val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_0);
val &= ~BIT(12);
an8855_reg_write(gsw, PON_RXFEDIG_CTRL_0, val);
/* TX Init */
val = an8855_reg_read(gsw, RG_QP_TX_MODE_16B_EN);
val &= ~BIT(0);
val &= ~(0xffff << 16);
val |= (0x4 << 16);
an8855_reg_write(gsw, RG_QP_TX_MODE_16B_EN, val);
/* RX Control */
val = an8855_reg_read(gsw, RG_QP_RXAFE_RESERVE);
val |= BIT(11);
an8855_reg_write(gsw, RG_QP_RXAFE_RESERVE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_MJV_LIM);
val &= ~(0x3 << 4);
val |= (0x1 << 4);
an8855_reg_write(gsw, RG_QP_CDR_LPF_MJV_LIM, val);
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_SETVALUE);
val &= ~(0xf << 25);
val |= (0x1 << 25);
val &= ~(0x7 << 29);
val |= (0x3 << 29);
an8855_reg_write(gsw, RG_QP_CDR_LPF_SETVALUE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
val &= ~(0x1f << 8);
val |= (0xf << 8);
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
val &= ~(0x3f << 0);
val |= (0x19 << 0);
val &= ~BIT(6);
an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
val &= ~(0x7f << 6);
val |= (0x21 << 6);
val &= ~(0x3 << 16);
val |= (0x2 << 16);
val &= ~BIT(13);
an8855_reg_write(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
val &= ~BIT(30);
an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
val &= ~(0x7 << 24);
val |= (0x4 << 24);
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
val = an8855_reg_read(gsw, PLL_CTRL_0);
val |= BIT(0);
an8855_reg_write(gsw, PLL_CTRL_0, val);
val = an8855_reg_read(gsw, RX_CTRL_26);
val &= ~BIT(23);
val |= BIT(26);
an8855_reg_write(gsw, RX_CTRL_26, val);
val = an8855_reg_read(gsw, RX_DLY_0);
val &= ~(0xff << 0);
val |= (0x6f << 0);
val |= BITS(8, 13);
an8855_reg_write(gsw, RX_DLY_0, val);
val = an8855_reg_read(gsw, RX_CTRL_42);
val &= ~(0x1fff << 0);
val |= (0x150 << 0);
an8855_reg_write(gsw, RX_CTRL_42, val);
val = an8855_reg_read(gsw, RX_CTRL_2);
val &= ~(0x1fff << 16);
val |= (0x150 << 16);
an8855_reg_write(gsw, RX_CTRL_2, val);
val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_9);
val &= ~(0x7 << 0);
val |= (0x1 << 0);
an8855_reg_write(gsw, PON_RXFEDIG_CTRL_9, val);
val = an8855_reg_read(gsw, RX_CTRL_8);
val &= ~(0xfff << 16);
val |= (0x200 << 16);
val &= ~(0x7fff << 14);
val |= (0xfff << 14);
an8855_reg_write(gsw, RX_CTRL_8, val);
/* Frequency memter */
val = an8855_reg_read(gsw, RX_CTRL_5);
val &= ~(0xfffff << 10);
val |= (0x10 << 10);
an8855_reg_write(gsw, RX_CTRL_5, val);
val = an8855_reg_read(gsw, RX_CTRL_6);
val &= ~(0xfffff << 0);
val |= (0x64 << 0);
an8855_reg_write(gsw, RX_CTRL_6, val);
val = an8855_reg_read(gsw, RX_CTRL_7);
val &= ~(0xfffff << 0);
val |= (0x2710 << 0);
an8855_reg_write(gsw, RX_CTRL_7, val);
/* PCS Init */
val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
val &= ~BIT(30);
an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
/* Rate Adaption */
val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
val &= ~BIT(31);
an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
val |= BIT(0);
val |= BIT(4);
val |= BITS(26, 27);
an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
/* Disable AN */
val = an8855_reg_read(gsw, SGMII_REG_AN0);
val &= ~BIT(12);
an8855_reg_write(gsw, SGMII_REG_AN0, val);
/* Force Speed */
val = an8855_reg_read(gsw, SGMII_STS_CTRL_0);
val |= BIT(2);
val |= BITS(4, 5);
an8855_reg_write(gsw, SGMII_STS_CTRL_0, val);
/* bypass flow control to MAC */
an8855_reg_write(gsw, MSG_RX_LIK_STS_0, 0x01010107);
an8855_reg_write(gsw, MSG_RX_LIK_STS_2, 0x00000EEF);
return 0;
}
static int an8855_sgmii_setup(struct gsw_an8855 *gsw, int mode)
{
u32 val = 0;
/* PMA Init */
/* PLL */
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_1);
val &= ~BITS(2, 3);
an8855_reg_write(gsw, QP_DIG_MODE_CTRL_1, val);
/* PLL - LPF */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0x3 << 0);
val |= (0x1 << 0);
val &= ~(0x7 << 2);
val |= (0x5 << 2);
val &= ~BITS(6, 7);
val &= ~(0x7 << 8);
val |= (0x3 << 8);
val |= BIT(29);
val &= ~BITS(12, 13);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - ICO */
val = an8855_reg_read(gsw, PLL_CTRL_4);
val |= BIT(2);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~BIT(14);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - CHP */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0xf << 16);
val |= (0x4 << 16);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - PFD */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~(0x3 << 20);
val |= (0x1 << 20);
val &= ~(0x3 << 24);
val |= (0x1 << 24);
val &= ~BIT(26);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - POSTDIV */
val = an8855_reg_read(gsw, PLL_CTRL_2);
val |= BIT(22);
val &= ~BIT(27);
val &= ~BIT(28);
an8855_reg_write(gsw, PLL_CTRL_2, val);
/* PLL - SDM */
val = an8855_reg_read(gsw, PLL_CTRL_4);
val &= ~BITS(3, 4);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_2);
val &= ~BIT(30);
an8855_reg_write(gsw, PLL_CTRL_2, val);
val = an8855_reg_read(gsw, SS_LCPLL_PWCTL_SETTING_2);
val &= ~(0x3 << 16);
val |= (0x1 << 16);
an8855_reg_write(gsw, SS_LCPLL_PWCTL_SETTING_2, val);
an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_2, 0x48000000);
an8855_reg_write(gsw, SS_LCPLL_TDC_PCW_1, 0x48000000);
val = an8855_reg_read(gsw, SS_LCPLL_TDC_FLT_5);
val &= ~BIT(24);
an8855_reg_write(gsw, SS_LCPLL_TDC_FLT_5, val);
val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
val &= ~BIT(8);
an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
/* PLL - SS */
val = an8855_reg_read(gsw, PLL_CTRL_3);
val &= ~BITS(0, 15);
an8855_reg_write(gsw, PLL_CTRL_3, val);
val = an8855_reg_read(gsw, PLL_CTRL_4);
val &= ~BITS(0, 1);
an8855_reg_write(gsw, PLL_CTRL_4, val);
val = an8855_reg_read(gsw, PLL_CTRL_3);
val &= ~BITS(16, 31);
an8855_reg_write(gsw, PLL_CTRL_3, val);
/* PLL - TDC */
val = an8855_reg_read(gsw, PLL_CK_CTRL_0);
val &= ~BIT(9);
an8855_reg_write(gsw, PLL_CK_CTRL_0, val);
val = an8855_reg_read(gsw, RG_QP_PLL_SDM_ORD);
val |= BIT(3);
val |= BIT(4);
an8855_reg_write(gsw, RG_QP_PLL_SDM_ORD, val);
val = an8855_reg_read(gsw, RG_QP_RX_DAC_EN);
val &= ~(0x3 << 16);
val |= (0x2 << 16);
an8855_reg_write(gsw, RG_QP_RX_DAC_EN, val);
/* PLL - TCL Disable (only for Co-SIM) */
val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_0);
val &= ~BIT(12);
an8855_reg_write(gsw, PON_RXFEDIG_CTRL_0, val);
/* TX Init */
val = an8855_reg_read(gsw, RG_QP_TX_MODE_16B_EN);
val &= ~BIT(0);
val &= ~BITS(16, 31);
an8855_reg_write(gsw, RG_QP_TX_MODE_16B_EN, val);
/* RX Init */
val = an8855_reg_read(gsw, RG_QP_RXAFE_RESERVE);
val |= BIT(11);
an8855_reg_write(gsw, RG_QP_RXAFE_RESERVE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_MJV_LIM);
val &= ~(0x3 << 4);
val |= (0x2 << 4);
an8855_reg_write(gsw, RG_QP_CDR_LPF_MJV_LIM, val);
val = an8855_reg_read(gsw, RG_QP_CDR_LPF_SETVALUE);
val &= ~(0xf << 25);
val |= (0x1 << 25);
val &= ~(0x7 << 29);
val |= (0x6 << 29);
an8855_reg_write(gsw, RG_QP_CDR_LPF_SETVALUE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
val &= ~(0x1f << 8);
val |= (0xc << 8);
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
val &= ~(0x3f << 0);
val |= (0x19 << 0);
val &= ~BIT(6);
an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF);
val &= ~(0x7f << 6);
val |= (0x21 << 6);
val &= ~(0x3 << 16);
val |= (0x2 << 16);
val &= ~BIT(13);
an8855_reg_write(gsw, RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE);
val &= ~BIT(30);
an8855_reg_write(gsw, RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
val = an8855_reg_read(gsw, RG_QP_CDR_PR_CKREF_DIV1);
val &= ~(0x7 << 24);
val |= (0x4 << 24);
an8855_reg_write(gsw, RG_QP_CDR_PR_CKREF_DIV1, val);
val = an8855_reg_read(gsw, PLL_CTRL_0);
val |= BIT(0);
an8855_reg_write(gsw, PLL_CTRL_0, val);
val = an8855_reg_read(gsw, RX_CTRL_26);
val &= ~BIT(23);
if (mode == SGMII_MODE_AN)
val |= BIT(26);
an8855_reg_write(gsw, RX_CTRL_26, val);
val = an8855_reg_read(gsw, RX_DLY_0);
val &= ~(0xff << 0);
val |= (0x6f << 0);
val |= BITS(8, 13);
an8855_reg_write(gsw, RX_DLY_0, val);
val = an8855_reg_read(gsw, RX_CTRL_42);
val &= ~(0x1fff << 0);
val |= (0x150 << 0);
an8855_reg_write(gsw, RX_CTRL_42, val);
val = an8855_reg_read(gsw, RX_CTRL_2);
val &= ~(0x1fff << 16);
val |= (0x150 << 16);
an8855_reg_write(gsw, RX_CTRL_2, val);
val = an8855_reg_read(gsw, PON_RXFEDIG_CTRL_9);
val &= ~(0x7 << 0);
val |= (0x1 << 0);
an8855_reg_write(gsw, PON_RXFEDIG_CTRL_9, val);
val = an8855_reg_read(gsw, RX_CTRL_8);
val &= ~(0xfff << 16);
val |= (0x200 << 16);
val &= ~(0x7fff << 0);
val |= (0xfff << 0);
an8855_reg_write(gsw, RX_CTRL_8, val);
/* Frequency memter */
val = an8855_reg_read(gsw, RX_CTRL_5);
val &= ~(0xfffff << 10);
val |= (0x28 << 10);
an8855_reg_write(gsw, RX_CTRL_5, val);
val = an8855_reg_read(gsw, RX_CTRL_6);
val &= ~(0xfffff << 0);
val |= (0x64 << 0);
an8855_reg_write(gsw, RX_CTRL_6, val);
val = an8855_reg_read(gsw, RX_CTRL_7);
val &= ~(0xfffff << 0);
val |= (0x2710 << 0);
an8855_reg_write(gsw, RX_CTRL_7, val);
if (mode == SGMII_MODE_FORCE) {
/* PCS Init */
val = an8855_reg_read(gsw, QP_DIG_MODE_CTRL_0);
val &= ~BIT(0);
val &= ~BITS(4, 5);
an8855_reg_write(gsw, QP_DIG_MODE_CTRL_0, val);
val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
val &= ~BIT(30);
an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
/* Rate Adaption - GMII path config. */
val = an8855_reg_read(gsw, RG_AN_SGMII_MODE_FORCE);
val |= BIT(0);
val &= ~BITS(4, 5);
an8855_reg_write(gsw, RG_AN_SGMII_MODE_FORCE, val);
val = an8855_reg_read(gsw, SGMII_STS_CTRL_0);
val |= BIT(2);
val &= ~(0x3 << 4);
val |= (0x2 << 4);
an8855_reg_write(gsw, SGMII_STS_CTRL_0, val);
val = an8855_reg_read(gsw, SGMII_REG_AN0);
val &= ~BIT(12);
an8855_reg_write(gsw, SGMII_REG_AN0, val);
val = an8855_reg_read(gsw, PHY_RX_FORCE_CTRL_0);
val |= BIT(4);
an8855_reg_write(gsw, PHY_RX_FORCE_CTRL_0, val);
val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
val &= ~BITS(0, 3);
val |= BIT(28);
an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
val |= BIT(0);
val |= BIT(4);
val |= BITS(26, 27);
an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
} else {
/* PCS Init */
val = an8855_reg_read(gsw, RG_HSGMII_PCS_CTROL_1);
val &= ~BIT(30);
an8855_reg_write(gsw, RG_HSGMII_PCS_CTROL_1, val);
/* Set AN Ability - Interrupt */
val = an8855_reg_read(gsw, SGMII_REG_AN_FORCE_CL37);
val |= BIT(0);
an8855_reg_write(gsw, SGMII_REG_AN_FORCE_CL37, val);
val = an8855_reg_read(gsw, SGMII_REG_AN_13);
val &= ~(0x3f << 0);
val |= (0xb << 0);
val |= BIT(8);
an8855_reg_write(gsw, SGMII_REG_AN_13, val);
/* Rate Adaption - GMII path config. */
val = an8855_reg_read(gsw, SGMII_REG_AN0);
val |= BIT(12);
an8855_reg_write(gsw, SGMII_REG_AN0, val);
val = an8855_reg_read(gsw, MII_RA_AN_ENABLE);
val |= BIT(0);
an8855_reg_write(gsw, MII_RA_AN_ENABLE, val);
val = an8855_reg_read(gsw, RATE_ADP_P0_CTRL_0);
val |= BIT(28);
an8855_reg_write(gsw, RATE_ADP_P0_CTRL_0, val);
val = an8855_reg_read(gsw, RG_RATE_ADAPT_CTRL_0);
val |= BIT(0);
val |= BIT(4);
val |= BITS(26, 27);
an8855_reg_write(gsw, RG_RATE_ADAPT_CTRL_0, val);
/* Only for Co-SIM */
/* AN Speed up (Only for Co-SIM) */
/* Restart AN */
val = an8855_reg_read(gsw, SGMII_REG_AN0);
val |= BIT(9);
val |= BIT(15);
an8855_reg_write(gsw, SGMII_REG_AN0, val);
}
/* bypass flow control to MAC */
an8855_reg_write(gsw, MSG_RX_LIK_STS_0, 0x01010107);
an8855_reg_write(gsw, MSG_RX_LIK_STS_2, 0x00000EEF);
return 0;
}
static int an8855_set_port_rmii(struct gsw_an8855 *gsw)
{
an8855_reg_write(gsw, RG_P5MUX_MODE, 0x301);
an8855_reg_write(gsw, RG_FORCE_CKDIR_SEL, 0x101);
an8855_reg_write(gsw, RG_SWITCH_MODE, 0x101);
an8855_reg_write(gsw, RG_FORCE_MAC5_SB, 0x1010101);
an8855_reg_write(gsw, CSR_RMII, 0x420102);
an8855_reg_write(gsw, RG_RGMII_TXCK_C, 0x1100910);
return 0;
}
static int an8855_set_port_rgmii(struct gsw_an8855 *gsw)
{
an8855_reg_write(gsw, RG_FORCE_MAC5_SB, 0x20101);
return 0;
}
static int an8855_mac_port_setup(struct gsw_an8855 *gsw, u32 port,
struct an8855_port_cfg *port_cfg)
{
u32 pmcr;
if (port != 5) {
dev_info(gsw->dev, "port %d is not a MAC port\n", port);
return -EINVAL;
}
if (port_cfg->enabled) {
pmcr = an8855_reg_read(gsw, PMCR(5));
switch (port_cfg->phy_mode) {
case PHY_INTERFACE_MODE_RMII:
pmcr &= ~FORCE_SPD;
pmcr |= FORCE_MODE | (MAC_SPD_100 << 28) | FORCE_DPX
| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
an8855_set_port_rmii(gsw);
break;
case PHY_INTERFACE_MODE_RGMII:
pmcr &= ~FORCE_SPD;
pmcr |= FORCE_MODE | (MAC_SPD_1000 << 28) | FORCE_DPX
| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
an8855_set_port_rgmii(gsw);
break;
case PHY_INTERFACE_MODE_SGMII:
if (port_cfg->force_link) {
pmcr &= ~FORCE_SPD;
pmcr |= FORCE_MODE | (MAC_SPD_1000 << 28)
| FORCE_DPX | FORCE_LNK | FORCE_TX_FC
| FORCE_RX_FC;
an8855_sgmii_setup(gsw, SGMII_MODE_FORCE);
} else
an8855_sgmii_setup(gsw, SGMII_MODE_AN);
break;
case PHY_INTERFACE_MODE_2500BASEX:
pmcr &= ~FORCE_SPD;
pmcr |= FORCE_MODE | (MAC_SPD_2500 << 28) | FORCE_DPX
| FORCE_LNK | FORCE_TX_FC | FORCE_RX_FC;
an8855_set_hsgmii_mode(gsw);
break;
default:
dev_info(gsw->dev, "%s is not supported by port %d\n",
phy_modes(port_cfg->phy_mode), port);
}
if (port_cfg->force_link)
an8855_reg_write(gsw, PMCR(port), pmcr);
}
return 0;
}
static int an8855_sw_detect(struct gsw_an8855 *gsw, struct chip_rev *crev)
{
u32 id, rev;
id = an8855_reg_read(gsw, CHIP_ID);
rev = an8855_reg_read(gsw, CHIP_REV);
if (id == AN8855) {
if (crev) {
crev->rev = rev;
crev->name = "AN8855";
}
return 0;
}
return -ENODEV;
}
static void an8855_phy_setting(struct gsw_an8855 *gsw)
{
int i;
u32 val;
/* Release power down */
an8855_reg_write(gsw, RG_GPHY_AFE_PWD, 0x0);
for (i = 0; i < AN8855_NUM_PHYS; i++) {
/* Enable HW auto downshift */
gsw->mii_write(gsw, i, 0x1f, 0x1);
val = gsw->mii_read(gsw, i, PHY_EXT_REG_14);
val |= PHY_EN_DOWN_SHFIT;
gsw->mii_write(gsw, i, PHY_EXT_REG_14, val);
gsw->mii_write(gsw, i, 0x1f, 0x0);
/* Enable Asymmetric Pause Capability */
val = gsw->mii_read(gsw, i, MII_ADVERTISE);
val |= ADVERTISE_PAUSE_ASYM;
gsw->mii_write(gsw, i, MII_ADVERTISE, val);
}
}
static void an8855_low_power_setting(struct gsw_an8855 *gsw)
{
int port, addr;
for (port = 0; port < AN8855_NUM_PHYS; port++) {
gsw->mmd_write(gsw, port, 0x1e, 0x11, 0x0f00);
gsw->mmd_write(gsw, port, 0x1e, 0x3c, 0x0000);
gsw->mmd_write(gsw, port, 0x1e, 0x3d, 0x0000);
gsw->mmd_write(gsw, port, 0x1e, 0x3e, 0x0000);
gsw->mmd_write(gsw, port, 0x1e, 0xc6, 0x53aa);
}
gsw->mmd_write(gsw, 0, 0x1f, 0x268, 0x07f1);
gsw->mmd_write(gsw, 0, 0x1f, 0x269, 0x2111);
gsw->mmd_write(gsw, 0, 0x1f, 0x26a, 0x0000);
gsw->mmd_write(gsw, 0, 0x1f, 0x26b, 0x0074);
gsw->mmd_write(gsw, 0, 0x1f, 0x26e, 0x00f6);
gsw->mmd_write(gsw, 0, 0x1f, 0x26f, 0x6666);
gsw->mmd_write(gsw, 0, 0x1f, 0x271, 0x2c02);
gsw->mmd_write(gsw, 0, 0x1f, 0x272, 0x0c22);
gsw->mmd_write(gsw, 0, 0x1f, 0x700, 0x0001);
gsw->mmd_write(gsw, 0, 0x1f, 0x701, 0x0803);
gsw->mmd_write(gsw, 0, 0x1f, 0x702, 0x01b6);
gsw->mmd_write(gsw, 0, 0x1f, 0x703, 0x2111);
gsw->mmd_write(gsw, 1, 0x1f, 0x700, 0x0001);
for (addr = 0x200; addr <= 0x230; addr += 2)
gsw->mmd_write(gsw, 0, 0x1f, addr, 0x2020);
for (addr = 0x201; addr <= 0x231; addr += 2)
gsw->mmd_write(gsw, 0, 0x1f, addr, 0x0020);
}
static void an8855_eee_setting(struct gsw_an8855 *gsw, u32 port)
{
/* Disable EEE */
gsw->mmd_write(gsw, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
}
static int an8855_sw_init(struct gsw_an8855 *gsw)
{
int i;
u32 val;
gsw->phy_base = gsw->smi_addr & AN8855_SMI_ADDR_MASK;
gsw->mii_read = an8855_mii_read;
gsw->mii_write = an8855_mii_write;
gsw->mmd_read = an8855_mmd_read;
gsw->mmd_write = an8855_mmd_write;
/* Force MAC link down before reset */
an8855_reg_write(gsw, PMCR(5), FORCE_MODE);
/* Switch soft reset */
an8855_reg_write(gsw, SYS_CTRL, SW_SYS_RST);
usleep_range(100000, 110000);
/* change gphy smi address */
if (gsw->new_smi_addr != gsw->smi_addr) {
an8855_reg_write(gsw, RG_GPHY_SMI_ADDR, gsw->new_smi_addr);
gsw->smi_addr = gsw->new_smi_addr;
gsw->phy_base = gsw->new_smi_addr;
}
for (i = 0; i < AN8855_NUM_PHYS; i++) {
val = gsw->mii_read(gsw, i, MII_BMCR);
val |= BMCR_ISOLATE;
gsw->mii_write(gsw, i, MII_BMCR, val);
}
an8855_mac_port_setup(gsw, 5, &gsw->port5_cfg);
/* Global mac control settings */
val = an8855_reg_read(gsw, GMACCR);
val |= (15 << MAX_RX_JUMBO_S) | RX_PKT_LEN_MAX_JUMBO;
an8855_reg_write(gsw, GMACCR, val);
val = an8855_reg_read(gsw, CKGCR);
val &= ~(CKG_LNKDN_GLB_STOP | CKG_LNKDN_PORT_STOP);
an8855_reg_write(gsw, CKGCR, val);
return 0;
}
static int an8855_sw_post_init(struct gsw_an8855 *gsw)
{
int i;
u32 val;
for (i = 0; i < AN8855_NUM_PHYS; i++) {
val = gsw->mii_read(gsw, i, MII_BMCR);
val &= ~BMCR_ISOLATE;
gsw->mii_write(gsw, i, MII_BMCR, val);
}
an8855_phy_setting(gsw);
for (i = 0; i < AN8855_NUM_PHYS; i++)
an8855_eee_setting(gsw, i);
/* PHY restart AN*/
for (i = 0; i < AN8855_NUM_PHYS; i++)
gsw->mii_write(gsw, i, MII_BMCR, 0x1240);
return 0;
}
struct an8855_sw_id an8855_id = {
.model = AN8855,
.detect = an8855_sw_detect,
.init = an8855_sw_init,
.post_init = an8855_sw_post_init
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Min Yao <min.yao@airoha.com>");
MODULE_DESCRIPTION("Driver for Airoha AN8855 Gigabit Switch");