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 <phy.h> 20 21 #define RK630_PHY_ID 0x00441400 22 23 /* PAGE 0 */ 24 #define REG_INTERRUPT_STATUS 0X10 25 #define REG_INTERRUPT_MASK 0X11 26 #define REG_GLOBAL_CONFIGURATION 0X13 27 #define REG_MAC_ADDRESS0 0x16 28 #define REG_MAC_ADDRESS1 0x17 29 #define REG_MAC_ADDRESS2 0x18 30 31 #define REG_PAGE_SEL 0x1F 32 33 /* PAGE 1 */ 34 #define REG_PAGE1_APS_CTRL 0x12 35 #define REG_PAGE1_UAPS_CONFIGURE 0X13 36 #define REG_PAGE1_EEE_CONFIGURE 0x17 37 38 /* PAGE 2 */ 39 #define REG_PAGE2_AFE_CTRL 0x18 40 41 /* PAGE 6 */ 42 #define REG_PAGE6_ADC_ANONTROL 0x10 43 #define REG_PAGE6_GAIN_ANONTROL 0x12 44 #define REG_PAGE6_AFE_RX_CTRL 0x13 45 #define REG_PAGE6_AFE_TX_CTRL 0x14 46 #define REG_PAGE6_AFE_DRIVER2 0x15 47 #define REG_PAGE6_CP_CURRENT 0x17 48 #define REG_PAGE6_ADC_OP_BIAS 0x18 49 #define REG_PAGE6_RX_DECTOR 0x19 50 #define REG_PAGE6_AFE_PDCW 0x1c 51 52 /* PAGE 8 */ 53 #define REG_PAGE8_AFE_CTRL 0x18 54 #define REG_PAGE8_AUTO_CAL 0x1d 55 56 /* 57 * Fixed address: 58 * Addr: 1 --- RK630@S40 59 * 2 --- RV1106@T22 60 */ 61 #define PHY_ADDR_S40 1 62 #define PHY_ADDR_T22 2 63 64 static int rk630_phy_startup(struct phy_device *phydev) 65 { 66 int ret; 67 68 /* Read the Status (2x to make sure link is right) */ 69 ret = genphy_update_link(phydev); 70 if (ret) 71 return ret; 72 /* Read the Status (2x to make sure link is right) */ 73 phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 74 75 return genphy_parse_link(phydev); 76 } 77 78 static void rk630_phy_ieee_set(struct phy_device *phydev, bool enable) 79 { 80 u32 value; 81 82 /* Switch to page 1 */ 83 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 84 value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE1_EEE_CONFIGURE); 85 if (enable) 86 value |= BIT(3); 87 else 88 value &= ~BIT(3); 89 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_EEE_CONFIGURE, value); 90 /* Switch to page 0 */ 91 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 92 } 93 94 static void rk630_phy_set_uaps(struct phy_device *phydev) 95 { 96 u32 value; 97 98 /* Switch to page 1 */ 99 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 100 value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE1_UAPS_CONFIGURE); 101 value |= BIT(15); 102 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_UAPS_CONFIGURE, value); 103 /* Switch to page 0 */ 104 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 105 } 106 107 static void rk630_phy_s40_config_init(struct phy_device *phydev) 108 { 109 phy_write(phydev, 0, MDIO_DEVAD_NONE, 110 phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13)); 111 112 /* Switch to page 1 */ 113 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 114 /* Disable APS */ 115 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 116 /* Switch to page 2 */ 117 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 118 /* PHYAFE TRX optimization */ 119 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 120 /* Switch to page 6 */ 121 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 122 /* PHYAFE TX optimization */ 123 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f); 124 /* PHYAFE RX optimization */ 125 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000); 126 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530); 127 128 /* Switch to page 8 */ 129 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 130 /* PHYAFE TRX optimization */ 131 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc); 132 133 /* Switch to page 0 */ 134 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 135 } 136 137 static void rk630_phy_t22_config_init(struct phy_device *phydev) 138 { 139 /* Switch to page 1 */ 140 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 141 /* Disable APS */ 142 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 143 /* Switch to page 2 */ 144 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 145 /* PHYAFE TRX optimization */ 146 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 147 /* Switch to page 6 */ 148 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 149 /* PHYAFE ADC optimization */ 150 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, 0x5540); 151 /* PHYAFE Gain optimization */ 152 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_GAIN_ANONTROL, 0x0400); 153 /* PHYAFE EQ optimization */ 154 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x1088); 155 /* PHYAFE TX optimization */ 156 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x3030); 157 /* PHYAFE CP current optimization */ 158 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_CP_CURRENT, 0x0575); 159 /* ADC OP BIAS optimization */ 160 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_OP_BIAS, 0x0000); 161 /* Rx signal detctor level optimization */ 162 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_RX_DECTOR, 0x0408); 163 /* PHYAFE PDCW optimization */ 164 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_PDCW, 0x8880); 165 166 /* Switch to page 8 */ 167 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 168 /* Disable auto-cal */ 169 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AUTO_CAL, 0x0844); 170 171 /* Switch to page 0 */ 172 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 173 } 174 static int rk630_phy_config_init(struct phy_device *phydev) 175 { 176 switch (phydev->addr) { 177 case PHY_ADDR_S40: 178 rk630_phy_s40_config_init(phydev); 179 break; 180 case PHY_ADDR_T22: 181 rk630_phy_t22_config_init(phydev); 182 break; 183 default: 184 printf("Unsupported address for current phy: %d\n", 185 phydev->addr); 186 return -EINVAL; 187 } 188 rk630_phy_ieee_set(phydev, true); 189 /* 190 * Ultra Auto-Power Saving Mode (UAPS) is designed to 191 * save power when cable is not plugged into PHY. 192 */ 193 rk630_phy_set_uaps(phydev); 194 195 return 0; 196 } 197 198 static struct phy_driver RK630_driver = { 199 .name = "Rockchip RK630", 200 .uid = RK630_PHY_ID, 201 .mask = 0xffffff, 202 .features = PHY_BASIC_FEATURES, 203 .config = &rk630_phy_config_init, 204 .startup = &rk630_phy_startup, 205 }; 206 207 int phy_rk630_init(void) 208 { 209 phy_register(&RK630_driver); 210 return 0; 211 } 212