Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15-rc8 359 lines 9.4 kB view raw
1/* 2 * Broadcom BCM7xxx internal transceivers support. 3 * 4 * Copyright (C) 2014, Broadcom Corporation 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/module.h> 13#include <linux/phy.h> 14#include <linux/delay.h> 15#include <linux/bitops.h> 16#include <linux/brcmphy.h> 17 18/* Broadcom BCM7xxx internal PHY registers */ 19#define MII_BCM7XXX_CHANNEL_WIDTH 0x2000 20 21/* 40nm only register definitions */ 22#define MII_BCM7XXX_100TX_AUX_CTL 0x10 23#define MII_BCM7XXX_100TX_FALSE_CAR 0x13 24#define MII_BCM7XXX_100TX_DISC 0x14 25#define MII_BCM7XXX_AUX_MODE 0x1d 26#define MII_BCM7XX_64CLK_MDIO BIT(12) 27#define MII_BCM7XXX_CORE_BASE1E 0x1e 28#define MII_BCM7XXX_TEST 0x1f 29#define MII_BCM7XXX_SHD_MODE_2 BIT(2) 30 31/* 28nm only register definitions */ 32#define MISC_ADDR(base, channel) base, channel 33 34#define DSP_TAP10 MISC_ADDR(0x0a, 0) 35#define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) 36#define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) 37#define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) 38 39#define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) 40#define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) 41#define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) 42#define AFE_TX_CONFIG MISC_ADDR(0x39, 0) 43#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) 44 45#define CORE_EXPB0 0xb0 46 47static int bcm7445_config_init(struct phy_device *phydev) 48{ 49 int ret; 50 const struct bcm7445_regs { 51 int reg; 52 u16 value; 53 } bcm7445_regs_cfg[] = { 54 /* increases ADC latency by 24ns */ 55 { MII_BCM54XX_EXP_SEL, 0x0038 }, 56 { MII_BCM54XX_EXP_DATA, 0xAB95 }, 57 /* increases internal 1V LDO voltage by 5% */ 58 { MII_BCM54XX_EXP_SEL, 0x2038 }, 59 { MII_BCM54XX_EXP_DATA, 0xBB22 }, 60 /* reduce RX low pass filter corner frequency */ 61 { MII_BCM54XX_EXP_SEL, 0x6038 }, 62 { MII_BCM54XX_EXP_DATA, 0xFFC5 }, 63 /* reduce RX high pass filter corner frequency */ 64 { MII_BCM54XX_EXP_SEL, 0x003a }, 65 { MII_BCM54XX_EXP_DATA, 0x2002 }, 66 }; 67 unsigned int i; 68 69 for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) { 70 ret = phy_write(phydev, 71 bcm7445_regs_cfg[i].reg, 72 bcm7445_regs_cfg[i].value); 73 if (ret) 74 return ret; 75 } 76 77 return 0; 78} 79 80static void phy_write_exp(struct phy_device *phydev, 81 u16 reg, u16 value) 82{ 83 phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg); 84 phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 85} 86 87static void phy_write_misc(struct phy_device *phydev, 88 u16 reg, u16 chl, u16 value) 89{ 90 int tmp; 91 92 phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 93 94 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); 95 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; 96 phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); 97 98 tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg; 99 phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp); 100 101 phy_write(phydev, MII_BCM54XX_EXP_DATA, value); 102} 103 104static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev) 105{ 106 /* Increase VCO range to prevent unlocking problem of PLL at low 107 * temp 108 */ 109 phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 110 111 /* Change Ki to 011 */ 112 phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 113 114 /* Disable loading of TVCO buffer to bandgap, set bandgap trim 115 * to 111 116 */ 117 phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 118 119 /* Adjust bias current trim by -3 */ 120 phy_write_misc(phydev, DSP_TAP10, 0x690b); 121 122 /* Switch to CORE_BASE1E */ 123 phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); 124 125 /* Reset R_CAL/RC_CAL Engine */ 126 phy_write_exp(phydev, CORE_EXPB0, 0x0010); 127 128 /* Disable Reset R_CAL/RC_CAL Engine */ 129 phy_write_exp(phydev, CORE_EXPB0, 0x0000); 130 131 /* write AFE_RXCONFIG_0 */ 132 phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 133 134 /* write AFE_RXCONFIG_1 */ 135 phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 136 137 /* write AFE_RX_LP_COUNTER */ 138 phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 139 140 /* write AFE_HPF_TRIM_OTHERS */ 141 phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 142 143 /* write AFTE_TX_CONFIG */ 144 phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 145 146 return 0; 147} 148 149static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 150{ 151 int ret; 152 153 ret = bcm7445_config_init(phydev); 154 if (ret) 155 return ret; 156 157 return bcm7xxx_28nm_afe_config_init(phydev); 158} 159 160static int phy_set_clr_bits(struct phy_device *dev, int location, 161 int set_mask, int clr_mask) 162{ 163 int v, ret; 164 165 v = phy_read(dev, location); 166 if (v < 0) 167 return v; 168 169 v &= ~clr_mask; 170 v |= set_mask; 171 172 ret = phy_write(dev, location, v); 173 if (ret < 0) 174 return ret; 175 176 return v; 177} 178 179static int bcm7xxx_config_init(struct phy_device *phydev) 180{ 181 int ret; 182 183 /* Enable 64 clock MDIO */ 184 phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); 185 phy_read(phydev, MII_BCM7XXX_AUX_MODE); 186 187 /* Workaround only required for 100Mbits/sec */ 188 if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) 189 return 0; 190 191 /* set shadow mode 2 */ 192 ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 193 MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); 194 if (ret < 0) 195 return ret; 196 197 /* set iddq_clkbias */ 198 phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); 199 udelay(10); 200 201 /* reset iddq_clkbias */ 202 phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); 203 204 phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); 205 206 /* reset shadow mode 2 */ 207 ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); 208 if (ret < 0) 209 return ret; 210 211 return 0; 212} 213 214/* Workaround for putting the PHY in IDDQ mode, required 215 * for all BCM7XXX PHYs 216 */ 217static int bcm7xxx_suspend(struct phy_device *phydev) 218{ 219 int ret; 220 const struct bcm7xxx_regs { 221 int reg; 222 u16 value; 223 } bcm7xxx_suspend_cfg[] = { 224 { MII_BCM7XXX_TEST, 0x008b }, 225 { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, 226 { MII_BCM7XXX_100TX_DISC, 0x7000 }, 227 { MII_BCM7XXX_TEST, 0x000f }, 228 { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, 229 { MII_BCM7XXX_TEST, 0x000b }, 230 }; 231 unsigned int i; 232 233 for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { 234 ret = phy_write(phydev, 235 bcm7xxx_suspend_cfg[i].reg, 236 bcm7xxx_suspend_cfg[i].value); 237 if (ret) 238 return ret; 239 } 240 241 return 0; 242} 243 244static int bcm7xxx_dummy_config_init(struct phy_device *phydev) 245{ 246 return 0; 247} 248 249static struct phy_driver bcm7xxx_driver[] = { 250{ 251 .phy_id = PHY_ID_BCM7366, 252 .phy_id_mask = 0xfffffff0, 253 .name = "Broadcom BCM7366", 254 .features = PHY_GBIT_FEATURES | 255 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 256 .flags = PHY_IS_INTERNAL, 257 .config_init = bcm7xxx_28nm_afe_config_init, 258 .config_aneg = genphy_config_aneg, 259 .read_status = genphy_read_status, 260 .suspend = bcm7xxx_suspend, 261 .resume = bcm7xxx_28nm_afe_config_init, 262 .driver = { .owner = THIS_MODULE }, 263}, { 264 .phy_id = PHY_ID_BCM7439, 265 .phy_id_mask = 0xfffffff0, 266 .name = "Broadcom BCM7439", 267 .features = PHY_GBIT_FEATURES | 268 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 269 .flags = PHY_IS_INTERNAL, 270 .config_init = bcm7xxx_28nm_afe_config_init, 271 .config_aneg = genphy_config_aneg, 272 .read_status = genphy_read_status, 273 .suspend = bcm7xxx_suspend, 274 .resume = bcm7xxx_28nm_afe_config_init, 275 .driver = { .owner = THIS_MODULE }, 276}, { 277 .phy_id = PHY_ID_BCM7445, 278 .phy_id_mask = 0xfffffff0, 279 .name = "Broadcom BCM7445", 280 .features = PHY_GBIT_FEATURES | 281 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 282 .flags = PHY_IS_INTERNAL, 283 .config_init = bcm7xxx_28nm_config_init, 284 .config_aneg = genphy_config_aneg, 285 .read_status = genphy_read_status, 286 .suspend = bcm7xxx_suspend, 287 .resume = bcm7xxx_28nm_config_init, 288 .driver = { .owner = THIS_MODULE }, 289}, { 290 .name = "Broadcom BCM7XXX 28nm", 291 .phy_id = PHY_ID_BCM7XXX_28, 292 .phy_id_mask = PHY_BCM_OUI_MASK, 293 .features = PHY_GBIT_FEATURES | 294 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 295 .flags = PHY_IS_INTERNAL, 296 .config_init = bcm7xxx_28nm_config_init, 297 .config_aneg = genphy_config_aneg, 298 .read_status = genphy_read_status, 299 .suspend = bcm7xxx_suspend, 300 .resume = bcm7xxx_28nm_config_init, 301 .driver = { .owner = THIS_MODULE }, 302}, { 303 .phy_id = PHY_BCM_OUI_4, 304 .phy_id_mask = 0xffff0000, 305 .name = "Broadcom BCM7XXX 40nm", 306 .features = PHY_GBIT_FEATURES | 307 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 308 .flags = PHY_IS_INTERNAL, 309 .config_init = bcm7xxx_config_init, 310 .config_aneg = genphy_config_aneg, 311 .read_status = genphy_read_status, 312 .suspend = bcm7xxx_suspend, 313 .resume = bcm7xxx_config_init, 314 .driver = { .owner = THIS_MODULE }, 315}, { 316 .phy_id = PHY_BCM_OUI_5, 317 .phy_id_mask = 0xffffff00, 318 .name = "Broadcom BCM7XXX 65nm", 319 .features = PHY_BASIC_FEATURES | 320 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 321 .flags = PHY_IS_INTERNAL, 322 .config_init = bcm7xxx_dummy_config_init, 323 .config_aneg = genphy_config_aneg, 324 .read_status = genphy_read_status, 325 .suspend = bcm7xxx_suspend, 326 .resume = bcm7xxx_config_init, 327 .driver = { .owner = THIS_MODULE }, 328} }; 329 330static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { 331 { PHY_ID_BCM7366, 0xfffffff0, }, 332 { PHY_ID_BCM7439, 0xfffffff0, }, 333 { PHY_ID_BCM7445, 0xfffffff0, }, 334 { PHY_ID_BCM7XXX_28, 0xfffffc00 }, 335 { PHY_BCM_OUI_4, 0xffff0000 }, 336 { PHY_BCM_OUI_5, 0xffffff00 }, 337 { } 338}; 339 340static int __init bcm7xxx_phy_init(void) 341{ 342 return phy_drivers_register(bcm7xxx_driver, 343 ARRAY_SIZE(bcm7xxx_driver)); 344} 345 346static void __exit bcm7xxx_phy_exit(void) 347{ 348 phy_drivers_unregister(bcm7xxx_driver, 349 ARRAY_SIZE(bcm7xxx_driver)); 350} 351 352module_init(bcm7xxx_phy_init); 353module_exit(bcm7xxx_phy_exit); 354 355MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); 356 357MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); 358MODULE_LICENSE("GPL"); 359MODULE_AUTHOR("Broadcom Corporation");