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> 9ee8daccaSBartosz Golaszewski #include <linux/property.h> 10*97f73bc5SBartosz Golaszewski 11a7c30e62SVinod Koul #include "stmmac.h" 12a7c30e62SVinod Koul #include "stmmac_platform.h" 13a7c30e62SVinod Koul 14a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG 0x0 15a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG 0x4 16b6837619SAndrew Halaney #define SDCC_TEST_CTL 0x8 17a7c30e62SVinod Koul #define SDCC_HC_REG_DDR_CONFIG 0xC 18a7c30e62SVinod Koul #define SDCC_HC_REG_DLL_CONFIG2 0x10 19a7c30e62SVinod Koul #define SDC4_STATUS 0x14 20a7c30e62SVinod Koul #define SDCC_USR_CTL 0x18 21a7c30e62SVinod Koul #define RGMII_IO_MACRO_CONFIG2 0x1C 22a7c30e62SVinod Koul #define RGMII_IO_MACRO_DEBUG1 0x20 23a7c30e62SVinod Koul #define EMAC_SYSTEM_LOW_POWER_DEBUG 0x28 24a7c30e62SVinod Koul 25a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG fields */ 26a7c30e62SVinod Koul #define RGMII_CONFIG_FUNC_CLK_EN BIT(30) 27a7c30e62SVinod Koul #define RGMII_CONFIG_POS_NEG_DATA_SEL BIT(23) 28a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_RX_INT GENMASK(21, 20) 29a7c30e62SVinod Koul #define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17) 30a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8) 31a7c30e62SVinod Koul #define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6) 32a7c30e62SVinod Koul #define RGMII_CONFIG_INTF_SEL GENMASK(5, 4) 33a7c30e62SVinod Koul #define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3) 34a7c30e62SVinod Koul #define RGMII_CONFIG_LOOPBACK_EN BIT(2) 35a7c30e62SVinod Koul #define RGMII_CONFIG_PROG_SWAP BIT(1) 36a7c30e62SVinod Koul #define RGMII_CONFIG_DDR_MODE BIT(0) 37a7c30e62SVinod Koul 38a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG fields */ 39a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_RST BIT(30) 40a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_PDN BIT(29) 41a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_MCLK_FREQ GENMASK(26, 24) 42a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_SELEXT GENMASK(23, 20) 43a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EXT_EN BIT(19) 44a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CK_OUT_EN BIT(18) 45a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_CDR_EN BIT(17) 46a7c30e62SVinod Koul #define SDCC_DLL_CONFIG_DLL_EN BIT(16) 47a7c30e62SVinod Koul #define SDCC_DLL_MCLK_GATING_EN BIT(5) 48a7c30e62SVinod Koul #define SDCC_DLL_CDR_FINE_PHASE GENMASK(3, 2) 49a7c30e62SVinod Koul 50a7c30e62SVinod Koul /* SDCC_HC_REG_DDR_CONFIG fields */ 51a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_DLY_EN BIT(31) 52a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21) 53a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27) 54a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30) 55b6837619SAndrew Halaney #define SDCC_DDR_CONFIG_TCXO_CYCLES_CNT GENMASK(11, 9) 56a7c30e62SVinod Koul #define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0) 57a7c30e62SVinod Koul 58a7c30e62SVinod Koul /* SDCC_HC_REG_DLL_CONFIG2 fields */ 59a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS BIT(21) 60a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC GENMASK(17, 10) 61a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL GENMASK(3, 2) 62a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW BIT(1) 63a7c30e62SVinod Koul #define SDCC_DLL_CONFIG2_DDR_CAL_EN BIT(0) 64a7c30e62SVinod Koul 65a7c30e62SVinod Koul /* SDC4_STATUS bits */ 66a7c30e62SVinod Koul #define SDC4_STATUS_DLL_LOCK BIT(7) 67a7c30e62SVinod Koul 68a7c30e62SVinod Koul /* RGMII_IO_MACRO_CONFIG2 fields */ 69a7c30e62SVinod Koul #define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17) 70a7c30e62SVinod Koul #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16) 71a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN BIT(13) 72a7c30e62SVinod Koul #define RGMII_CONFIG2_CLK_DIVIDE_SEL BIT(12) 73a7c30e62SVinod Koul #define RGMII_CONFIG2_RX_PROG_SWAP BIT(7) 74a7c30e62SVinod Koul #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) 75a7c30e62SVinod Koul #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) 76a7c30e62SVinod Koul 77a7c30e62SVinod Koul struct ethqos_emac_por { 78a7c30e62SVinod Koul unsigned int offset; 79a7c30e62SVinod Koul unsigned int value; 80a7c30e62SVinod Koul }; 81a7c30e62SVinod Koul 82fd4a5177SVinod Koul struct ethqos_emac_driver_data { 83fd4a5177SVinod Koul const struct ethqos_emac_por *por; 84fd4a5177SVinod Koul unsigned int num_por; 85030f1d59SAndrew Halaney bool rgmii_config_loopback_en; 86b6837619SAndrew Halaney bool has_emac3; 87b6837619SAndrew Halaney struct dwmac4_addrs dwmac4_addrs; 88fd4a5177SVinod Koul }; 89fd4a5177SVinod Koul 90a7c30e62SVinod Koul struct qcom_ethqos { 91a7c30e62SVinod Koul struct platform_device *pdev; 92a7c30e62SVinod Koul void __iomem *rgmii_base; 93a7c30e62SVinod Koul 94a7c30e62SVinod Koul unsigned int rgmii_clk_rate; 95a7c30e62SVinod Koul struct clk *rgmii_clk; 96a7c30e62SVinod Koul unsigned int speed; 97a7c30e62SVinod Koul 98a7c30e62SVinod Koul const struct ethqos_emac_por *por; 99a7c30e62SVinod Koul unsigned int num_por; 100030f1d59SAndrew Halaney bool rgmii_config_loopback_en; 101b6837619SAndrew Halaney bool has_emac3; 102a7c30e62SVinod Koul }; 103a7c30e62SVinod Koul 104a7c30e62SVinod Koul static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) 105a7c30e62SVinod Koul { 106a7c30e62SVinod Koul return readl(ethqos->rgmii_base + offset); 107a7c30e62SVinod Koul } 108a7c30e62SVinod Koul 109a7c30e62SVinod Koul static void rgmii_writel(struct qcom_ethqos *ethqos, 110a7c30e62SVinod Koul int value, unsigned int offset) 111a7c30e62SVinod Koul { 112a7c30e62SVinod Koul writel(value, ethqos->rgmii_base + offset); 113a7c30e62SVinod Koul } 114a7c30e62SVinod Koul 115a7c30e62SVinod Koul static void rgmii_updatel(struct qcom_ethqos *ethqos, 116a7c30e62SVinod Koul int mask, int val, unsigned int offset) 117a7c30e62SVinod Koul { 118a7c30e62SVinod Koul unsigned int temp; 119a7c30e62SVinod Koul 120a7c30e62SVinod Koul temp = rgmii_readl(ethqos, offset); 121a7c30e62SVinod Koul temp = (temp & ~(mask)) | val; 122a7c30e62SVinod Koul rgmii_writel(ethqos, temp, offset); 123a7c30e62SVinod Koul } 124a7c30e62SVinod Koul 1254047b9dbSBhupesh Sharma static void rgmii_dump(void *priv) 126a7c30e62SVinod Koul { 1274047b9dbSBhupesh Sharma struct qcom_ethqos *ethqos = priv; 128302555a0SBartosz Golaszewski struct device *dev = ðqos->pdev->dev; 1294047b9dbSBhupesh Sharma 130302555a0SBartosz Golaszewski dev_dbg(dev, "Rgmii register dump\n"); 131302555a0SBartosz Golaszewski dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %x\n", 132a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG)); 133302555a0SBartosz Golaszewski dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", 134a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG)); 135302555a0SBartosz Golaszewski dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", 136a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG)); 137302555a0SBartosz Golaszewski dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", 138a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2)); 139302555a0SBartosz Golaszewski dev_dbg(dev, "SDC4_STATUS: %x\n", 140a7c30e62SVinod Koul rgmii_readl(ethqos, SDC4_STATUS)); 141302555a0SBartosz Golaszewski dev_dbg(dev, "SDCC_USR_CTL: %x\n", 142a7c30e62SVinod Koul rgmii_readl(ethqos, SDCC_USR_CTL)); 143302555a0SBartosz Golaszewski dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %x\n", 144a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2)); 145302555a0SBartosz Golaszewski dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %x\n", 146a7c30e62SVinod Koul rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1)); 147302555a0SBartosz Golaszewski dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", 148a7c30e62SVinod Koul rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); 149a7c30e62SVinod Koul } 150a7c30e62SVinod Koul 151a7c30e62SVinod Koul /* Clock rates */ 152a7c30e62SVinod Koul #define RGMII_1000_NOM_CLK_FREQ (250 * 1000 * 1000UL) 153a7c30e62SVinod Koul #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ (50 * 1000 * 1000UL) 154a7c30e62SVinod Koul #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL) 155a7c30e62SVinod Koul 156a7c30e62SVinod Koul static void 157a7c30e62SVinod Koul ethqos_update_rgmii_clk(struct qcom_ethqos *ethqos, unsigned int speed) 158a7c30e62SVinod Koul { 159a7c30e62SVinod Koul switch (speed) { 160a7c30e62SVinod Koul case SPEED_1000: 161a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_1000_NOM_CLK_FREQ; 162a7c30e62SVinod Koul break; 163a7c30e62SVinod Koul 164a7c30e62SVinod Koul case SPEED_100: 165a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; 166a7c30e62SVinod Koul break; 167a7c30e62SVinod Koul 168a7c30e62SVinod Koul case SPEED_10: 169a7c30e62SVinod Koul ethqos->rgmii_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; 170a7c30e62SVinod Koul break; 171a7c30e62SVinod Koul } 172a7c30e62SVinod Koul 173a7c30e62SVinod Koul clk_set_rate(ethqos->rgmii_clk, ethqos->rgmii_clk_rate); 174a7c30e62SVinod Koul } 175a7c30e62SVinod Koul 176a7c30e62SVinod Koul static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) 177a7c30e62SVinod Koul { 178a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN, 179a7c30e62SVinod Koul RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); 180a7c30e62SVinod Koul } 181a7c30e62SVinod Koul 182a7c30e62SVinod Koul static const struct ethqos_emac_por emac_v2_3_0_por[] = { 183a7c30e62SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, 184a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, 185a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, 186a7c30e62SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, 187a7c30e62SVinod Koul { .offset = SDCC_USR_CTL, .value = 0x00010800 }, 188a7c30e62SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, 189a7c30e62SVinod Koul }; 190a7c30e62SVinod Koul 191fd4a5177SVinod Koul static const struct ethqos_emac_driver_data emac_v2_3_0_data = { 192fd4a5177SVinod Koul .por = emac_v2_3_0_por, 193fd4a5177SVinod Koul .num_por = ARRAY_SIZE(emac_v2_3_0_por), 194030f1d59SAndrew Halaney .rgmii_config_loopback_en = true, 195b6837619SAndrew Halaney .has_emac3 = false, 196fd4a5177SVinod Koul }; 197fd4a5177SVinod Koul 198d90b3120SVinod Koul static const struct ethqos_emac_por emac_v2_1_0_por[] = { 199d90b3120SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40C01343 }, 200d90b3120SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, 201d90b3120SVinod Koul { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, 202d90b3120SVinod Koul { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, 203d90b3120SVinod Koul { .offset = SDCC_USR_CTL, .value = 0x00010800 }, 204d90b3120SVinod Koul { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, 205d90b3120SVinod Koul }; 206d90b3120SVinod Koul 207d90b3120SVinod Koul static const struct ethqos_emac_driver_data emac_v2_1_0_data = { 208d90b3120SVinod Koul .por = emac_v2_1_0_por, 209d90b3120SVinod Koul .num_por = ARRAY_SIZE(emac_v2_1_0_por), 210030f1d59SAndrew Halaney .rgmii_config_loopback_en = false, 211b6837619SAndrew Halaney .has_emac3 = false, 212b6837619SAndrew Halaney }; 213b6837619SAndrew Halaney 214b6837619SAndrew Halaney static const struct ethqos_emac_por emac_v3_0_0_por[] = { 215b6837619SAndrew Halaney { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40c01343 }, 216b6837619SAndrew Halaney { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642c }, 217b6837619SAndrew Halaney { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, 218b6837619SAndrew Halaney { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, 219b6837619SAndrew Halaney { .offset = SDCC_USR_CTL, .value = 0x00010800 }, 220b6837619SAndrew Halaney { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, 221b6837619SAndrew Halaney }; 222b6837619SAndrew Halaney 223b6837619SAndrew Halaney static const struct ethqos_emac_driver_data emac_v3_0_0_data = { 224b6837619SAndrew Halaney .por = emac_v3_0_0_por, 225b6837619SAndrew Halaney .num_por = ARRAY_SIZE(emac_v3_0_0_por), 226b6837619SAndrew Halaney .rgmii_config_loopback_en = false, 227b6837619SAndrew Halaney .has_emac3 = true, 228b6837619SAndrew Halaney .dwmac4_addrs = { 229b6837619SAndrew Halaney .dma_chan = 0x00008100, 230b6837619SAndrew Halaney .dma_chan_offset = 0x1000, 231b6837619SAndrew Halaney .mtl_chan = 0x00008000, 232b6837619SAndrew Halaney .mtl_chan_offset = 0x1000, 233b6837619SAndrew Halaney .mtl_ets_ctrl = 0x00008010, 234b6837619SAndrew Halaney .mtl_ets_ctrl_offset = 0x1000, 235b6837619SAndrew Halaney .mtl_txq_weight = 0x00008018, 236b6837619SAndrew Halaney .mtl_txq_weight_offset = 0x1000, 237b6837619SAndrew Halaney .mtl_send_slp_cred = 0x0000801c, 238b6837619SAndrew Halaney .mtl_send_slp_cred_offset = 0x1000, 239b6837619SAndrew Halaney .mtl_high_cred = 0x00008020, 240b6837619SAndrew Halaney .mtl_high_cred_offset = 0x1000, 241b6837619SAndrew Halaney .mtl_low_cred = 0x00008024, 242b6837619SAndrew Halaney .mtl_low_cred_offset = 0x1000, 243b6837619SAndrew Halaney }, 244d90b3120SVinod Koul }; 245d90b3120SVinod Koul 246a7c30e62SVinod Koul static int ethqos_dll_configure(struct qcom_ethqos *ethqos) 247a7c30e62SVinod Koul { 248302555a0SBartosz Golaszewski struct device *dev = ðqos->pdev->dev; 249a7c30e62SVinod Koul unsigned int val; 250a7c30e62SVinod Koul int retry = 1000; 251a7c30e62SVinod Koul 252a7c30e62SVinod Koul /* Set CDR_EN */ 253a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, 254a7c30e62SVinod Koul SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); 255a7c30e62SVinod Koul 256a7c30e62SVinod Koul /* Set CDR_EXT_EN */ 257a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, 258a7c30e62SVinod Koul SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG); 259a7c30e62SVinod Koul 260a7c30e62SVinod Koul /* Clear CK_OUT_EN */ 261a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 262a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 263a7c30e62SVinod Koul 264a7c30e62SVinod Koul /* Set DLL_EN */ 265a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, 266a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); 267a7c30e62SVinod Koul 268b6837619SAndrew Halaney if (!ethqos->has_emac3) { 269a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, 270a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 271a7c30e62SVinod Koul 272a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, 273a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG); 274b6837619SAndrew Halaney } 275a7c30e62SVinod Koul 276a7c30e62SVinod Koul /* Wait for CK_OUT_EN clear */ 277a7c30e62SVinod Koul do { 278a7c30e62SVinod Koul val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); 279a7c30e62SVinod Koul val &= SDCC_DLL_CONFIG_CK_OUT_EN; 280a7c30e62SVinod Koul if (!val) 281a7c30e62SVinod Koul break; 282a7c30e62SVinod Koul mdelay(1); 283a7c30e62SVinod Koul retry--; 284a7c30e62SVinod Koul } while (retry > 0); 285a7c30e62SVinod Koul if (!retry) 286302555a0SBartosz Golaszewski dev_err(dev, "Clear CK_OUT_EN timedout\n"); 287a7c30e62SVinod Koul 288a7c30e62SVinod Koul /* Set CK_OUT_EN */ 289a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 290a7c30e62SVinod Koul SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); 291a7c30e62SVinod Koul 292a7c30e62SVinod Koul /* Wait for CK_OUT_EN set */ 293a7c30e62SVinod Koul retry = 1000; 294a7c30e62SVinod Koul do { 295a7c30e62SVinod Koul val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); 296a7c30e62SVinod Koul val &= SDCC_DLL_CONFIG_CK_OUT_EN; 297a7c30e62SVinod Koul if (val) 298a7c30e62SVinod Koul break; 299a7c30e62SVinod Koul mdelay(1); 300a7c30e62SVinod Koul retry--; 301a7c30e62SVinod Koul } while (retry > 0); 302a7c30e62SVinod Koul if (!retry) 303302555a0SBartosz Golaszewski dev_err(dev, "Set CK_OUT_EN timedout\n"); 304a7c30e62SVinod Koul 305a7c30e62SVinod Koul /* Set DDR_CAL_EN */ 306a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, 307a7c30e62SVinod Koul SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); 308a7c30e62SVinod Koul 309b6837619SAndrew Halaney if (!ethqos->has_emac3) { 310a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, 311a7c30e62SVinod Koul 0, SDCC_HC_REG_DLL_CONFIG2); 312a7c30e62SVinod Koul 313a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 314a7c30e62SVinod Koul 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); 315a7c30e62SVinod Koul 316a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, 317a7c30e62SVinod Koul BIT(2), SDCC_HC_REG_DLL_CONFIG2); 318a7c30e62SVinod Koul 319a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, 320a7c30e62SVinod Koul SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, 321a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG2); 322b6837619SAndrew Halaney } 323a7c30e62SVinod Koul 324a7c30e62SVinod Koul return 0; 325a7c30e62SVinod Koul } 326a7c30e62SVinod Koul 327a7c30e62SVinod Koul static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) 328a7c30e62SVinod Koul { 329302555a0SBartosz Golaszewski struct device *dev = ðqos->pdev->dev; 330164a9ebeSAndrew Halaney int phase_shift; 331164a9ebeSAndrew Halaney int phy_mode; 332030f1d59SAndrew Halaney int loopback; 333164a9ebeSAndrew Halaney 334164a9ebeSAndrew Halaney /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ 335302555a0SBartosz Golaszewski phy_mode = device_get_phy_mode(dev); 336164a9ebeSAndrew Halaney if (phy_mode == PHY_INTERFACE_MODE_RGMII_ID || 337164a9ebeSAndrew Halaney phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) 338164a9ebeSAndrew Halaney phase_shift = 0; 339164a9ebeSAndrew Halaney else 340164a9ebeSAndrew Halaney phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; 341164a9ebeSAndrew Halaney 342a7c30e62SVinod Koul /* Disable loopback mode */ 343a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, 344a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 345a7c30e62SVinod Koul 346030f1d59SAndrew Halaney /* Determine if this platform wants loopback enabled after programming */ 347030f1d59SAndrew Halaney if (ethqos->rgmii_config_loopback_en) 348030f1d59SAndrew Halaney loopback = RGMII_CONFIG_LOOPBACK_EN; 349030f1d59SAndrew Halaney else 350030f1d59SAndrew Halaney loopback = 0; 351030f1d59SAndrew Halaney 352a7c30e62SVinod Koul /* Select RGMII, write 0 to interface select */ 353a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, 354a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 355a7c30e62SVinod Koul 356a7c30e62SVinod Koul switch (ethqos->speed) { 357a7c30e62SVinod Koul case SPEED_1000: 358a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 359a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 360a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 361a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 362a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 363a7c30e62SVinod Koul RGMII_CONFIG_POS_NEG_DATA_SEL, 364a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 365a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 366a7c30e62SVinod Koul RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG); 367a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 368a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 369164a9ebeSAndrew Halaney 370a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 371164a9ebeSAndrew Halaney phase_shift, RGMII_IO_MACRO_CONFIG2); 372a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 373a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 374a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 375a7c30e62SVinod Koul RGMII_CONFIG2_RX_PROG_SWAP, 376a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG2); 377a7c30e62SVinod Koul 378b6837619SAndrew Halaney /* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns, 379b6837619SAndrew Halaney * in practice this becomes PRG_RCLK_DLY = 52 * 4 / 2 * RX delay ns 380b6837619SAndrew Halaney */ 381b6837619SAndrew Halaney if (ethqos->has_emac3) { 382b6837619SAndrew Halaney /* 0.9 ns */ 383b6837619SAndrew Halaney rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 384b6837619SAndrew Halaney 115, SDCC_HC_REG_DDR_CONFIG); 385b6837619SAndrew Halaney } else { 386b6837619SAndrew Halaney /* 1.8 ns */ 387a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 388a7c30e62SVinod Koul 57, SDCC_HC_REG_DDR_CONFIG); 389b6837619SAndrew Halaney } 390a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, 391a7c30e62SVinod Koul SDCC_DDR_CONFIG_PRG_DLY_EN, 392a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 393a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 394030f1d59SAndrew Halaney loopback, RGMII_IO_MACRO_CONFIG); 395a7c30e62SVinod Koul break; 396a7c30e62SVinod Koul 397a7c30e62SVinod Koul case SPEED_100: 398a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 399a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 400a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 401a7c30e62SVinod Koul RGMII_CONFIG_BYPASS_TX_ID_EN, 402a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 403a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 404a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 405a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 406a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 407a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 408a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 409a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 410164a9ebeSAndrew Halaney phase_shift, RGMII_IO_MACRO_CONFIG2); 411a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, 412a7c30e62SVinod Koul BIT(6), RGMII_IO_MACRO_CONFIG); 413a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 414a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 415b6837619SAndrew Halaney 416b6837619SAndrew Halaney if (ethqos->has_emac3) 417b6837619SAndrew Halaney rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 418b6837619SAndrew Halaney RGMII_CONFIG2_RX_PROG_SWAP, 419b6837619SAndrew Halaney RGMII_IO_MACRO_CONFIG2); 420b6837619SAndrew Halaney else 421a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 422a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 423b6837619SAndrew Halaney 424a7c30e62SVinod Koul /* Write 0x5 to PRG_RCLK_DLY_CODE */ 425a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, 426a7c30e62SVinod Koul (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); 427a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 428a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 429a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 430a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 431a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 432a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 433a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 434030f1d59SAndrew Halaney loopback, RGMII_IO_MACRO_CONFIG); 435a7c30e62SVinod Koul break; 436a7c30e62SVinod Koul 437a7c30e62SVinod Koul case SPEED_10: 438a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, 439a7c30e62SVinod Koul RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); 440a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, 441a7c30e62SVinod Koul RGMII_CONFIG_BYPASS_TX_ID_EN, 442a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 443a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, 444a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 445a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, 446a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG); 447a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 448a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 449a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, 450164a9ebeSAndrew Halaney phase_shift, RGMII_IO_MACRO_CONFIG2); 451a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, 452a7c30e62SVinod Koul BIT(12) | GENMASK(9, 8), 453a7c30e62SVinod Koul RGMII_IO_MACRO_CONFIG); 454a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 455a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 456b6837619SAndrew Halaney if (ethqos->has_emac3) 457b6837619SAndrew Halaney rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 458b6837619SAndrew Halaney RGMII_CONFIG2_RX_PROG_SWAP, 459b6837619SAndrew Halaney RGMII_IO_MACRO_CONFIG2); 460b6837619SAndrew Halaney else 461a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, 462a7c30e62SVinod Koul 0, RGMII_IO_MACRO_CONFIG2); 463a7c30e62SVinod Koul /* Write 0x5 to PRG_RCLK_DLY_CODE */ 464a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, 465a7c30e62SVinod Koul (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); 466a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 467a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, 468a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 469a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 470a7c30e62SVinod Koul SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, 471a7c30e62SVinod Koul SDCC_HC_REG_DDR_CONFIG); 472a7c30e62SVinod Koul rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, 473030f1d59SAndrew Halaney loopback, RGMII_IO_MACRO_CONFIG); 474a7c30e62SVinod Koul break; 475a7c30e62SVinod Koul default: 476302555a0SBartosz Golaszewski dev_err(dev, "Invalid speed %d\n", ethqos->speed); 477a7c30e62SVinod Koul return -EINVAL; 478a7c30e62SVinod Koul } 479a7c30e62SVinod Koul 480a7c30e62SVinod Koul return 0; 481a7c30e62SVinod Koul } 482a7c30e62SVinod Koul 483a7c30e62SVinod Koul static int ethqos_configure(struct qcom_ethqos *ethqos) 484a7c30e62SVinod Koul { 485302555a0SBartosz Golaszewski struct device *dev = ðqos->pdev->dev; 486a7c30e62SVinod Koul volatile unsigned int dll_lock; 487a7c30e62SVinod Koul unsigned int i, retry = 1000; 488a7c30e62SVinod Koul 489a7c30e62SVinod Koul /* Reset to POR values and enable clk */ 490a7c30e62SVinod Koul for (i = 0; i < ethqos->num_por; i++) 491a7c30e62SVinod Koul rgmii_writel(ethqos, ethqos->por[i].value, 492a7c30e62SVinod Koul ethqos->por[i].offset); 493a7c30e62SVinod Koul ethqos_set_func_clk_en(ethqos); 494a7c30e62SVinod Koul 495a7c30e62SVinod Koul /* Initialize the DLL first */ 496a7c30e62SVinod Koul 497a7c30e62SVinod Koul /* Set DLL_RST */ 498a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 499a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); 500a7c30e62SVinod Koul 501a7c30e62SVinod Koul /* Set PDN */ 502a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 503a7c30e62SVinod Koul SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); 504a7c30e62SVinod Koul 505b6837619SAndrew Halaney if (ethqos->has_emac3) { 506b6837619SAndrew Halaney if (ethqos->speed == SPEED_1000) { 507b6837619SAndrew Halaney rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL); 508b6837619SAndrew Halaney rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL); 509b6837619SAndrew Halaney rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); 510b6837619SAndrew Halaney } else { 511b6837619SAndrew Halaney rgmii_writel(ethqos, 0x40010800, SDCC_USR_CTL); 512b6837619SAndrew Halaney rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); 513b6837619SAndrew Halaney } 514b6837619SAndrew Halaney } 515b6837619SAndrew Halaney 516a7c30e62SVinod Koul /* Clear DLL_RST */ 517a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, 518a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 519a7c30e62SVinod Koul 520a7c30e62SVinod Koul /* Clear PDN */ 521a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0, 522a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 523a7c30e62SVinod Koul 524a7c30e62SVinod Koul if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { 525a7c30e62SVinod Koul /* Set DLL_EN */ 526a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, 527a7c30e62SVinod Koul SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); 528a7c30e62SVinod Koul 529a7c30e62SVinod Koul /* Set CK_OUT_EN */ 530a7c30e62SVinod Koul rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, 531a7c30e62SVinod Koul SDCC_DLL_CONFIG_CK_OUT_EN, 532a7c30e62SVinod Koul SDCC_HC_REG_DLL_CONFIG); 533a7c30e62SVinod Koul 534a7c30e62SVinod Koul /* Set USR_CTL bit 26 with mask of 3 bits */ 535b6837619SAndrew Halaney if (!ethqos->has_emac3) 536b6837619SAndrew Halaney rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), 537b6837619SAndrew Halaney SDCC_USR_CTL); 538a7c30e62SVinod Koul 539a7c30e62SVinod Koul /* wait for DLL LOCK */ 540a7c30e62SVinod Koul do { 541a7c30e62SVinod Koul mdelay(1); 542a7c30e62SVinod Koul dll_lock = rgmii_readl(ethqos, SDC4_STATUS); 543a7c30e62SVinod Koul if (dll_lock & SDC4_STATUS_DLL_LOCK) 544a7c30e62SVinod Koul break; 5457d10f077SDejin Zheng retry--; 546a7c30e62SVinod Koul } while (retry > 0); 547a7c30e62SVinod Koul if (!retry) 548302555a0SBartosz Golaszewski dev_err(dev, "Timeout while waiting for DLL lock\n"); 549a7c30e62SVinod Koul } 550a7c30e62SVinod Koul 551a7c30e62SVinod Koul if (ethqos->speed == SPEED_1000) 552a7c30e62SVinod Koul ethqos_dll_configure(ethqos); 553a7c30e62SVinod Koul 554a7c30e62SVinod Koul ethqos_rgmii_macro_init(ethqos); 555a7c30e62SVinod Koul 556a7c30e62SVinod Koul return 0; 557a7c30e62SVinod Koul } 558a7c30e62SVinod Koul 559a7c30e62SVinod Koul static void ethqos_fix_mac_speed(void *priv, unsigned int speed) 560a7c30e62SVinod Koul { 561a7c30e62SVinod Koul struct qcom_ethqos *ethqos = priv; 562a7c30e62SVinod Koul 563a7c30e62SVinod Koul ethqos->speed = speed; 564a7c30e62SVinod Koul ethqos_update_rgmii_clk(ethqos, speed); 565a7c30e62SVinod Koul ethqos_configure(ethqos); 566a7c30e62SVinod Koul } 567a7c30e62SVinod Koul 5686c950ca7SBhupesh Sharma static int ethqos_clks_config(void *priv, bool enabled) 5696c950ca7SBhupesh Sharma { 5706c950ca7SBhupesh Sharma struct qcom_ethqos *ethqos = priv; 5716c950ca7SBhupesh Sharma int ret = 0; 5726c950ca7SBhupesh Sharma 5736c950ca7SBhupesh Sharma if (enabled) { 5746c950ca7SBhupesh Sharma ret = clk_prepare_enable(ethqos->rgmii_clk); 5756c950ca7SBhupesh Sharma if (ret) { 5766c950ca7SBhupesh Sharma dev_err(ðqos->pdev->dev, "rgmii_clk enable failed\n"); 5776c950ca7SBhupesh Sharma return ret; 5786c950ca7SBhupesh Sharma } 579ffba2123SBjorn Andersson 580ffba2123SBjorn Andersson /* Enable functional clock to prevent DMA reset to timeout due 581ffba2123SBjorn Andersson * to lacking PHY clock after the hardware block has been power 582ffba2123SBjorn Andersson * cycled. The actual configuration will be adjusted once 583ffba2123SBjorn Andersson * ethqos_fix_mac_speed() is invoked. 584ffba2123SBjorn Andersson */ 585ffba2123SBjorn Andersson ethqos_set_func_clk_en(ethqos); 5866c950ca7SBhupesh Sharma } else { 5876c950ca7SBhupesh Sharma clk_disable_unprepare(ethqos->rgmii_clk); 5886c950ca7SBhupesh Sharma } 5896c950ca7SBhupesh Sharma 5906c950ca7SBhupesh Sharma return ret; 5916c950ca7SBhupesh Sharma } 5926c950ca7SBhupesh Sharma 5939fc68f23SBartosz Golaszewski static void ethqos_clks_disable(void *data) 5949fc68f23SBartosz Golaszewski { 5959fc68f23SBartosz Golaszewski ethqos_clks_config(data, false); 5969fc68f23SBartosz Golaszewski } 5979fc68f23SBartosz Golaszewski 598a7c30e62SVinod Koul static int qcom_ethqos_probe(struct platform_device *pdev) 599a7c30e62SVinod Koul { 600a7c30e62SVinod Koul struct device_node *np = pdev->dev.of_node; 6017b5e64a9SBartosz Golaszewski const struct ethqos_emac_driver_data *data; 602a7c30e62SVinod Koul struct plat_stmmacenet_data *plat_dat; 603a7c30e62SVinod Koul struct stmmac_resources stmmac_res; 604302555a0SBartosz Golaszewski struct device *dev = &pdev->dev; 605a7c30e62SVinod Koul struct qcom_ethqos *ethqos; 606a7c30e62SVinod Koul int ret; 607a7c30e62SVinod Koul 608a7c30e62SVinod Koul ret = stmmac_get_platform_resources(pdev, &stmmac_res); 609a7c30e62SVinod Koul if (ret) 610a7c30e62SVinod Koul return ret; 611a7c30e62SVinod Koul 61283216e39SMichael Walle plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 613a7c30e62SVinod Koul if (IS_ERR(plat_dat)) { 614302555a0SBartosz Golaszewski dev_err(dev, "dt configuration failed\n"); 615a7c30e62SVinod Koul return PTR_ERR(plat_dat); 616a7c30e62SVinod Koul } 617a7c30e62SVinod Koul 6186c950ca7SBhupesh Sharma plat_dat->clks_config = ethqos_clks_config; 6196c950ca7SBhupesh Sharma 620302555a0SBartosz Golaszewski ethqos = devm_kzalloc(dev, sizeof(*ethqos), GFP_KERNEL); 621a7c30e62SVinod Koul if (!ethqos) { 622a7c30e62SVinod Koul ret = -ENOMEM; 6239bc58060SBartosz Golaszewski goto out_config_dt; 624a7c30e62SVinod Koul } 625a7c30e62SVinod Koul 626a7c30e62SVinod Koul ethqos->pdev = pdev; 6273a5a32b5SYang Yingliang ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); 628a7c30e62SVinod Koul if (IS_ERR(ethqos->rgmii_base)) { 629a7c30e62SVinod Koul ret = PTR_ERR(ethqos->rgmii_base); 6309bc58060SBartosz Golaszewski goto out_config_dt; 631a7c30e62SVinod Koul } 632a7c30e62SVinod Koul 633302555a0SBartosz Golaszewski data = of_device_get_match_data(dev); 634fd4a5177SVinod Koul ethqos->por = data->por; 635fd4a5177SVinod Koul ethqos->num_por = data->num_por; 636030f1d59SAndrew Halaney ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; 637b6837619SAndrew Halaney ethqos->has_emac3 = data->has_emac3; 638a7c30e62SVinod Koul 639302555a0SBartosz Golaszewski ethqos->rgmii_clk = devm_clk_get(dev, "rgmii"); 6408f4ebaaaSWei Yongjun if (IS_ERR(ethqos->rgmii_clk)) { 6418f4ebaaaSWei Yongjun ret = PTR_ERR(ethqos->rgmii_clk); 6429bc58060SBartosz Golaszewski goto out_config_dt; 643a7c30e62SVinod Koul } 644a7c30e62SVinod Koul 6456c950ca7SBhupesh Sharma ret = ethqos_clks_config(ethqos, true); 646a7c30e62SVinod Koul if (ret) 6479bc58060SBartosz Golaszewski goto out_config_dt; 648a7c30e62SVinod Koul 649302555a0SBartosz Golaszewski ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos); 6509fc68f23SBartosz Golaszewski if (ret) 6519bc58060SBartosz Golaszewski goto out_config_dt; 6529fc68f23SBartosz Golaszewski 653a7c30e62SVinod Koul ethqos->speed = SPEED_1000; 654a7c30e62SVinod Koul ethqos_update_rgmii_clk(ethqos, SPEED_1000); 655a7c30e62SVinod Koul ethqos_set_func_clk_en(ethqos); 656a7c30e62SVinod Koul 657a7c30e62SVinod Koul plat_dat->bsp_priv = ethqos; 658a7c30e62SVinod Koul plat_dat->fix_mac_speed = ethqos_fix_mac_speed; 6594047b9dbSBhupesh Sharma plat_dat->dump_debug_regs = rgmii_dump; 660a7c30e62SVinod Koul plat_dat->has_gmac4 = 1; 6619bc00973SBartosz Golaszewski if (ethqos->has_emac3) 662b6837619SAndrew Halaney plat_dat->dwmac4_addrs = &data->dwmac4_addrs; 663a7c30e62SVinod Koul plat_dat->pmt = 1; 664a7c30e62SVinod Koul plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); 66554aa39a5SAndrey Konovalov if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) 66654aa39a5SAndrey Konovalov plat_dat->rx_clk_runs_in_lpi = 1; 667a7c30e62SVinod Koul 668302555a0SBartosz Golaszewski ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res); 669a7c30e62SVinod Koul if (ret) 6709bc58060SBartosz Golaszewski goto out_config_dt; 671a7c30e62SVinod Koul 672a7c30e62SVinod Koul return ret; 673a7c30e62SVinod Koul 6749bc58060SBartosz Golaszewski out_config_dt: 675a7c30e62SVinod Koul stmmac_remove_config_dt(pdev, plat_dat); 676a7c30e62SVinod Koul 677a7c30e62SVinod Koul return ret; 678a7c30e62SVinod Koul } 679a7c30e62SVinod Koul 680a7c30e62SVinod Koul static const struct of_device_id qcom_ethqos_match[] = { 681fd4a5177SVinod Koul { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, 682b6837619SAndrew Halaney { .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data}, 683d90b3120SVinod Koul { .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data}, 684a7c30e62SVinod Koul { } 685a7c30e62SVinod Koul }; 686a7c30e62SVinod Koul MODULE_DEVICE_TABLE(of, qcom_ethqos_match); 687a7c30e62SVinod Koul 688a7c30e62SVinod Koul static struct platform_driver qcom_ethqos_driver = { 689a7c30e62SVinod Koul .probe = qcom_ethqos_probe, 6909fc68f23SBartosz Golaszewski .remove_new = stmmac_pltfr_remove, 691a7c30e62SVinod Koul .driver = { 692a7c30e62SVinod Koul .name = "qcom-ethqos", 693a7c30e62SVinod Koul .pm = &stmmac_pltfr_pm_ops, 694dc54e450SKrzysztof Kozlowski .of_match_table = qcom_ethqos_match, 695a7c30e62SVinod Koul }, 696a7c30e62SVinod Koul }; 697a7c30e62SVinod Koul module_platform_driver(qcom_ethqos_driver); 698a7c30e62SVinod Koul 699a7c30e62SVinod Koul MODULE_DESCRIPTION("Qualcomm ETHQOS driver"); 700a7c30e62SVinod Koul MODULE_LICENSE("GPL v2"); 701