1*010fe5dfSDaniel Machon // SPDX-License-Identifier: GPL-2.0+ 2*010fe5dfSDaniel Machon /* Microchip lan969x Switch driver 3*010fe5dfSDaniel Machon * 4*010fe5dfSDaniel Machon * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. 5*010fe5dfSDaniel Machon */ 6*010fe5dfSDaniel Machon 7*010fe5dfSDaniel Machon #include "lan969x.h" 8*010fe5dfSDaniel Machon 9*010fe5dfSDaniel Machon /* Tx clock selectors */ 10*010fe5dfSDaniel Machon #define LAN969X_RGMII_TX_CLK_SEL_125MHZ 1 /* 1000Mbps */ 11*010fe5dfSDaniel Machon #define LAN969X_RGMII_TX_CLK_SEL_25MHZ 2 /* 100Mbps */ 12*010fe5dfSDaniel Machon #define LAN969X_RGMII_TX_CLK_SEL_2M5MHZ 3 /* 10Mbps */ 13*010fe5dfSDaniel Machon 14*010fe5dfSDaniel Machon /* Port speed selectors */ 15*010fe5dfSDaniel Machon #define LAN969X_RGMII_SPEED_SEL_10 0 /* Select 10Mbps speed */ 16*010fe5dfSDaniel Machon #define LAN969X_RGMII_SPEED_SEL_100 1 /* Select 100Mbps speed */ 17*010fe5dfSDaniel Machon #define LAN969X_RGMII_SPEED_SEL_1000 2 /* Select 1000Mbps speed */ 18*010fe5dfSDaniel Machon 19*010fe5dfSDaniel Machon /* Clock delay selectors */ 20*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_1_0_NS 2 /* Phase shift 45deg */ 21*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_1_7_NS 3 /* Phase shift 77deg */ 22*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_2_0_NS 4 /* Phase shift 90deg */ 23*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS 5 /* Phase shift 112deg */ 24*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_3_0_NS 6 /* Phase shift 135deg */ 25*010fe5dfSDaniel Machon #define LAN969X_RGMII_CLK_DELAY_SEL_3_3_NS 7 /* Phase shift 147deg */ 26*010fe5dfSDaniel Machon 27*010fe5dfSDaniel Machon #define LAN969X_RGMII_PORT_START_IDX 28 /* Index of the first RGMII port */ 28*010fe5dfSDaniel Machon #define LAN969X_RGMII_IFG_TX 4 /* TX Inter Frame Gap value */ 29*010fe5dfSDaniel Machon #define LAN969X_RGMII_IFG_RX1 5 /* RX1 Inter Frame Gap value */ 30*010fe5dfSDaniel Machon #define LAN969X_RGMII_IFG_RX2 1 /* RX2 Inter Frame Gap value */ 31*010fe5dfSDaniel Machon 32*010fe5dfSDaniel Machon #define RGMII_PORT_IDX(port) ((port)->portno - LAN969X_RGMII_PORT_START_IDX) 33*010fe5dfSDaniel Machon 34*010fe5dfSDaniel Machon /* Get the tx clock selector based on the port speed. */ 35*010fe5dfSDaniel Machon static int lan969x_rgmii_get_clk_sel(int speed) 36*010fe5dfSDaniel Machon { 37*010fe5dfSDaniel Machon return (speed == SPEED_10 ? LAN969X_RGMII_TX_CLK_SEL_2M5MHZ : 38*010fe5dfSDaniel Machon speed == SPEED_100 ? LAN969X_RGMII_TX_CLK_SEL_25MHZ : 39*010fe5dfSDaniel Machon LAN969X_RGMII_TX_CLK_SEL_125MHZ); 40*010fe5dfSDaniel Machon } 41*010fe5dfSDaniel Machon 42*010fe5dfSDaniel Machon /* Get the port speed selector based on the port speed. */ 43*010fe5dfSDaniel Machon static int lan969x_rgmii_get_speed_sel(int speed) 44*010fe5dfSDaniel Machon { 45*010fe5dfSDaniel Machon return (speed == SPEED_10 ? LAN969X_RGMII_SPEED_SEL_10 : 46*010fe5dfSDaniel Machon speed == SPEED_100 ? LAN969X_RGMII_SPEED_SEL_100 : 47*010fe5dfSDaniel Machon LAN969X_RGMII_SPEED_SEL_1000); 48*010fe5dfSDaniel Machon } 49*010fe5dfSDaniel Machon 50*010fe5dfSDaniel Machon /* Get the clock delay selector based on the clock delay in picoseconds. */ 51*010fe5dfSDaniel Machon static int lan969x_rgmii_get_clk_delay_sel(struct sparx5_port *port, 52*010fe5dfSDaniel Machon u32 delay_ps, u32 *clk_delay_sel) 53*010fe5dfSDaniel Machon { 54*010fe5dfSDaniel Machon switch (delay_ps) { 55*010fe5dfSDaniel Machon case 0: 56*010fe5dfSDaniel Machon /* Hardware default selector. */ 57*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS; 58*010fe5dfSDaniel Machon break; 59*010fe5dfSDaniel Machon case 1000: 60*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_1_0_NS; 61*010fe5dfSDaniel Machon break; 62*010fe5dfSDaniel Machon case 1700: 63*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_1_7_NS; 64*010fe5dfSDaniel Machon break; 65*010fe5dfSDaniel Machon case 2000: 66*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_0_NS; 67*010fe5dfSDaniel Machon break; 68*010fe5dfSDaniel Machon case 2500: 69*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS; 70*010fe5dfSDaniel Machon break; 71*010fe5dfSDaniel Machon case 3000: 72*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_3_0_NS; 73*010fe5dfSDaniel Machon break; 74*010fe5dfSDaniel Machon case 3300: 75*010fe5dfSDaniel Machon *clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_3_3_NS; 76*010fe5dfSDaniel Machon break; 77*010fe5dfSDaniel Machon default: 78*010fe5dfSDaniel Machon dev_err(port->sparx5->dev, "Invalid RGMII delay: %u", delay_ps); 79*010fe5dfSDaniel Machon return -EINVAL; 80*010fe5dfSDaniel Machon } 81*010fe5dfSDaniel Machon 82*010fe5dfSDaniel Machon return 0; 83*010fe5dfSDaniel Machon } 84*010fe5dfSDaniel Machon 85*010fe5dfSDaniel Machon /* Configure the RGMII tx clock frequency. */ 86*010fe5dfSDaniel Machon static void lan969x_rgmii_tx_clk_config(struct sparx5_port *port, 87*010fe5dfSDaniel Machon struct sparx5_port_config *conf) 88*010fe5dfSDaniel Machon { 89*010fe5dfSDaniel Machon u32 clk_sel = lan969x_rgmii_get_clk_sel(conf->speed); 90*010fe5dfSDaniel Machon u32 idx = RGMII_PORT_IDX(port); 91*010fe5dfSDaniel Machon 92*010fe5dfSDaniel Machon /* Take the RGMII clock domain out of reset and set tx clock 93*010fe5dfSDaniel Machon * frequency. 94*010fe5dfSDaniel Machon */ 95*010fe5dfSDaniel Machon spx5_rmw(HSIO_WRAP_RGMII_CFG_TX_CLK_CFG_SET(clk_sel) | 96*010fe5dfSDaniel Machon HSIO_WRAP_RGMII_CFG_RGMII_TX_RST_SET(0) | 97*010fe5dfSDaniel Machon HSIO_WRAP_RGMII_CFG_RGMII_RX_RST_SET(0), 98*010fe5dfSDaniel Machon HSIO_WRAP_RGMII_CFG_TX_CLK_CFG | 99*010fe5dfSDaniel Machon HSIO_WRAP_RGMII_CFG_RGMII_TX_RST | 100*010fe5dfSDaniel Machon HSIO_WRAP_RGMII_CFG_RGMII_RX_RST, 101*010fe5dfSDaniel Machon port->sparx5, HSIO_WRAP_RGMII_CFG(idx)); 102*010fe5dfSDaniel Machon } 103*010fe5dfSDaniel Machon 104*010fe5dfSDaniel Machon /* Configure the RGMII port device. */ 105*010fe5dfSDaniel Machon static void lan969x_rgmii_port_device_config(struct sparx5_port *port, 106*010fe5dfSDaniel Machon struct sparx5_port_config *conf) 107*010fe5dfSDaniel Machon { 108*010fe5dfSDaniel Machon u32 dtag, dotag, etype, speed_sel, idx = RGMII_PORT_IDX(port); 109*010fe5dfSDaniel Machon 110*010fe5dfSDaniel Machon speed_sel = lan969x_rgmii_get_speed_sel(conf->speed); 111*010fe5dfSDaniel Machon 112*010fe5dfSDaniel Machon etype = (port->vlan_type == SPX5_VLAN_PORT_TYPE_S_CUSTOM ? 113*010fe5dfSDaniel Machon port->custom_etype : 114*010fe5dfSDaniel Machon port->vlan_type == SPX5_VLAN_PORT_TYPE_C ? 115*010fe5dfSDaniel Machon ETH_P_8021Q : ETH_P_8021AD); 116*010fe5dfSDaniel Machon 117*010fe5dfSDaniel Machon dtag = port->max_vlan_tags == SPX5_PORT_MAX_TAGS_TWO; 118*010fe5dfSDaniel Machon dotag = port->max_vlan_tags != SPX5_PORT_MAX_TAGS_NONE; 119*010fe5dfSDaniel Machon 120*010fe5dfSDaniel Machon /* Enable the MAC. */ 121*010fe5dfSDaniel Machon spx5_wr(DEVRGMII_MAC_ENA_CFG_RX_ENA_SET(1) | 122*010fe5dfSDaniel Machon DEVRGMII_MAC_ENA_CFG_TX_ENA_SET(1), 123*010fe5dfSDaniel Machon port->sparx5, DEVRGMII_MAC_ENA_CFG(idx)); 124*010fe5dfSDaniel Machon 125*010fe5dfSDaniel Machon /* Configure the Inter Frame Gap. */ 126*010fe5dfSDaniel Machon spx5_wr(DEVRGMII_MAC_IFG_CFG_TX_IFG_SET(LAN969X_RGMII_IFG_TX) | 127*010fe5dfSDaniel Machon DEVRGMII_MAC_IFG_CFG_RX_IFG1_SET(LAN969X_RGMII_IFG_RX1) | 128*010fe5dfSDaniel Machon DEVRGMII_MAC_IFG_CFG_RX_IFG2_SET(LAN969X_RGMII_IFG_RX2), 129*010fe5dfSDaniel Machon port->sparx5, DEVRGMII_MAC_IFG_CFG(idx)); 130*010fe5dfSDaniel Machon 131*010fe5dfSDaniel Machon /* Configure port data rate. */ 132*010fe5dfSDaniel Machon spx5_wr(DEVRGMII_DEV_RST_CTRL_SPEED_SEL_SET(speed_sel), 133*010fe5dfSDaniel Machon port->sparx5, DEVRGMII_DEV_RST_CTRL(idx)); 134*010fe5dfSDaniel Machon 135*010fe5dfSDaniel Machon /* Configure VLAN awareness. */ 136*010fe5dfSDaniel Machon spx5_wr(DEVRGMII_MAC_TAGS_CFG_TAG_ID_SET(etype) | 137*010fe5dfSDaniel Machon DEVRGMII_MAC_TAGS_CFG_PB_ENA_SET(dtag) | 138*010fe5dfSDaniel Machon DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(dotag) | 139*010fe5dfSDaniel Machon DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(dotag), 140*010fe5dfSDaniel Machon port->sparx5, 141*010fe5dfSDaniel Machon DEVRGMII_MAC_TAGS_CFG(idx)); 142*010fe5dfSDaniel Machon } 143*010fe5dfSDaniel Machon 144*010fe5dfSDaniel Machon /* Configure the RGMII delay lines in the MAC. 145*010fe5dfSDaniel Machon * 146*010fe5dfSDaniel Machon * We use the rx-internal-delay-ps" and "tx-internal-delay-ps" properties to 147*010fe5dfSDaniel Machon * configure the rx and tx delays for the MAC. If these properties are missing 148*010fe5dfSDaniel Machon * or set to zero, the MAC will not apply any delay. 149*010fe5dfSDaniel Machon * 150*010fe5dfSDaniel Machon * The PHY side delays are determined by the PHY mode 151*010fe5dfSDaniel Machon * (e.g. PHY_INTERFACE_MODE_RGMII_{ID, RXID, TXID}), and ignored by the MAC side 152*010fe5dfSDaniel Machon * entirely. 153*010fe5dfSDaniel Machon */ 154*010fe5dfSDaniel Machon static int lan969x_rgmii_delay_config(struct sparx5_port *port, 155*010fe5dfSDaniel Machon struct sparx5_port_config *conf) 156*010fe5dfSDaniel Machon { 157*010fe5dfSDaniel Machon u32 tx_clk_sel, rx_clk_sel, tx_delay_ps = 0, rx_delay_ps = 0; 158*010fe5dfSDaniel Machon u32 idx = RGMII_PORT_IDX(port); 159*010fe5dfSDaniel Machon int err; 160*010fe5dfSDaniel Machon 161*010fe5dfSDaniel Machon of_property_read_u32(port->of_node, "rx-internal-delay-ps", 162*010fe5dfSDaniel Machon &rx_delay_ps); 163*010fe5dfSDaniel Machon 164*010fe5dfSDaniel Machon of_property_read_u32(port->of_node, "tx-internal-delay-ps", 165*010fe5dfSDaniel Machon &tx_delay_ps); 166*010fe5dfSDaniel Machon 167*010fe5dfSDaniel Machon err = lan969x_rgmii_get_clk_delay_sel(port, rx_delay_ps, &rx_clk_sel); 168*010fe5dfSDaniel Machon if (err) 169*010fe5dfSDaniel Machon return err; 170*010fe5dfSDaniel Machon 171*010fe5dfSDaniel Machon err = lan969x_rgmii_get_clk_delay_sel(port, tx_delay_ps, &tx_clk_sel); 172*010fe5dfSDaniel Machon if (err) 173*010fe5dfSDaniel Machon return err; 174*010fe5dfSDaniel Machon 175*010fe5dfSDaniel Machon /* Configure rx delay. */ 176*010fe5dfSDaniel Machon spx5_rmw(HSIO_WRAP_DLL_CFG_DLL_RST_SET(0) | 177*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_ENA_SET(1) | 178*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_SET(!!rx_delay_ps) | 179*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_SET(rx_clk_sel), 180*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_RST | 181*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_ENA | 182*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_ENA | 183*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_SEL, 184*010fe5dfSDaniel Machon port->sparx5, HSIO_WRAP_DLL_CFG(idx, 0)); 185*010fe5dfSDaniel Machon 186*010fe5dfSDaniel Machon /* Configure tx delay. */ 187*010fe5dfSDaniel Machon spx5_rmw(HSIO_WRAP_DLL_CFG_DLL_RST_SET(0) | 188*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_ENA_SET(1) | 189*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_SET(!!tx_delay_ps) | 190*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_SET(tx_clk_sel), 191*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_RST | 192*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_ENA | 193*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_ENA | 194*010fe5dfSDaniel Machon HSIO_WRAP_DLL_CFG_DLL_CLK_SEL, 195*010fe5dfSDaniel Machon port->sparx5, HSIO_WRAP_DLL_CFG(idx, 1)); 196*010fe5dfSDaniel Machon 197*010fe5dfSDaniel Machon return 0; 198*010fe5dfSDaniel Machon } 199*010fe5dfSDaniel Machon 200*010fe5dfSDaniel Machon /* Configure GPIO's to be used as RGMII interface. */ 201*010fe5dfSDaniel Machon static void lan969x_rgmii_gpio_config(struct sparx5_port *port) 202*010fe5dfSDaniel Machon { 203*010fe5dfSDaniel Machon u32 idx = RGMII_PORT_IDX(port); 204*010fe5dfSDaniel Machon 205*010fe5dfSDaniel Machon /* Enable the RGMII on the GPIOs. */ 206*010fe5dfSDaniel Machon spx5_wr(HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG_SET(1), port->sparx5, 207*010fe5dfSDaniel Machon HSIO_WRAP_XMII_CFG(!idx)); 208*010fe5dfSDaniel Machon } 209*010fe5dfSDaniel Machon 210*010fe5dfSDaniel Machon int lan969x_port_config_rgmii(struct sparx5_port *port, 211*010fe5dfSDaniel Machon struct sparx5_port_config *conf) 212*010fe5dfSDaniel Machon { 213*010fe5dfSDaniel Machon int err; 214*010fe5dfSDaniel Machon 215*010fe5dfSDaniel Machon err = lan969x_rgmii_delay_config(port, conf); 216*010fe5dfSDaniel Machon if (err) 217*010fe5dfSDaniel Machon return err; 218*010fe5dfSDaniel Machon 219*010fe5dfSDaniel Machon lan969x_rgmii_tx_clk_config(port, conf); 220*010fe5dfSDaniel Machon lan969x_rgmii_gpio_config(port); 221*010fe5dfSDaniel Machon lan969x_rgmii_port_device_config(port, conf); 222*010fe5dfSDaniel Machon 223*010fe5dfSDaniel Machon return 0; 224*010fe5dfSDaniel Machon } 225