1 // SPDX-License-Identifier: GPL-2.0+ 2 /** 3 * 4 * Driver for ROCKCHIP RK630 Ethernet PHYs 5 * 6 * Copyright (c) 2020, Fuzhou Rockchip Electronics Co., Ltd 7 * 8 * David Wu <david.wu@rock-chips.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 */ 16 17 #include <config.h> 18 #include <common.h> 19 #include <misc.h> 20 #include <phy.h> 21 22 #define RK630_PHY_ID 0x00441400 23 24 /* PAGE 0 */ 25 #define REG_MMD_ACCESS_CONTROL 0x0d 26 #define REG_MMD_ACCESS_DATA_ADDRESS 0x0e 27 #define REG_INTERRUPT_STATUS 0X10 28 #define REG_INTERRUPT_MASK 0X11 29 #define REG_GLOBAL_CONFIGURATION 0X13 30 #define REG_MAC_ADDRESS0 0x16 31 #define REG_MAC_ADDRESS1 0x17 32 #define REG_MAC_ADDRESS2 0x18 33 34 #define REG_PAGE_SEL 0x1F 35 36 /* PAGE 1 */ 37 #define REG_PAGE1_APS_CTRL 0x12 38 #define REG_PAGE1_UAPS_CONFIGURE 0X13 39 #define REG_PAGE1_EEE_CONFIGURE 0x17 40 41 /* PAGE 2 */ 42 #define REG_PAGE2_AFE_CTRL 0x18 43 44 /* PAGE 6 */ 45 #define REG_PAGE6_ADC_ANONTROL 0x10 46 #define REG_PAGE6_GAIN_ANONTROL 0x12 47 #define REG_PAGE6_AFE_RX_CTRL 0x13 48 #define REG_PAGE6_AFE_TX_CTRL 0x14 49 #define REG_PAGE6_AFE_DRIVER2 0x15 50 #define REG_PAGE6_CP_CURRENT 0x17 51 #define REG_PAGE6_ADC_OP_BIAS 0x18 52 #define REG_PAGE6_RX_DECTOR 0x19 53 #define REG_PAGE6_TX_MOS_DRV 0x1B 54 #define REG_PAGE6_AFE_PDCW 0x1c 55 56 /* PAGE 8 */ 57 #define REG_PAGE8_AFE_CTRL 0x18 58 #define REG_PAGE8_AUTO_CAL 0x1d 59 60 /* 61 * Fixed address: 62 * Addr: 1 --- RK630@S40 63 * 2 --- RV1106@T22 64 */ 65 #define PHY_ADDR_S40 1 66 #define PHY_ADDR_T22 2 67 68 #define T22_TX_LEVEL_100M 0x2d 69 #define T22_TX_LEVEL_10M 0x32 70 71 static int rk630_phy_t22_get_txlevel_from_efuse(unsigned char *txlevel_100, 72 unsigned char *txlevel_10) 73 { 74 #if defined(CONFIG_ROCKCHIP_EFUSE) || defined(CONFIG_ROCKCHIP_OTP) 75 unsigned char tx_level[2]; 76 struct udevice *dev; 77 u32 regs[2] = {0}; 78 ofnode node; 79 int ret; 80 81 /* retrieve the device */ 82 if (IS_ENABLED(CONFIG_ROCKCHIP_EFUSE)) 83 ret = uclass_get_device_by_driver(UCLASS_MISC, 84 DM_GET_DRIVER(rockchip_efuse), 85 &dev); 86 else 87 ret = uclass_get_device_by_driver(UCLASS_MISC, 88 DM_GET_DRIVER(rockchip_otp), 89 &dev); 90 91 if (ret) { 92 printf("%s: could not find efuse/otp device\n", __func__); 93 return ret; 94 } 95 96 node = dev_read_subnode(dev, "macphy-txlevel"); 97 if (!ofnode_valid(node)) 98 return -EINVAL; 99 100 ret = ofnode_read_u32_array(node, "reg", regs, 2); 101 if (ret) { 102 printf("Cannot get efuse reg\n"); 103 return -EINVAL; 104 } 105 106 /* read the txlevel from the efuses */ 107 ret = misc_read(dev, regs[0], &tx_level, 2); 108 if (ret) { 109 printf("%s: read txlevel from efuse/otp failed, ret=%d\n", 110 __func__, ret); 111 return ret; 112 } 113 *txlevel_100 = tx_level[1]; 114 *txlevel_10 = tx_level[0]; 115 116 return 0; 117 #else 118 return -EINVAL; 119 #endif 120 } 121 122 static int rk630_phy_startup(struct phy_device *phydev) 123 { 124 int ret; 125 126 /* Read the Status (2x to make sure link is right) */ 127 ret = genphy_update_link(phydev); 128 if (ret) 129 return ret; 130 131 /* Read the Status (2x to make sure link is right) */ 132 phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 133 134 return genphy_parse_link(phydev); 135 } 136 137 static void rk630_phy_s40_config_init(struct phy_device *phydev) 138 { 139 phy_write(phydev, 0, MDIO_DEVAD_NONE, 140 phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13)); 141 142 /* Switch to page 1 */ 143 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 144 /* Disable APS */ 145 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 146 /* Switch to page 2 */ 147 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 148 /* PHYAFE TRX optimization */ 149 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 150 /* Switch to page 6 */ 151 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 152 /* PHYAFE TX optimization */ 153 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f); 154 /* PHYAFE RX optimization */ 155 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000); 156 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530); 157 158 /* Switch to page 8 */ 159 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 160 /* PHYAFE TRX optimization */ 161 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc); 162 163 /* Switch to page 0 */ 164 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 165 } 166 167 static void rk630_phy_t22_config_init(struct phy_device *phydev) 168 { 169 unsigned char tx_level_100M = T22_TX_LEVEL_100M; 170 unsigned char tx_level_10M = T22_TX_LEVEL_10M; 171 172 /* Switch to page 1 */ 173 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 174 /* Disable APS */ 175 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 176 /* Switch to page 2 */ 177 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 178 /* PHYAFE TRX optimization */ 179 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 180 /* Switch to page 6 */ 181 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 182 /* PHYAFE ADC optimization */ 183 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, 0x5540); 184 /* PHYAFE Gain optimization */ 185 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_GAIN_ANONTROL, 0x0400); 186 /* PHYAFE EQ optimization */ 187 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x1088); 188 189 if (rk630_phy_t22_get_txlevel_from_efuse(&tx_level_100M, &tx_level_10M)) { 190 tx_level_100M = T22_TX_LEVEL_100M; 191 tx_level_10M = T22_TX_LEVEL_10M; 192 } 193 /* PHYAFE TX optimization */ 194 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 195 (tx_level_100M << 8) | tx_level_10M); 196 197 /* PHYAFE CP current optimization */ 198 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_CP_CURRENT, 0x0575); 199 /* ADC OP BIAS optimization */ 200 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_OP_BIAS, 0x0000); 201 /* Rx signal detctor level optimization */ 202 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_RX_DECTOR, 0x0408); 203 /* PHYAFE PDCW optimization */ 204 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_PDCW, 0x8880); 205 /* Add PHY Tx mos drive, reduce power noise/jitter */ 206 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_TX_MOS_DRV, 0x888e); 207 208 /* Switch to page 8 */ 209 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 210 /* Disable auto-cal */ 211 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AUTO_CAL, 0x0844); 212 213 /* Switch to page 0 */ 214 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 215 216 /* Disable eee mode advertised */ 217 phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x0007); 218 phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x003c); 219 phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x4007); 220 phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x0000); 221 } 222 static int rk630_phy_config_init(struct phy_device *phydev) 223 { 224 switch (phydev->addr) { 225 case PHY_ADDR_S40: 226 rk630_phy_s40_config_init(phydev); 227 break; 228 case PHY_ADDR_T22: 229 rk630_phy_t22_config_init(phydev); 230 break; 231 default: 232 printf("Unsupported address for current phy: %d\n", 233 phydev->addr); 234 return -EINVAL; 235 } 236 237 genphy_config_aneg(phydev); 238 return 0; 239 } 240 241 static struct phy_driver RK630_driver = { 242 .name = "Rockchip RK630", 243 .uid = RK630_PHY_ID, 244 .mask = 0xffffff, 245 .features = PHY_BASIC_FEATURES, 246 .config = &rk630_phy_config_init, 247 .startup = &rk630_phy_startup, 248 }; 249 250 int phy_rk630_init(void) 251 { 252 phy_register(&RK630_driver); 253 return 0; 254 } 255