1a7c30e62SVinod Koul // SPDX-License-Identifier: GPL-2.0 2a7c30e62SVinod Koul // Copyright (c) 2018-19, Linaro Limited 3a7c30e62SVinod Koul 4a7c30e62SVinod Koul #include <linux/module.h> 5a7c30e62SVinod Koul #include <linux/of.h> 6a7c30e62SVinod Koul #include <linux/of_device.h> 7a7c30e62SVinod Koul #include <linux/platform_device.h> 8a7c30e62SVinod Koul #include <linux/phy.h> 9a7c30e62SVinod Koul #include "stmmac.h" 10a7c30e62SVinod Koul #include "stmmac_platform.h" 11a7c30e62SVinod Koul 12a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG 0x0 13a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG 0x4 14a7c30e62SVinod Koul #define SDCC_HC_REG_DDR_CONFIG 0xC 15a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG2 0x10 16a7c30e62SVinod Koul #define SDC4_STATUS 0x14 17a7c30e62SVinod Koul #define SDCC_USR_CTL 0x18 18a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG2 0x1C 19a7c30e62SVinod Koul #define RGMII_IO_MACRO_DEBUG1 0x20 20a7c30e62SVinod Koul #define EMAC_SYSTEM_LOW_POWER_DEBUG 0x28 21a7c30e62SVinod Koul 22a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG fields */ 23a7c30e62SVinod Koul #define RGMII_CONFIG_FUNC_CLK_EN BIT(30) 24a7c30e62SVinod Koul #define RGMII_CONFIG_POS_NEG_DATA_SEL BIT(23) 25a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_RX_INT GENMASK(21, 20) 26a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17) 27a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8) 28a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6) 29a7c30e62SVinod Koul #define RGMII_CONFIG_INTF_SEL GENMASK(5, 4) 30a7c30e62SVinod Koul #define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3) 31a7c30e62SVinod Koul #define RGMII_CONFIG_LOOPBACK_EN BIT(2) 32a7c30e62SVinod Koul #define RGMII_CONFIG_PROG_SWAP BIT(1) 33a7c30e62SVinod Koul #define RGMII_CONFIG_DDR_MODE BIT(0) 34a7c30e62SVinod Koul 35a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG fields */ 36a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_RST BIT(30) 37a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_PDN BIT(29) 38a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_MCLK_FREQ GENMASK(26, 24) 39a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_SELEXT GENMASK(23, 20) 40a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EXT_EN BIT(19) 41a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CK_OUT_EN BIT(18) 42a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EN BIT(17) 43a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_EN BIT(16) 44a7c30e62SVinod Koul #define SDCC_DLL_MCLK_GATING_EN BIT(5) 45a7c30e62SVinod Koul #define SDCC_DLL_CDR_FINE_PHASE GENMASK(3, 2) 46a7c30e62SVinod Koul 47a7c30e62SVinod Koul /* SDCC_HC_REG_DDR_CONFIG fields */ 48a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_DLY_EN BIT(31) 49a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21) 50a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27) 51a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30) 52a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0) 53a7c30e62SVinod Koul 54a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG2 fields */ 55a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS BIT(21) 56a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC GENMASK(17, 10) 57a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL GENMASK(3, 2) 58a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW BIT(1) 59a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_CAL_EN BIT(0) 60a7c30e62SVinod Koul 61a7c30e62SVinod Koul /* SDC4_STATUS bits */ 62a7c30e62SVinod Koul #define SDC4_STATUS_DLL_LOCK BIT(7) 63a7c30e62SVinod Koul 64a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG2 fields */ 65a7c30e62SVinod Koul #define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17) 66a7c30e62SVinod Koul #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16) 67a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN BIT(13) 68a7c30e62SVinod Koul #define RGMII_CONFIG2_CLK_DIVIDE_SEL BIT(12) 69a7c30e62SVinod Koul #define RGMII_CONFIG2_RX_PROG_SWAP BIT(7) 70a7c30e62SVinod Koul #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) 71a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) 72a7c30e62SVinod Koul 73a7c30e62SVinod Koul struct ethqos_emac_por { 74a7c30e62SVinod Koul unsigned int offset; 75a7c30e62SVinod Koul unsigned int value; 76a7c30e62SVinod Koul }; 77a7c30e62SVinod Koul 78fd4a5177SVinod Koul struct ethqos_emac_driver_data { 79fd4a5177SVinod Koul const struct ethqos_emac_por *por; 80fd4a5177SVinod Koul unsigned int num_por; 81fd4a5177SVinod Koul }; 82fd4a5177SVinod Koul 83a7c30e62SVinod Koul struct qcom_ethqos { 84a7c30e62SVinod Koul struct platform_device *pdev; 85a7c30e62SVinod Koul void __iomem *rgmii_base; 86a7c30e62SVinod Koul 87a7c30e62SVinod Koul unsigned int rgmii_clk_rate; 88a7c30e62SVinod Koul struct clk *rgmii_clk; 89a7c30e62SVinod Koul unsigned int speed; 90a7c30e62SVinod Koul 91a7c30e62SVinod Koul const struct ethqos_emac_por *por; 92a7c30e62SVinod Koul unsigned int num_por; 93a7c30e62SVinod Koul }; 94a7c30e62SVinod Koul 95a7c30e62SVinod Koul static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) 96a7c30e62SVinod Koul { 97a7c30e62SVinod Koul return readl(ethqos->rgmii_base + offset); 98a7c30e62SVinod Koul } 99a7c30e62SVinod Koul 100a7c30e62SVinod Koul static void rgmii_writel(struct qcom_ethqos *ethqos, 101a7c30e62SVinod Koul int value, unsigned int offset) 102a7c30e62SVinod Koul { 103a7c30e62SVinod Koul writel(value, ethqos->rgmii_base + offset); 104a7c30e62SVinod Koul } 105a7c30e62SVinod Koul 106a7c30e62SVinod Koul static void rgmii_updatel(struct qcom_ethqos *ethqos, 107a7c30e62SVinod Koul int mask, int val, unsigned int offset) 108a7c30e62SVinod Koul { 109a7c30e62SVinod Koul unsigned int temp; 110a7c30e62SVinod Koul 111a7c30e62SVinod Koul temp = rgmii_readl(ethqos, offset); 112a7c30e62SVinod Koul temp = (temp & ~(mask)) | val; 113a7c30e62SVinod Koul rgmii_writel(ethqos, temp, offset); 114a7c30e62SVinod Koul } 115a7c30e62SVinod Koul 116*4047b9dbSBhupesh Sharma static void rgmii_dump(void *priv) 117a7c30e62SVinod Koul { 118*4047b9dbSBhupesh Sharma struct qcom_ethqos *ethqos = priv; 119*4047b9dbSBhupesh Sharma 120a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "Rgmii register dump\n"); 121a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG: %x\n", 122a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG)); 123a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", 124a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG)); 125a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", 126a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG)); 127a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", 128a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2)); 129a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "SDC4_STATUS: %x\n", 130a7c30e62SVinod Koul rgmii_readl(ethqos, SDC4_STATUS)); 131a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "SDCC_USR_CTL: %x\n", 132a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_USR_CTL)); 133a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG2: %x\n", 134a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2)); 135a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_DEBUG1: %x\n", 136a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1)); 137a7c30e62SVinod Koul dev_dbg(ðqos->pdev->dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", 138a7c30e62SVinod Koul rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); 139a7c30e62SVinod Koul } 140a7c30e62SVinod Koul 141a7c30e62SVinod Koul /* Clock rates */ 142a7c30e62SVinod Koul #define RGMII_1000_NOM_CLK_FREQ (250 * 1000 * 1000UL) 143a7c30e62SVinod Koul #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ (50 * 1000 * 1000UL) 144a7c30e62SVinod Koul #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL) 145a7c30e62SVinod Koul 146a7c30e62SVinod Koul static void 147a7c30e62SVinod Koul ethqos_update_rgmii_clk(struct qcom_ethqos *ethqos, unsigned int speed) 148a7c30e62SVinod Koul { 149a7c30e62SVinod Koul switch (speed) { 150a7c30e62SVinod Koul case SPEED_1000: 151a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_1000_NOM_CLK_FREQ; 152a7c30e62SVinod Koul break; 153a7c30e62SVinod Koul 154a7c30e62SVinod Koul case SPEED_100: 155a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; 156a7c30e62SVinod Koul break; 157a7c30e62SVinod Koul 158a7c30e62SVinod Koul case SPEED_10: 159a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; 160a7c30e62SVinod Koul break; 161a7c30e62SVinod Koul } 162a7c30e62SVinod Koul 163a7c30e62SVinod Koul clk_set_rate(ethqos->rgmii_clk, ethqos->rgmii_clk_rate); 164a7c30e62SVinod Koul } 165a7c30e62SVinod Koul 166a7c30e62SVinod Koul static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) 167a7c30e62SVinod Koul { 168a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN, 169a7c30e62SVinod Koul RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); 170a7c30e62SVinod Koul } 171a7c30e62SVinod Koul 172a7c30e62SVinod Koul static const struct ethqos_emac_por emac_v2_3_0_por[] = { 173a7c30e62SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, 174a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, 175a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, 176a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, 177a7c30e62SVinod Koul { .offset = SDCC_USR_CTL, .value = 0x00010800 }, 178a7c30e62SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, 179a7c30e62SVinod Koul }; 180a7c30e62SVinod Koul 181fd4a5177SVinod Koul static const struct ethqos_emac_driver_data emac_v2_3_0_data = { 182fd4a5177SVinod Koul .por = emac_v2_3_0_por, 183fd4a5177SVinod Koul .num_por = ARRAY_SIZE(emac_v2_3_0_por), 184fd4a5177SVinod Koul }; 185fd4a5177SVinod Koul 186a7c30e62SVinod Koul static int ethqos_dll_configure(struct qcom_ethqos *ethqos) 187a7c30e62SVinod Koul { 188a7c30e62SVinod Koul unsigned int val; 189a7c30e62SVinod Koul int retry = 1000; 190a7c30e62SVinod Koul 191a7c30e62SVinod Koul /* Set CDR_EN */ 192a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, 193a7c30e62SVinod Koul SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); 194a7c30e62SVinod Koul 195a7c30e62SVinod Koul /* Set CDR_EXT_EN */ 196a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, 197a7c30e62SVinod Koul SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG); 198a7c30e62SVinod Koul 199a7c30e62SVinod Koul /* Clear CK_OUT_EN */ 200a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 201a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 202a7c30e62SVinod Koul 203a7c30e62SVinod Koul /* Set DLL_EN */ 204a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, 205a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); 206a7c30e62SVinod Koul 207a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, 208a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 209a7c30e62SVinod Koul 210a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, 211a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 212a7c30e62SVinod Koul 213a7c30e62SVinod Koul /* Wait for CK_OUT_EN clear */ 214a7c30e62SVinod Koul do { 215a7c30e62SVinod Koul val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); 216a7c30e62SVinod Koul val &= SDCC_DLL_CONFIG_CK_OUT_EN; 217a7c30e62SVinod Koul if (!val) 218a7c30e62SVinod Koul break; 219a7c30e62SVinod Koul mdelay(1); 220a7c30e62SVinod Koul retry--; 221a7c30e62SVinod Koul } while (retry > 0); 222a7c30e62SVinod Koul if (!retry) 223a7c30e62SVinod Koul dev_err(ðqos->pdev->dev, "Clear CK_OUT_EN timedout\n"); 224a7c30e62SVinod Koul 225a7c30e62SVinod Koul /* Set CK_OUT_EN */ 226a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 227a7c30e62SVinod Koul SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); 228a7c30e62SVinod Koul 229a7c30e62SVinod Koul /* Wait for CK_OUT_EN set */ 230a7c30e62SVinod Koul retry = 1000; 231a7c30e62SVinod Koul do { 232a7c30e62SVinod Koul val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); 233a7c30e62SVinod Koul val &= SDCC_DLL_CONFIG_CK_OUT_EN; 234a7c30e62SVinod Koul if (val) 235a7c30e62SVinod Koul break; 236a7c30e62SVinod Koul mdelay(1); 237a7c30e62SVinod Koul retry--; 238a7c30e62SVinod Koul } while (retry > 0); 239a7c30e62SVinod Koul if (!retry) 240a7c30e62SVinod Koul dev_err(ðqos->pdev->dev, "Set CK_OUT_EN timedout\n"); 241a7c30e62SVinod Koul 242a7c30e62SVinod Koul /* Set DDR_CAL_EN */ 243a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, 244a7c30e62SVinod Koul SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); 245a7c30e62SVinod Koul 246a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, 247a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG2); 248a7c30e62SVinod Koul 249a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 250a7c30e62SVinod Koul 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); 251a7c30e62SVinod Koul 252a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, 253a7c30e62SVinod Koul BIT(2), SDCC_HC_REG_DLL_CONFIG2); 254a7c30e62SVinod Koul 255a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, 256a7c30e62SVinod Koul SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, 257a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG2); 258a7c30e62SVinod Koul 259a7c30e62SVinod Koul return 0; 260a7c30e62SVinod Koul } 261a7c30e62SVinod Koul 262a7c30e62SVinod Koul static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) 263a7c30e62SVinod Koul { 264a7c30e62SVinod Koul /* Disable loopback mode */ 265a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, 266a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 267a7c30e62SVinod Koul 268a7c30e62SVinod Koul /* Select RGMII, write 0 to interface select */ 269a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, 270a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 271a7c30e62SVinod Koul 272a7c30e62SVinod Koul switch (ethqos->speed) { 273a7c30e62SVinod Koul case SPEED_1000: 274a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 275a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 276a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 277a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 278a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 279a7c30e62SVinod Koul RGMII_CONFIG_POS_NEG_DATA_SEL, 280a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 281a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 282a7c30e62SVinod Koul RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG); 283a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 284a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 285a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 286a7c30e62SVinod Koul RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 287a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG2); 288a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 289a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 290a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 291a7c30e62SVinod Koul RGMII_CONFIG2_RX_PROG_SWAP, 292a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG2); 293a7c30e62SVinod Koul 294a7c30e62SVinod Koul /* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */ 295a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 296a7c30e62SVinod Koul 57, SDCC_HC_REG_DDR_CONFIG); 297a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, 298a7c30e62SVinod Koul SDCC_DDR_CONFIG_PRG_DLY_EN, 299a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 300a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 301a7c30e62SVinod Koul RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); 302a7c30e62SVinod Koul break; 303a7c30e62SVinod Koul 304a7c30e62SVinod Koul case SPEED_100: 305a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 306a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 307a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 308a7c30e62SVinod Koul RGMII_CONFIG_BYPASS_TX_ID_EN, 309a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 310a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 311a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 312a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 313a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 314a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 315a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 316a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 317a7c30e62SVinod Koul RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 318a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG2); 319a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, 320a7c30e62SVinod Koul BIT(6), RGMII_IO_MACRO_CONFIG); 321a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 322a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 323a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 324a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 325a7c30e62SVinod Koul /* Write 0x5 to PRG_RCLK_DLY_CODE */ 326a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, 327a7c30e62SVinod Koul (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); 328a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 329a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 330a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 331a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 332a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 333a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 334a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 335a7c30e62SVinod Koul RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); 336a7c30e62SVinod Koul break; 337a7c30e62SVinod Koul 338a7c30e62SVinod Koul case SPEED_10: 339a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 340a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 341a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 342a7c30e62SVinod Koul RGMII_CONFIG_BYPASS_TX_ID_EN, 343a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 344a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 345a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 346a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 347a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 348a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 349a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 350a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 351a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 352a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, 353a7c30e62SVinod Koul BIT(12) | GENMASK(9, 8), 354a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 355a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 356a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 357a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 358a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 359a7c30e62SVinod Koul /* Write 0x5 to PRG_RCLK_DLY_CODE */ 360a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, 361a7c30e62SVinod Koul (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); 362a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 363a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 364a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 365a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 366a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 367a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 368a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 369a7c30e62SVinod Koul RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); 370a7c30e62SVinod Koul break; 371a7c30e62SVinod Koul default: 372a7c30e62SVinod Koul dev_err(ðqos->pdev->dev, 373a7c30e62SVinod Koul "Invalid speed %d\n", ethqos->speed); 374a7c30e62SVinod Koul return -EINVAL; 375a7c30e62SVinod Koul } 376a7c30e62SVinod Koul 377a7c30e62SVinod Koul return 0; 378a7c30e62SVinod Koul } 379a7c30e62SVinod Koul 380a7c30e62SVinod Koul static int ethqos_configure(struct qcom_ethqos *ethqos) 381a7c30e62SVinod Koul { 382a7c30e62SVinod Koul volatile unsigned int dll_lock; 383a7c30e62SVinod Koul unsigned int i, retry = 1000; 384a7c30e62SVinod Koul 385a7c30e62SVinod Koul /* Reset to POR values and enable clk */ 386a7c30e62SVinod Koul for (i = 0; i < ethqos->num_por; i++) 387a7c30e62SVinod Koul rgmii_writel(ethqos, ethqos->por[i].value, 388a7c30e62SVinod Koul ethqos->por[i].offset); 389a7c30e62SVinod Koul ethqos_set_func_clk_en(ethqos); 390a7c30e62SVinod Koul 391a7c30e62SVinod Koul /* Initialize the DLL first */ 392a7c30e62SVinod Koul 393a7c30e62SVinod Koul /* Set DLL_RST */ 394a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 395a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); 396a7c30e62SVinod Koul 397a7c30e62SVinod Koul /* Set PDN */ 398a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 399a7c30e62SVinod Koul SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); 400a7c30e62SVinod Koul 401a7c30e62SVinod Koul /* Clear DLL_RST */ 402a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, 403a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 404a7c30e62SVinod Koul 405a7c30e62SVinod Koul /* Clear PDN */ 406a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0, 407a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 408a7c30e62SVinod Koul 409a7c30e62SVinod Koul if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { 410a7c30e62SVinod Koul /* Set DLL_EN */ 411a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, 412a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); 413a7c30e62SVinod Koul 414a7c30e62SVinod Koul /* Set CK_OUT_EN */ 415a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 416a7c30e62SVinod Koul SDCC_DLL_CONFIG_CK_OUT_EN, 417a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 418a7c30e62SVinod Koul 419a7c30e62SVinod Koul /* Set USR_CTL bit 26 with mask of 3 bits */ 420a7c30e62SVinod Koul rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), SDCC_USR_CTL); 421a7c30e62SVinod Koul 422a7c30e62SVinod Koul /* wait for DLL LOCK */ 423a7c30e62SVinod Koul do { 424a7c30e62SVinod Koul mdelay(1); 425a7c30e62SVinod Koul dll_lock = rgmii_readl(ethqos, SDC4_STATUS); 426a7c30e62SVinod Koul if (dll_lock & SDC4_STATUS_DLL_LOCK) 427a7c30e62SVinod Koul break; 4287d10f077SDejin Zheng retry--; 429a7c30e62SVinod Koul } while (retry > 0); 430a7c30e62SVinod Koul if (!retry) 431a7c30e62SVinod Koul dev_err(ðqos->pdev->dev, 432a7c30e62SVinod Koul "Timeout while waiting for DLL lock\n"); 433a7c30e62SVinod Koul } 434a7c30e62SVinod Koul 435a7c30e62SVinod Koul if (ethqos->speed == SPEED_1000) 436a7c30e62SVinod Koul ethqos_dll_configure(ethqos); 437a7c30e62SVinod Koul 438a7c30e62SVinod Koul ethqos_rgmii_macro_init(ethqos); 439a7c30e62SVinod Koul 440a7c30e62SVinod Koul return 0; 441a7c30e62SVinod Koul } 442a7c30e62SVinod Koul 443a7c30e62SVinod Koul static void ethqos_fix_mac_speed(void *priv, unsigned int speed) 444a7c30e62SVinod Koul { 445a7c30e62SVinod Koul struct qcom_ethqos *ethqos = priv; 446a7c30e62SVinod Koul 447a7c30e62SVinod Koul ethqos->speed = speed; 448a7c30e62SVinod Koul ethqos_update_rgmii_clk(ethqos, speed); 449a7c30e62SVinod Koul ethqos_configure(ethqos); 450a7c30e62SVinod Koul } 451a7c30e62SVinod Koul 4526c950ca7SBhupesh Sharma static int ethqos_clks_config(void *priv, bool enabled) 4536c950ca7SBhupesh Sharma { 4546c950ca7SBhupesh Sharma struct qcom_ethqos *ethqos = priv; 4556c950ca7SBhupesh Sharma int ret = 0; 4566c950ca7SBhupesh Sharma 4576c950ca7SBhupesh Sharma if (enabled) { 4586c950ca7SBhupesh Sharma ret = clk_prepare_enable(ethqos->rgmii_clk); 4596c950ca7SBhupesh Sharma if (ret) { 4606c950ca7SBhupesh Sharma dev_err(ðqos->pdev->dev, "rgmii_clk enable failed\n"); 4616c950ca7SBhupesh Sharma return ret; 4626c950ca7SBhupesh Sharma } 4636c950ca7SBhupesh Sharma } else { 4646c950ca7SBhupesh Sharma clk_disable_unprepare(ethqos->rgmii_clk); 4656c950ca7SBhupesh Sharma } 4666c950ca7SBhupesh Sharma 4676c950ca7SBhupesh Sharma return ret; 4686c950ca7SBhupesh Sharma } 4696c950ca7SBhupesh Sharma 470a7c30e62SVinod Koul static int qcom_ethqos_probe(struct platform_device *pdev) 471a7c30e62SVinod Koul { 472a7c30e62SVinod Koul struct device_node *np = pdev->dev.of_node; 473a7c30e62SVinod Koul struct plat_stmmacenet_data *plat_dat; 474a7c30e62SVinod Koul struct stmmac_resources stmmac_res; 475fd4a5177SVinod Koul const struct ethqos_emac_driver_data *data; 476a7c30e62SVinod Koul struct qcom_ethqos *ethqos; 477a7c30e62SVinod Koul int ret; 478a7c30e62SVinod Koul 479a7c30e62SVinod Koul ret = stmmac_get_platform_resources(pdev, &stmmac_res); 480a7c30e62SVinod Koul if (ret) 481a7c30e62SVinod Koul return ret; 482a7c30e62SVinod Koul 48383216e39SMichael Walle plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 484a7c30e62SVinod Koul if (IS_ERR(plat_dat)) { 485a7c30e62SVinod Koul dev_err(&pdev->dev, "dt configuration failed\n"); 486a7c30e62SVinod Koul return PTR_ERR(plat_dat); 487a7c30e62SVinod Koul } 488a7c30e62SVinod Koul 4896c950ca7SBhupesh Sharma plat_dat->clks_config = ethqos_clks_config; 4906c950ca7SBhupesh Sharma 491a7c30e62SVinod Koul ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); 492a7c30e62SVinod Koul if (!ethqos) { 493a7c30e62SVinod Koul ret = -ENOMEM; 494a7c30e62SVinod Koul goto err_mem; 495a7c30e62SVinod Koul } 496a7c30e62SVinod Koul 497a7c30e62SVinod Koul ethqos->pdev = pdev; 4983a5a32b5SYang Yingliang ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); 499a7c30e62SVinod Koul if (IS_ERR(ethqos->rgmii_base)) { 500a7c30e62SVinod Koul ret = PTR_ERR(ethqos->rgmii_base); 501a7c30e62SVinod Koul goto err_mem; 502a7c30e62SVinod Koul } 503a7c30e62SVinod Koul 504fd4a5177SVinod Koul data = of_device_get_match_data(&pdev->dev); 505fd4a5177SVinod Koul ethqos->por = data->por; 506fd4a5177SVinod Koul ethqos->num_por = data->num_por; 507a7c30e62SVinod Koul 508a7c30e62SVinod Koul ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); 5098f4ebaaaSWei Yongjun if (IS_ERR(ethqos->rgmii_clk)) { 5108f4ebaaaSWei Yongjun ret = PTR_ERR(ethqos->rgmii_clk); 511a7c30e62SVinod Koul goto err_mem; 512a7c30e62SVinod Koul } 513a7c30e62SVinod Koul 5146c950ca7SBhupesh Sharma ret = ethqos_clks_config(ethqos, true); 515a7c30e62SVinod Koul if (ret) 516a7c30e62SVinod Koul goto err_mem; 517a7c30e62SVinod Koul 518a7c30e62SVinod Koul ethqos->speed = SPEED_1000; 519a7c30e62SVinod Koul ethqos_update_rgmii_clk(ethqos, SPEED_1000); 520a7c30e62SVinod Koul ethqos_set_func_clk_en(ethqos); 521a7c30e62SVinod Koul 522a7c30e62SVinod Koul plat_dat->bsp_priv = ethqos; 523a7c30e62SVinod Koul plat_dat->fix_mac_speed = ethqos_fix_mac_speed; 524*4047b9dbSBhupesh Sharma plat_dat->dump_debug_regs = rgmii_dump; 525a7c30e62SVinod Koul plat_dat->has_gmac4 = 1; 526a7c30e62SVinod Koul plat_dat->pmt = 1; 527a7c30e62SVinod Koul plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); 528a7c30e62SVinod Koul 529a7c30e62SVinod Koul ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 530a7c30e62SVinod Koul if (ret) 531a7c30e62SVinod Koul goto err_clk; 532a7c30e62SVinod Koul 533a7c30e62SVinod Koul return ret; 534a7c30e62SVinod Koul 535a7c30e62SVinod Koul err_clk: 5366c950ca7SBhupesh Sharma ethqos_clks_config(ethqos, false); 537a7c30e62SVinod Koul 538a7c30e62SVinod Koul err_mem: 539a7c30e62SVinod Koul stmmac_remove_config_dt(pdev, plat_dat); 540a7c30e62SVinod Koul 541a7c30e62SVinod Koul return ret; 542a7c30e62SVinod Koul } 543a7c30e62SVinod Koul 544a7c30e62SVinod Koul static int qcom_ethqos_remove(struct platform_device *pdev) 545a7c30e62SVinod Koul { 546a7c30e62SVinod Koul struct qcom_ethqos *ethqos; 547a7c30e62SVinod Koul int ret; 548a7c30e62SVinod Koul 549a7c30e62SVinod Koul ethqos = get_stmmac_bsp_priv(&pdev->dev); 550a7c30e62SVinod Koul if (!ethqos) 551a7c30e62SVinod Koul return -ENODEV; 552a7c30e62SVinod Koul 553a7c30e62SVinod Koul ret = stmmac_pltfr_remove(pdev); 5546c950ca7SBhupesh Sharma ethqos_clks_config(ethqos, false); 555a7c30e62SVinod Koul 556a7c30e62SVinod Koul return ret; 557a7c30e62SVinod Koul } 558a7c30e62SVinod Koul 559a7c30e62SVinod Koul static const struct of_device_id qcom_ethqos_match[] = { 560fd4a5177SVinod Koul { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, 561a7c30e62SVinod Koul { } 562a7c30e62SVinod Koul }; 563a7c30e62SVinod Koul MODULE_DEVICE_TABLE(of, qcom_ethqos_match); 564a7c30e62SVinod Koul 565a7c30e62SVinod Koul static struct platform_driver qcom_ethqos_driver = { 566a7c30e62SVinod Koul .probe = qcom_ethqos_probe, 567a7c30e62SVinod Koul .remove = qcom_ethqos_remove, 568a7c30e62SVinod Koul .driver = { 569a7c30e62SVinod Koul .name = "qcom-ethqos", 570a7c30e62SVinod Koul .pm = &stmmac_pltfr_pm_ops, 571a7c30e62SVinod Koul .of_match_table = of_match_ptr(qcom_ethqos_match), 572a7c30e62SVinod Koul }, 573a7c30e62SVinod Koul }; 574a7c30e62SVinod Koul module_platform_driver(qcom_ethqos_driver); 575a7c30e62SVinod Koul 576a7c30e62SVinod Koul MODULE_DESCRIPTION("Qualcomm ETHQOS driver"); 577a7c30e62SVinod Koul MODULE_LICENSE("GPL v2"); 578