diff options
Diffstat (limited to 'drivers/net/phy/marvell.c')
| -rw-r--r-- | drivers/net/phy/marvell.c | 156 |
1 files changed, 144 insertions, 12 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f4d4eb659cad..22aec5cce683 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c | |||
| @@ -42,6 +42,19 @@ | |||
| 42 | #define MII_M1011_IMASK_INIT 0x6400 | 42 | #define MII_M1011_IMASK_INIT 0x6400 |
| 43 | #define MII_M1011_IMASK_CLEAR 0x0000 | 43 | #define MII_M1011_IMASK_CLEAR 0x0000 |
| 44 | 44 | ||
| 45 | #define MII_M1011_PHY_SCR 0x10 | ||
| 46 | #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 | ||
| 47 | |||
| 48 | #define MII_M1145_PHY_EXT_CR 0x14 | ||
| 49 | #define MII_M1145_RGMII_RX_DELAY 0x0080 | ||
| 50 | #define MII_M1145_RGMII_TX_DELAY 0x0002 | ||
| 51 | |||
| 52 | #define M1145_DEV_FLAGS_RESISTANCE 0x00000001 | ||
| 53 | |||
| 54 | #define MII_M1111_PHY_LED_CONTROL 0x18 | ||
| 55 | #define MII_M1111_PHY_LED_DIRECT 0x4100 | ||
| 56 | #define MII_M1111_PHY_LED_COMBINE 0x411c | ||
| 57 | |||
| 45 | MODULE_DESCRIPTION("Marvell PHY driver"); | 58 | MODULE_DESCRIPTION("Marvell PHY driver"); |
| 46 | MODULE_AUTHOR("Andy Fleming"); | 59 | MODULE_AUTHOR("Andy Fleming"); |
| 47 | MODULE_LICENSE("GPL"); | 60 | MODULE_LICENSE("GPL"); |
| @@ -63,7 +76,7 @@ static int marvell_config_intr(struct phy_device *phydev) | |||
| 63 | { | 76 | { |
| 64 | int err; | 77 | int err; |
| 65 | 78 | ||
| 66 | if(phydev->interrupts == PHY_INTERRUPT_ENABLED) | 79 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) |
| 67 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); | 80 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); |
| 68 | else | 81 | else |
| 69 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); | 82 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); |
| @@ -103,34 +116,153 @@ static int marvell_config_aneg(struct phy_device *phydev) | |||
| 103 | if (err < 0) | 116 | if (err < 0) |
| 104 | return err; | 117 | return err; |
| 105 | 118 | ||
| 119 | err = phy_write(phydev, MII_M1011_PHY_SCR, | ||
| 120 | MII_M1011_PHY_SCR_AUTO_CROSS); | ||
| 121 | if (err < 0) | ||
| 122 | return err; | ||
| 123 | |||
| 124 | err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, | ||
| 125 | MII_M1111_PHY_LED_DIRECT); | ||
| 126 | if (err < 0) | ||
| 127 | return err; | ||
| 106 | 128 | ||
| 107 | err = genphy_config_aneg(phydev); | 129 | err = genphy_config_aneg(phydev); |
| 108 | 130 | ||
| 109 | return err; | 131 | return err; |
| 110 | } | 132 | } |
| 111 | 133 | ||
| 134 | static int m88e1145_config_init(struct phy_device *phydev) | ||
| 135 | { | ||
| 136 | int err; | ||
| 137 | |||
| 138 | /* Take care of errata E0 & E1 */ | ||
| 139 | err = phy_write(phydev, 0x1d, 0x001b); | ||
| 140 | if (err < 0) | ||
| 141 | return err; | ||
| 142 | |||
| 143 | err = phy_write(phydev, 0x1e, 0x418f); | ||
| 144 | if (err < 0) | ||
| 145 | return err; | ||
| 146 | |||
| 147 | err = phy_write(phydev, 0x1d, 0x0016); | ||
| 148 | if (err < 0) | ||
| 149 | return err; | ||
| 150 | |||
| 151 | err = phy_write(phydev, 0x1e, 0xa2da); | ||
| 152 | if (err < 0) | ||
| 153 | return err; | ||
| 154 | |||
| 155 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { | ||
| 156 | int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); | ||
| 157 | if (temp < 0) | ||
| 158 | return temp; | ||
| 159 | |||
| 160 | temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); | ||
| 161 | |||
| 162 | err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); | ||
| 163 | if (err < 0) | ||
| 164 | return err; | ||
| 165 | |||
| 166 | if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) { | ||
| 167 | err = phy_write(phydev, 0x1d, 0x0012); | ||
| 168 | if (err < 0) | ||
| 169 | return err; | ||
| 170 | |||
| 171 | temp = phy_read(phydev, 0x1e); | ||
| 172 | if (temp < 0) | ||
| 173 | return temp; | ||
| 174 | |||
| 175 | temp &= 0xf03f; | ||
| 176 | temp |= 2 << 9; /* 36 ohm */ | ||
| 177 | temp |= 2 << 6; /* 39 ohm */ | ||
| 178 | |||
| 179 | err = phy_write(phydev, 0x1e, temp); | ||
| 180 | if (err < 0) | ||
| 181 | return err; | ||
| 182 | |||
| 183 | err = phy_write(phydev, 0x1d, 0x3); | ||
| 184 | if (err < 0) | ||
| 185 | return err; | ||
| 186 | |||
| 187 | err = phy_write(phydev, 0x1e, 0x8000); | ||
| 188 | if (err < 0) | ||
| 189 | return err; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 112 | 195 | ||
| 113 | static struct phy_driver m88e1101_driver = { | 196 | static struct phy_driver m88e1101_driver = { |
| 114 | .phy_id = 0x01410c00, | 197 | .phy_id = 0x01410c60, |
| 115 | .phy_id_mask = 0xffffff00, | 198 | .phy_id_mask = 0xfffffff0, |
| 116 | .name = "Marvell 88E1101", | 199 | .name = "Marvell 88E1101", |
| 117 | .features = PHY_GBIT_FEATURES, | 200 | .features = PHY_GBIT_FEATURES, |
| 118 | .flags = PHY_HAS_INTERRUPT, | 201 | .flags = PHY_HAS_INTERRUPT, |
| 119 | .config_aneg = &marvell_config_aneg, | 202 | .config_aneg = &marvell_config_aneg, |
| 120 | .read_status = &genphy_read_status, | 203 | .read_status = &genphy_read_status, |
| 121 | .ack_interrupt = &marvell_ack_interrupt, | 204 | .ack_interrupt = &marvell_ack_interrupt, |
| 122 | .config_intr = &marvell_config_intr, | 205 | .config_intr = &marvell_config_intr, |
| 123 | .driver = { .owner = THIS_MODULE,}, | 206 | .driver = {.owner = THIS_MODULE,}, |
| 207 | }; | ||
| 208 | |||
| 209 | static struct phy_driver m88e1111s_driver = { | ||
| 210 | .phy_id = 0x01410cc0, | ||
| 211 | .phy_id_mask = 0xfffffff0, | ||
| 212 | .name = "Marvell 88E1111", | ||
| 213 | .features = PHY_GBIT_FEATURES, | ||
| 214 | .flags = PHY_HAS_INTERRUPT, | ||
| 215 | .config_aneg = &marvell_config_aneg, | ||
| 216 | .read_status = &genphy_read_status, | ||
| 217 | .ack_interrupt = &marvell_ack_interrupt, | ||
| 218 | .config_intr = &marvell_config_intr, | ||
| 219 | .driver = {.owner = THIS_MODULE,}, | ||
| 220 | }; | ||
| 221 | |||
| 222 | static struct phy_driver m88e1145_driver = { | ||
| 223 | .phy_id = 0x01410cd0, | ||
| 224 | .phy_id_mask = 0xfffffff0, | ||
| 225 | .name = "Marvell 88E1145", | ||
| 226 | .features = PHY_GBIT_FEATURES, | ||
| 227 | .flags = PHY_HAS_INTERRUPT, | ||
| 228 | .config_init = &m88e1145_config_init, | ||
| 229 | .config_aneg = &marvell_config_aneg, | ||
| 230 | .read_status = &genphy_read_status, | ||
| 231 | .ack_interrupt = &marvell_ack_interrupt, | ||
| 232 | .config_intr = &marvell_config_intr, | ||
| 233 | .driver = {.owner = THIS_MODULE,}, | ||
| 124 | }; | 234 | }; |
| 125 | 235 | ||
| 126 | static int __init marvell_init(void) | 236 | static int __init marvell_init(void) |
| 127 | { | 237 | { |
| 128 | return phy_driver_register(&m88e1101_driver); | 238 | int ret; |
| 239 | |||
| 240 | ret = phy_driver_register(&m88e1101_driver); | ||
| 241 | if (ret) | ||
| 242 | return ret; | ||
| 243 | |||
| 244 | ret = phy_driver_register(&m88e1111s_driver); | ||
| 245 | if (ret) | ||
| 246 | goto err1111s; | ||
| 247 | |||
| 248 | ret = phy_driver_register(&m88e1145_driver); | ||
| 249 | if (ret) | ||
| 250 | goto err1145; | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | |||
| 254 | err1145: | ||
| 255 | phy_driver_unregister(&m88e1111s_driver); | ||
| 256 | err1111s: | ||
| 257 | phy_driver_unregister(&m88e1101_driver); | ||
| 258 | return ret; | ||
| 129 | } | 259 | } |
| 130 | 260 | ||
| 131 | static void __exit marvell_exit(void) | 261 | static void __exit marvell_exit(void) |
| 132 | { | 262 | { |
| 133 | phy_driver_unregister(&m88e1101_driver); | 263 | phy_driver_unregister(&m88e1101_driver); |
| 264 | phy_driver_unregister(&m88e1111s_driver); | ||
| 265 | phy_driver_unregister(&m88e1145_driver); | ||
| 134 | } | 266 | } |
| 135 | 267 | ||
| 136 | module_init(marvell_init); | 268 | module_init(marvell_init); |
