Add the new programming sequence needed for EMAC3 based platforms such as the sc8280xp family. Signed-off-by: Andrew Halaney <ahalaney@xxxxxxxxxx> --- Changes since v1: * None .../stmicro/stmmac/dwmac-qcom-ethqos.c | 106 ++++++++++++++---- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 41e6f4fa92f3..1fe8563b9c0d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -11,6 +11,7 @@ #define RGMII_IO_MACRO_CONFIG 0x0 #define SDCC_HC_REG_DLL_CONFIG 0x4 +#define SDCC_TEST_CTL 0x8 #define SDCC_HC_REG_DDR_CONFIG 0xC #define SDCC_HC_REG_DLL_CONFIG2 0x10 #define SDC4_STATUS 0x14 @@ -49,6 +50,7 @@ #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21) #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27) #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30) +#define SDCC_DDR_CONFIG_TCXO_CYCLES_CNT GENMASK(11, 9) #define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0) /* SDCC_HC_REG_DLL_CONFIG2 fields */ @@ -79,6 +81,7 @@ struct ethqos_emac_driver_data { const struct ethqos_emac_por *por; unsigned int num_por; bool rgmii_config_loopback_en; + bool has_emac3; }; struct qcom_ethqos { @@ -92,6 +95,7 @@ struct qcom_ethqos { const struct ethqos_emac_por *por; unsigned int num_por; bool rgmii_config_loopback_en; + bool has_emac3; }; static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) @@ -184,6 +188,7 @@ static const struct ethqos_emac_driver_data emac_v2_3_0_data = { .por = emac_v2_3_0_por, .num_por = ARRAY_SIZE(emac_v2_3_0_por), .rgmii_config_loopback_en = true, + .has_emac3 = false, }; static const struct ethqos_emac_por emac_v2_1_0_por[] = { @@ -199,6 +204,23 @@ static const struct ethqos_emac_driver_data emac_v2_1_0_data = { .por = emac_v2_1_0_por, .num_por = ARRAY_SIZE(emac_v2_1_0_por), .rgmii_config_loopback_en = false, + .has_emac3 = false, +}; + +static const struct ethqos_emac_por emac_v3_0_0_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40c01343 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642c }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, + { .offset = SDCC_USR_CTL, .value = 0x00010800 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +}; + +static const struct ethqos_emac_driver_data emac_v3_0_0_data = { + .por = emac_v3_0_0_por, + .num_por = ARRAY_SIZE(emac_v3_0_0_por), + .rgmii_config_loopback_en = false, + .has_emac3 = true, }; static int ethqos_dll_configure(struct qcom_ethqos *ethqos) @@ -222,11 +244,13 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); - rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, - 0, SDCC_HC_REG_DLL_CONFIG); + if (!ethqos->has_emac3) { + rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, + 0, SDCC_HC_REG_DLL_CONFIG); - rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, - 0, SDCC_HC_REG_DLL_CONFIG); + rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, + 0, SDCC_HC_REG_DLL_CONFIG); + } /* Wait for CK_OUT_EN clear */ do { @@ -261,18 +285,20 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, - 0, SDCC_HC_REG_DLL_CONFIG2); + if (!ethqos->has_emac3) { + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + 0, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, - 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, + 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, - BIT(2), SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, + BIT(2), SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, - SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, - SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, + SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, + SDCC_HC_REG_DLL_CONFIG2); + } return 0; } @@ -326,9 +352,17 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); - /* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */ - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, - 57, SDCC_HC_REG_DDR_CONFIG); + /* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns, + * in practice this becomes PRG_RCLK_DLY = 52 * 4 / 2 * RX delay ns + */ + if (ethqos->has_emac3) + /* 0.9 ns */ + rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 115, SDCC_HC_REG_DDR_CONFIG); + else + /* 1.8 ns */ + rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 57, SDCC_HC_REG_DDR_CONFIG); rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_HC_REG_DDR_CONFIG); @@ -354,8 +388,15 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) BIT(6), RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + + if (ethqos->has_emac3) + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); + else + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + 0, RGMII_IO_MACRO_CONFIG2); + /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); @@ -388,8 +429,13 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + if (ethqos->has_emac3) + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); + else + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + 0, RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); @@ -432,6 +478,17 @@ static int ethqos_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); + if (ethqos->has_emac3) { + if (ethqos->speed == SPEED_1000) { + rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL); + rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL); + rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); + } else { + rgmii_writel(ethqos, 0x40010800, SDCC_USR_CTL); + rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); + } + } + /* Clear DLL_RST */ rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, SDCC_HC_REG_DLL_CONFIG); @@ -451,7 +508,9 @@ static int ethqos_configure(struct qcom_ethqos *ethqos) SDCC_HC_REG_DLL_CONFIG); /* Set USR_CTL bit 26 with mask of 3 bits */ - rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), SDCC_USR_CTL); + if (!ethqos->has_emac3) + rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), + SDCC_USR_CTL); /* wait for DLL LOCK */ do { @@ -546,6 +605,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->por = data->por; ethqos->num_por = data->num_por; ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; + ethqos->has_emac3 = data->has_emac3; ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); if (IS_ERR(ethqos->rgmii_clk)) { @@ -564,7 +624,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->bsp_priv = ethqos; plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->dump_debug_regs = rgmii_dump; - plat_dat->has_gmac4 = 1; + plat_dat->has_gmac4 = !data->has_emac3; + plat_dat->has_emac3 = data->has_emac3; plat_dat->pmt = 1; plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) @@ -603,6 +664,7 @@ static int qcom_ethqos_remove(struct platform_device *pdev) static const struct of_device_id qcom_ethqos_match[] = { { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, { .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data}, + { .compatible = "qcom,sc8280xp-ethqos", &emac_v3_0_0_data}, { } }; MODULE_DEVICE_TABLE(of, qcom_ethqos_match); -- 2.39.2