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_s40_config_init(struct phy_device *phydev) 79 { 80 phy_write(phydev, 0, MDIO_DEVAD_NONE, 81 phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13)); 82 83 /* Switch to page 1 */ 84 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 85 /* Disable APS */ 86 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 87 /* Switch to page 2 */ 88 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 89 /* PHYAFE TRX optimization */ 90 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 91 /* Switch to page 6 */ 92 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 93 /* PHYAFE TX optimization */ 94 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f); 95 /* PHYAFE RX optimization */ 96 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000); 97 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530); 98 99 /* Switch to page 8 */ 100 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 101 /* PHYAFE TRX optimization */ 102 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc); 103 104 /* Switch to page 0 */ 105 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 106 } 107 108 static void rk630_phy_t22_config_init(struct phy_device *phydev) 109 { 110 /* Switch to page 1 */ 111 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100); 112 /* Disable APS */ 113 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824); 114 /* Switch to page 2 */ 115 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200); 116 /* PHYAFE TRX optimization */ 117 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000); 118 /* Switch to page 6 */ 119 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600); 120 /* PHYAFE ADC optimization */ 121 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, 0x5540); 122 /* PHYAFE Gain optimization */ 123 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_GAIN_ANONTROL, 0x0400); 124 /* PHYAFE EQ optimization */ 125 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x1088); 126 /* PHYAFE TX optimization */ 127 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x3030); 128 /* PHYAFE CP current optimization */ 129 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_CP_CURRENT, 0x0575); 130 /* ADC OP BIAS optimization */ 131 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_OP_BIAS, 0x0000); 132 /* Rx signal detctor level optimization */ 133 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_RX_DECTOR, 0x0408); 134 /* PHYAFE PDCW optimization */ 135 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_PDCW, 0x8880); 136 137 /* Switch to page 8 */ 138 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800); 139 /* Disable auto-cal */ 140 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AUTO_CAL, 0x0844); 141 142 /* Switch to page 0 */ 143 phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000); 144 } 145 static int rk630_phy_config_init(struct phy_device *phydev) 146 { 147 switch (phydev->addr) { 148 case PHY_ADDR_S40: 149 rk630_phy_s40_config_init(phydev); 150 break; 151 case PHY_ADDR_T22: 152 rk630_phy_t22_config_init(phydev); 153 break; 154 default: 155 printf("Unsupported address for current phy: %d\n", 156 phydev->addr); 157 return -EINVAL; 158 } 159 160 return 0; 161 } 162 163 static struct phy_driver RK630_driver = { 164 .name = "Rockchip RK630", 165 .uid = RK630_PHY_ID, 166 .mask = 0xffffff, 167 .features = PHY_BASIC_FEATURES, 168 .config = &rk630_phy_config_init, 169 .startup = &rk630_phy_startup, 170 }; 171 172 int phy_rk630_init(void) 173 { 174 phy_register(&RK630_driver); 175 return 0; 176 } 177