sungem_phy.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. /*
  2. * PHY drivers for the sungem ethernet driver.
  3. *
  4. * This file could be shared with other drivers.
  5. *
  6. * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
  7. *
  8. * TODO:
  9. * - Implement WOL
  10. * - Add support for PHYs that provide an IRQ line
  11. * - Eventually moved the entire polling state machine in
  12. * there (out of the eth driver), so that it can easily be
  13. * skipped on PHYs that implement it in hardware.
  14. * - On LXT971 & BCM5201, Apple uses some chip specific regs
  15. * to read the link status. Figure out why and if it makes
  16. * sense to do the same (magic aneg ?)
  17. * - Apple has some additional power management code for some
  18. * Broadcom PHYs that they "hide" from the OpenSource version
  19. * of darwin, still need to reverse engineer that
  20. */
  21. #include <linux/config.h>
  22. #include <linux/module.h>
  23. #include <linux/kernel.h>
  24. #include <linux/sched.h>
  25. #include <linux/types.h>
  26. #include <linux/netdevice.h>
  27. #include <linux/etherdevice.h>
  28. #include <linux/mii.h>
  29. #include <linux/ethtool.h>
  30. #include <linux/delay.h>
  31. #ifdef CONFIG_PPC_PMAC
  32. #include <asm/prom.h>
  33. #endif
  34. #include "sungem_phy.h"
  35. /* Link modes of the BCM5400 PHY */
  36. static const int phy_BCM5400_link_table[8][3] = {
  37. { 0, 0, 0 }, /* No link */
  38. { 0, 0, 0 }, /* 10BT Half Duplex */
  39. { 1, 0, 0 }, /* 10BT Full Duplex */
  40. { 0, 1, 0 }, /* 100BT Half Duplex */
  41. { 0, 1, 0 }, /* 100BT Half Duplex */
  42. { 1, 1, 0 }, /* 100BT Full Duplex*/
  43. { 1, 0, 1 }, /* 1000BT */
  44. { 1, 0, 1 }, /* 1000BT */
  45. };
  46. static inline int __phy_read(struct mii_phy* phy, int id, int reg)
  47. {
  48. return phy->mdio_read(phy->dev, id, reg);
  49. }
  50. static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
  51. {
  52. phy->mdio_write(phy->dev, id, reg, val);
  53. }
  54. static inline int phy_read(struct mii_phy* phy, int reg)
  55. {
  56. return phy->mdio_read(phy->dev, phy->mii_id, reg);
  57. }
  58. static inline void phy_write(struct mii_phy* phy, int reg, int val)
  59. {
  60. phy->mdio_write(phy->dev, phy->mii_id, reg, val);
  61. }
  62. static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
  63. {
  64. u16 val;
  65. int limit = 10000;
  66. val = __phy_read(phy, phy_id, MII_BMCR);
  67. val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
  68. val |= BMCR_RESET;
  69. __phy_write(phy, phy_id, MII_BMCR, val);
  70. udelay(100);
  71. while (limit--) {
  72. val = __phy_read(phy, phy_id, MII_BMCR);
  73. if ((val & BMCR_RESET) == 0)
  74. break;
  75. udelay(10);
  76. }
  77. if ((val & BMCR_ISOLATE) && limit > 0)
  78. __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
  79. return (limit <= 0);
  80. }
  81. static int bcm5201_init(struct mii_phy* phy)
  82. {
  83. u16 data;
  84. data = phy_read(phy, MII_BCM5201_MULTIPHY);
  85. data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
  86. phy_write(phy, MII_BCM5201_MULTIPHY, data);
  87. phy_write(phy, MII_BCM5201_INTERRUPT, 0);
  88. return 0;
  89. }
  90. static int bcm5201_suspend(struct mii_phy* phy)
  91. {
  92. phy_write(phy, MII_BCM5201_INTERRUPT, 0);
  93. phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
  94. return 0;
  95. }
  96. static int bcm5221_init(struct mii_phy* phy)
  97. {
  98. u16 data;
  99. data = phy_read(phy, MII_BCM5221_TEST);
  100. phy_write(phy, MII_BCM5221_TEST,
  101. data | MII_BCM5221_TEST_ENABLE_SHADOWS);
  102. data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
  103. phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
  104. data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
  105. data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  106. phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
  107. data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
  108. data = phy_read(phy, MII_BCM5221_TEST);
  109. phy_write(phy, MII_BCM5221_TEST,
  110. data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
  111. return 0;
  112. }
  113. static int bcm5221_suspend(struct mii_phy* phy)
  114. {
  115. u16 data;
  116. data = phy_read(phy, MII_BCM5221_TEST);
  117. phy_write(phy, MII_BCM5221_TEST,
  118. data | MII_BCM5221_TEST_ENABLE_SHADOWS);
  119. data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  120. phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
  121. data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
  122. return 0;
  123. }
  124. static int bcm5400_init(struct mii_phy* phy)
  125. {
  126. u16 data;
  127. /* Configure for gigabit full duplex */
  128. data = phy_read(phy, MII_BCM5400_AUXCONTROL);
  129. data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
  130. phy_write(phy, MII_BCM5400_AUXCONTROL, data);
  131. data = phy_read(phy, MII_BCM5400_GB_CONTROL);
  132. data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
  133. phy_write(phy, MII_BCM5400_GB_CONTROL, data);
  134. udelay(100);
  135. /* Reset and configure cascaded 10/100 PHY */
  136. (void)reset_one_mii_phy(phy, 0x1f);
  137. data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
  138. data |= MII_BCM5201_MULTIPHY_SERIALMODE;
  139. __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
  140. data = phy_read(phy, MII_BCM5400_AUXCONTROL);
  141. data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
  142. phy_write(phy, MII_BCM5400_AUXCONTROL, data);
  143. return 0;
  144. }
  145. static int bcm5400_suspend(struct mii_phy* phy)
  146. {
  147. #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
  148. phy_write(phy, MII_BMCR, BMCR_PDOWN);
  149. #endif
  150. return 0;
  151. }
  152. static int bcm5401_init(struct mii_phy* phy)
  153. {
  154. u16 data;
  155. int rev;
  156. rev = phy_read(phy, MII_PHYSID2) & 0x000f;
  157. if (rev == 0 || rev == 3) {
  158. /* Some revisions of 5401 appear to need this
  159. * initialisation sequence to disable, according
  160. * to OF, "tap power management"
  161. *
  162. * WARNING ! OF and Darwin don't agree on the
  163. * register addresses. OF seem to interpret the
  164. * register numbers below as decimal
  165. *
  166. * Note: This should (and does) match tg3_init_5401phy_dsp
  167. * in the tg3.c driver. -DaveM
  168. */
  169. phy_write(phy, 0x18, 0x0c20);
  170. phy_write(phy, 0x17, 0x0012);
  171. phy_write(phy, 0x15, 0x1804);
  172. phy_write(phy, 0x17, 0x0013);
  173. phy_write(phy, 0x15, 0x1204);
  174. phy_write(phy, 0x17, 0x8006);
  175. phy_write(phy, 0x15, 0x0132);
  176. phy_write(phy, 0x17, 0x8006);
  177. phy_write(phy, 0x15, 0x0232);
  178. phy_write(phy, 0x17, 0x201f);
  179. phy_write(phy, 0x15, 0x0a20);
  180. }
  181. /* Configure for gigabit full duplex */
  182. data = phy_read(phy, MII_BCM5400_GB_CONTROL);
  183. data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
  184. phy_write(phy, MII_BCM5400_GB_CONTROL, data);
  185. udelay(10);
  186. /* Reset and configure cascaded 10/100 PHY */
  187. (void)reset_one_mii_phy(phy, 0x1f);
  188. data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
  189. data |= MII_BCM5201_MULTIPHY_SERIALMODE;
  190. __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
  191. return 0;
  192. }
  193. static int bcm5401_suspend(struct mii_phy* phy)
  194. {
  195. #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
  196. phy_write(phy, MII_BMCR, BMCR_PDOWN);
  197. #endif
  198. return 0;
  199. }
  200. static int bcm5411_init(struct mii_phy* phy)
  201. {
  202. u16 data;
  203. /* Here's some more Apple black magic to setup
  204. * some voltage stuffs.
  205. */
  206. phy_write(phy, 0x1c, 0x8c23);
  207. phy_write(phy, 0x1c, 0x8ca3);
  208. phy_write(phy, 0x1c, 0x8c23);
  209. /* Here, Apple seems to want to reset it, do
  210. * it as well
  211. */
  212. phy_write(phy, MII_BMCR, BMCR_RESET);
  213. phy_write(phy, MII_BMCR, 0x1340);
  214. data = phy_read(phy, MII_BCM5400_GB_CONTROL);
  215. data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
  216. phy_write(phy, MII_BCM5400_GB_CONTROL, data);
  217. udelay(10);
  218. /* Reset and configure cascaded 10/100 PHY */
  219. (void)reset_one_mii_phy(phy, 0x1f);
  220. return 0;
  221. }
  222. static int generic_suspend(struct mii_phy* phy)
  223. {
  224. phy_write(phy, MII_BMCR, BMCR_PDOWN);
  225. return 0;
  226. }
  227. static int bcm5421_init(struct mii_phy* phy)
  228. {
  229. u16 data;
  230. unsigned int id;
  231. id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
  232. /* Revision 0 of 5421 needs some fixups */
  233. if (id == 0x002060e0) {
  234. /* This is borrowed from MacOS
  235. */
  236. phy_write(phy, 0x18, 0x1007);
  237. data = phy_read(phy, 0x18);
  238. phy_write(phy, 0x18, data | 0x0400);
  239. phy_write(phy, 0x18, 0x0007);
  240. data = phy_read(phy, 0x18);
  241. phy_write(phy, 0x18, data | 0x0800);
  242. phy_write(phy, 0x17, 0x000a);
  243. data = phy_read(phy, 0x15);
  244. phy_write(phy, 0x15, data | 0x0200);
  245. }
  246. /* Pick up some init code from OF for K2 version */
  247. if ((id & 0xfffffff0) == 0x002062e0) {
  248. phy_write(phy, 4, 0x01e1);
  249. phy_write(phy, 9, 0x0300);
  250. }
  251. /* Check if we can enable automatic low power */
  252. #ifdef CONFIG_PPC_PMAC
  253. if (phy->platform_data) {
  254. struct device_node *np = of_get_parent(phy->platform_data);
  255. int can_low_power = 1;
  256. if (np == NULL || get_property(np, "no-autolowpower", NULL))
  257. can_low_power = 0;
  258. if (can_low_power) {
  259. /* Enable automatic low-power */
  260. phy_write(phy, 0x1c, 0x9002);
  261. phy_write(phy, 0x1c, 0xa821);
  262. phy_write(phy, 0x1c, 0x941d);
  263. }
  264. }
  265. #endif /* CONFIG_PPC_PMAC */
  266. return 0;
  267. }
  268. static int bcm5421_enable_fiber(struct mii_phy* phy)
  269. {
  270. /* enable fiber mode */
  271. phy_write(phy, MII_NCONFIG, 0x9020);
  272. /* LEDs active in both modes, autosense prio = fiber */
  273. phy_write(phy, MII_NCONFIG, 0x945f);
  274. /* switch off fibre autoneg */
  275. phy_write(phy, MII_NCONFIG, 0xfc01);
  276. phy_write(phy, 0x0b, 0x0004);
  277. return 0;
  278. }
  279. static int bcm5461_enable_fiber(struct mii_phy* phy)
  280. {
  281. phy_write(phy, MII_NCONFIG, 0xfc0c);
  282. phy_write(phy, MII_BMCR, 0x4140);
  283. phy_write(phy, MII_NCONFIG, 0xfc0b);
  284. phy_write(phy, MII_BMCR, 0x0140);
  285. return 0;
  286. }
  287. static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
  288. {
  289. u16 ctl, adv;
  290. phy->autoneg = 1;
  291. phy->speed = SPEED_10;
  292. phy->duplex = DUPLEX_HALF;
  293. phy->pause = 0;
  294. phy->advertising = advertise;
  295. /* Setup standard advertise */
  296. adv = phy_read(phy, MII_ADVERTISE);
  297. adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  298. if (advertise & ADVERTISED_10baseT_Half)
  299. adv |= ADVERTISE_10HALF;
  300. if (advertise & ADVERTISED_10baseT_Full)
  301. adv |= ADVERTISE_10FULL;
  302. if (advertise & ADVERTISED_100baseT_Half)
  303. adv |= ADVERTISE_100HALF;
  304. if (advertise & ADVERTISED_100baseT_Full)
  305. adv |= ADVERTISE_100FULL;
  306. phy_write(phy, MII_ADVERTISE, adv);
  307. /* Setup 1000BT advertise */
  308. adv = phy_read(phy, MII_1000BASETCONTROL);
  309. adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
  310. if (advertise & SUPPORTED_1000baseT_Half)
  311. adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
  312. if (advertise & SUPPORTED_1000baseT_Full)
  313. adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
  314. phy_write(phy, MII_1000BASETCONTROL, adv);
  315. /* Start/Restart aneg */
  316. ctl = phy_read(phy, MII_BMCR);
  317. ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  318. phy_write(phy, MII_BMCR, ctl);
  319. return 0;
  320. }
  321. static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
  322. {
  323. u16 ctl;
  324. phy->autoneg = 0;
  325. phy->speed = speed;
  326. phy->duplex = fd;
  327. phy->pause = 0;
  328. ctl = phy_read(phy, MII_BMCR);
  329. ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
  330. /* First reset the PHY */
  331. phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
  332. /* Select speed & duplex */
  333. switch(speed) {
  334. case SPEED_10:
  335. break;
  336. case SPEED_100:
  337. ctl |= BMCR_SPEED100;
  338. break;
  339. case SPEED_1000:
  340. ctl |= BMCR_SPD2;
  341. }
  342. if (fd == DUPLEX_FULL)
  343. ctl |= BMCR_FULLDPLX;
  344. // XXX Should we set the sungem to GII now on 1000BT ?
  345. phy_write(phy, MII_BMCR, ctl);
  346. return 0;
  347. }
  348. static int bcm54xx_read_link(struct mii_phy *phy)
  349. {
  350. int link_mode;
  351. u16 val;
  352. if (phy->autoneg) {
  353. val = phy_read(phy, MII_BCM5400_AUXSTATUS);
  354. link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
  355. MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
  356. phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
  357. phy->speed = phy_BCM5400_link_table[link_mode][2] ?
  358. SPEED_1000 :
  359. (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
  360. val = phy_read(phy, MII_LPA);
  361. phy->pause = ((val & LPA_PAUSE) != 0);
  362. }
  363. /* On non-aneg, we assume what we put in BMCR is the speed,
  364. * though magic-aneg shouldn't prevent this case from occurring
  365. */
  366. return 0;
  367. }
  368. static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
  369. {
  370. u16 ctl, adv;
  371. phy->autoneg = 1;
  372. phy->speed = SPEED_10;
  373. phy->duplex = DUPLEX_HALF;
  374. phy->pause = 0;
  375. phy->advertising = advertise;
  376. /* Setup standard advertise */
  377. adv = phy_read(phy, MII_ADVERTISE);
  378. adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  379. if (advertise & ADVERTISED_10baseT_Half)
  380. adv |= ADVERTISE_10HALF;
  381. if (advertise & ADVERTISED_10baseT_Full)
  382. adv |= ADVERTISE_10FULL;
  383. if (advertise & ADVERTISED_100baseT_Half)
  384. adv |= ADVERTISE_100HALF;
  385. if (advertise & ADVERTISED_100baseT_Full)
  386. adv |= ADVERTISE_100FULL;
  387. phy_write(phy, MII_ADVERTISE, adv);
  388. /* Setup 1000BT advertise & enable crossover detect
  389. * XXX How do we advertise 1000BT ? Darwin source is
  390. * confusing here, they read from specific control and
  391. * write to control... Someone has specs for those
  392. * beasts ?
  393. */
  394. adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
  395. adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
  396. adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
  397. MII_1000BASETCONTROL_HALFDUPLEXCAP);
  398. if (advertise & SUPPORTED_1000baseT_Half)
  399. adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
  400. if (advertise & SUPPORTED_1000baseT_Full)
  401. adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
  402. phy_write(phy, MII_1000BASETCONTROL, adv);
  403. /* Start/Restart aneg */
  404. ctl = phy_read(phy, MII_BMCR);
  405. ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  406. phy_write(phy, MII_BMCR, ctl);
  407. return 0;
  408. }
  409. static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
  410. {
  411. u16 ctl, ctl2;
  412. phy->autoneg = 0;
  413. phy->speed = speed;
  414. phy->duplex = fd;
  415. phy->pause = 0;
  416. ctl = phy_read(phy, MII_BMCR);
  417. ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
  418. ctl |= BMCR_RESET;
  419. /* Select speed & duplex */
  420. switch(speed) {
  421. case SPEED_10:
  422. break;
  423. case SPEED_100:
  424. ctl |= BMCR_SPEED100;
  425. break;
  426. /* I'm not sure about the one below, again, Darwin source is
  427. * quite confusing and I lack chip specs
  428. */
  429. case SPEED_1000:
  430. ctl |= BMCR_SPD2;
  431. }
  432. if (fd == DUPLEX_FULL)
  433. ctl |= BMCR_FULLDPLX;
  434. /* Disable crossover. Again, the way Apple does it is strange,
  435. * though I don't assume they are wrong ;)
  436. */
  437. ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
  438. ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
  439. MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
  440. MII_1000BASETCONTROL_FULLDUPLEXCAP |
  441. MII_1000BASETCONTROL_HALFDUPLEXCAP);
  442. if (speed == SPEED_1000)
  443. ctl2 |= (fd == DUPLEX_FULL) ?
  444. MII_1000BASETCONTROL_FULLDUPLEXCAP :
  445. MII_1000BASETCONTROL_HALFDUPLEXCAP;
  446. phy_write(phy, MII_1000BASETCONTROL, ctl2);
  447. // XXX Should we set the sungem to GII now on 1000BT ?
  448. phy_write(phy, MII_BMCR, ctl);
  449. return 0;
  450. }
  451. static int marvell_read_link(struct mii_phy *phy)
  452. {
  453. u16 status;
  454. if (phy->autoneg) {
  455. status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
  456. if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
  457. return -EAGAIN;
  458. if (status & MII_M1011_PHY_SPEC_STATUS_1000)
  459. phy->speed = SPEED_1000;
  460. else if (status & MII_M1011_PHY_SPEC_STATUS_100)
  461. phy->speed = SPEED_100;
  462. else
  463. phy->speed = SPEED_10;
  464. if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
  465. phy->duplex = DUPLEX_FULL;
  466. else
  467. phy->duplex = DUPLEX_HALF;
  468. phy->pause = 0; /* XXX Check against spec ! */
  469. }
  470. /* On non-aneg, we assume what we put in BMCR is the speed,
  471. * though magic-aneg shouldn't prevent this case from occurring
  472. */
  473. return 0;
  474. }
  475. static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
  476. {
  477. u16 ctl, adv;
  478. phy->autoneg = 1;
  479. phy->speed = SPEED_10;
  480. phy->duplex = DUPLEX_HALF;
  481. phy->pause = 0;
  482. phy->advertising = advertise;
  483. /* Setup standard advertise */
  484. adv = phy_read(phy, MII_ADVERTISE);
  485. adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  486. if (advertise & ADVERTISED_10baseT_Half)
  487. adv |= ADVERTISE_10HALF;
  488. if (advertise & ADVERTISED_10baseT_Full)
  489. adv |= ADVERTISE_10FULL;
  490. if (advertise & ADVERTISED_100baseT_Half)
  491. adv |= ADVERTISE_100HALF;
  492. if (advertise & ADVERTISED_100baseT_Full)
  493. adv |= ADVERTISE_100FULL;
  494. phy_write(phy, MII_ADVERTISE, adv);
  495. /* Start/Restart aneg */
  496. ctl = phy_read(phy, MII_BMCR);
  497. ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  498. phy_write(phy, MII_BMCR, ctl);
  499. return 0;
  500. }
  501. static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
  502. {
  503. u16 ctl;
  504. phy->autoneg = 0;
  505. phy->speed = speed;
  506. phy->duplex = fd;
  507. phy->pause = 0;
  508. ctl = phy_read(phy, MII_BMCR);
  509. ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
  510. /* First reset the PHY */
  511. phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
  512. /* Select speed & duplex */
  513. switch(speed) {
  514. case SPEED_10:
  515. break;
  516. case SPEED_100:
  517. ctl |= BMCR_SPEED100;
  518. break;
  519. case SPEED_1000:
  520. default:
  521. return -EINVAL;
  522. }
  523. if (fd == DUPLEX_FULL)
  524. ctl |= BMCR_FULLDPLX;
  525. phy_write(phy, MII_BMCR, ctl);
  526. return 0;
  527. }
  528. static int genmii_poll_link(struct mii_phy *phy)
  529. {
  530. u16 status;
  531. (void)phy_read(phy, MII_BMSR);
  532. status = phy_read(phy, MII_BMSR);
  533. if ((status & BMSR_LSTATUS) == 0)
  534. return 0;
  535. if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
  536. return 0;
  537. return 1;
  538. }
  539. static int genmii_read_link(struct mii_phy *phy)
  540. {
  541. u16 lpa;
  542. if (phy->autoneg) {
  543. lpa = phy_read(phy, MII_LPA);
  544. if (lpa & (LPA_10FULL | LPA_100FULL))
  545. phy->duplex = DUPLEX_FULL;
  546. else
  547. phy->duplex = DUPLEX_HALF;
  548. if (lpa & (LPA_100FULL | LPA_100HALF))
  549. phy->speed = SPEED_100;
  550. else
  551. phy->speed = SPEED_10;
  552. phy->pause = 0;
  553. }
  554. /* On non-aneg, we assume what we put in BMCR is the speed,
  555. * though magic-aneg shouldn't prevent this case from occurring
  556. */
  557. return 0;
  558. }
  559. #define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
  560. SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
  561. SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
  562. #define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
  563. SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
  564. /* Broadcom BCM 5201 */
  565. static struct mii_phy_ops bcm5201_phy_ops = {
  566. .init = bcm5201_init,
  567. .suspend = bcm5201_suspend,
  568. .setup_aneg = genmii_setup_aneg,
  569. .setup_forced = genmii_setup_forced,
  570. .poll_link = genmii_poll_link,
  571. .read_link = genmii_read_link,
  572. };
  573. static struct mii_phy_def bcm5201_phy_def = {
  574. .phy_id = 0x00406210,
  575. .phy_id_mask = 0xfffffff0,
  576. .name = "BCM5201",
  577. .features = MII_BASIC_FEATURES,
  578. .magic_aneg = 1,
  579. .ops = &bcm5201_phy_ops
  580. };
  581. /* Broadcom BCM 5221 */
  582. static struct mii_phy_ops bcm5221_phy_ops = {
  583. .suspend = bcm5221_suspend,
  584. .init = bcm5221_init,
  585. .setup_aneg = genmii_setup_aneg,
  586. .setup_forced = genmii_setup_forced,
  587. .poll_link = genmii_poll_link,
  588. .read_link = genmii_read_link,
  589. };
  590. static struct mii_phy_def bcm5221_phy_def = {
  591. .phy_id = 0x004061e0,
  592. .phy_id_mask = 0xfffffff0,
  593. .name = "BCM5221",
  594. .features = MII_BASIC_FEATURES,
  595. .magic_aneg = 1,
  596. .ops = &bcm5221_phy_ops
  597. };
  598. /* Broadcom BCM 5400 */
  599. static struct mii_phy_ops bcm5400_phy_ops = {
  600. .init = bcm5400_init,
  601. .suspend = bcm5400_suspend,
  602. .setup_aneg = bcm54xx_setup_aneg,
  603. .setup_forced = bcm54xx_setup_forced,
  604. .poll_link = genmii_poll_link,
  605. .read_link = bcm54xx_read_link,
  606. };
  607. static struct mii_phy_def bcm5400_phy_def = {
  608. .phy_id = 0x00206040,
  609. .phy_id_mask = 0xfffffff0,
  610. .name = "BCM5400",
  611. .features = MII_GBIT_FEATURES,
  612. .magic_aneg = 1,
  613. .ops = &bcm5400_phy_ops
  614. };
  615. /* Broadcom BCM 5401 */
  616. static struct mii_phy_ops bcm5401_phy_ops = {
  617. .init = bcm5401_init,
  618. .suspend = bcm5401_suspend,
  619. .setup_aneg = bcm54xx_setup_aneg,
  620. .setup_forced = bcm54xx_setup_forced,
  621. .poll_link = genmii_poll_link,
  622. .read_link = bcm54xx_read_link,
  623. };
  624. static struct mii_phy_def bcm5401_phy_def = {
  625. .phy_id = 0x00206050,
  626. .phy_id_mask = 0xfffffff0,
  627. .name = "BCM5401",
  628. .features = MII_GBIT_FEATURES,
  629. .magic_aneg = 1,
  630. .ops = &bcm5401_phy_ops
  631. };
  632. /* Broadcom BCM 5411 */
  633. static struct mii_phy_ops bcm5411_phy_ops = {
  634. .init = bcm5411_init,
  635. .suspend = generic_suspend,
  636. .setup_aneg = bcm54xx_setup_aneg,
  637. .setup_forced = bcm54xx_setup_forced,
  638. .poll_link = genmii_poll_link,
  639. .read_link = bcm54xx_read_link,
  640. };
  641. static struct mii_phy_def bcm5411_phy_def = {
  642. .phy_id = 0x00206070,
  643. .phy_id_mask = 0xfffffff0,
  644. .name = "BCM5411",
  645. .features = MII_GBIT_FEATURES,
  646. .magic_aneg = 1,
  647. .ops = &bcm5411_phy_ops
  648. };
  649. /* Broadcom BCM 5421 */
  650. static struct mii_phy_ops bcm5421_phy_ops = {
  651. .init = bcm5421_init,
  652. .suspend = generic_suspend,
  653. .setup_aneg = bcm54xx_setup_aneg,
  654. .setup_forced = bcm54xx_setup_forced,
  655. .poll_link = genmii_poll_link,
  656. .read_link = bcm54xx_read_link,
  657. .enable_fiber = bcm5421_enable_fiber,
  658. };
  659. static struct mii_phy_def bcm5421_phy_def = {
  660. .phy_id = 0x002060e0,
  661. .phy_id_mask = 0xfffffff0,
  662. .name = "BCM5421",
  663. .features = MII_GBIT_FEATURES,
  664. .magic_aneg = 1,
  665. .ops = &bcm5421_phy_ops
  666. };
  667. /* Broadcom BCM 5421 built-in K2 */
  668. static struct mii_phy_ops bcm5421k2_phy_ops = {
  669. .init = bcm5421_init,
  670. .suspend = generic_suspend,
  671. .setup_aneg = bcm54xx_setup_aneg,
  672. .setup_forced = bcm54xx_setup_forced,
  673. .poll_link = genmii_poll_link,
  674. .read_link = bcm54xx_read_link,
  675. };
  676. static struct mii_phy_def bcm5421k2_phy_def = {
  677. .phy_id = 0x002062e0,
  678. .phy_id_mask = 0xfffffff0,
  679. .name = "BCM5421-K2",
  680. .features = MII_GBIT_FEATURES,
  681. .magic_aneg = 1,
  682. .ops = &bcm5421k2_phy_ops
  683. };
  684. static struct mii_phy_ops bcm5461_phy_ops = {
  685. .init = bcm5421_init,
  686. .suspend = generic_suspend,
  687. .setup_aneg = bcm54xx_setup_aneg,
  688. .setup_forced = bcm54xx_setup_forced,
  689. .poll_link = genmii_poll_link,
  690. .read_link = bcm54xx_read_link,
  691. .enable_fiber = bcm5461_enable_fiber,
  692. };
  693. static struct mii_phy_def bcm5461_phy_def = {
  694. .phy_id = 0x002060c0,
  695. .phy_id_mask = 0xfffffff0,
  696. .name = "BCM5461",
  697. .features = MII_GBIT_FEATURES,
  698. .magic_aneg = 1,
  699. .ops = &bcm5461_phy_ops
  700. };
  701. /* Broadcom BCM 5462 built-in Vesta */
  702. static struct mii_phy_ops bcm5462V_phy_ops = {
  703. .init = bcm5421_init,
  704. .suspend = generic_suspend,
  705. .setup_aneg = bcm54xx_setup_aneg,
  706. .setup_forced = bcm54xx_setup_forced,
  707. .poll_link = genmii_poll_link,
  708. .read_link = bcm54xx_read_link,
  709. };
  710. static struct mii_phy_def bcm5462V_phy_def = {
  711. .phy_id = 0x002060d0,
  712. .phy_id_mask = 0xfffffff0,
  713. .name = "BCM5462-Vesta",
  714. .features = MII_GBIT_FEATURES,
  715. .magic_aneg = 1,
  716. .ops = &bcm5462V_phy_ops
  717. };
  718. /* Marvell 88E1101 (Apple seem to deal with 2 different revs,
  719. * I masked out the 8 last bits to get both, but some specs
  720. * would be useful here) --BenH.
  721. */
  722. static struct mii_phy_ops marvell_phy_ops = {
  723. .suspend = generic_suspend,
  724. .setup_aneg = marvell_setup_aneg,
  725. .setup_forced = marvell_setup_forced,
  726. .poll_link = genmii_poll_link,
  727. .read_link = marvell_read_link
  728. };
  729. static struct mii_phy_def marvell_phy_def = {
  730. .phy_id = 0x01410c00,
  731. .phy_id_mask = 0xffffff00,
  732. .name = "Marvell 88E1101",
  733. .features = MII_GBIT_FEATURES,
  734. .magic_aneg = 1,
  735. .ops = &marvell_phy_ops
  736. };
  737. /* Generic implementation for most 10/100 PHYs */
  738. static struct mii_phy_ops generic_phy_ops = {
  739. .setup_aneg = genmii_setup_aneg,
  740. .setup_forced = genmii_setup_forced,
  741. .poll_link = genmii_poll_link,
  742. .read_link = genmii_read_link
  743. };
  744. static struct mii_phy_def genmii_phy_def = {
  745. .phy_id = 0x00000000,
  746. .phy_id_mask = 0x00000000,
  747. .name = "Generic MII",
  748. .features = MII_BASIC_FEATURES,
  749. .magic_aneg = 0,
  750. .ops = &generic_phy_ops
  751. };
  752. static struct mii_phy_def* mii_phy_table[] = {
  753. &bcm5201_phy_def,
  754. &bcm5221_phy_def,
  755. &bcm5400_phy_def,
  756. &bcm5401_phy_def,
  757. &bcm5411_phy_def,
  758. &bcm5421_phy_def,
  759. &bcm5421k2_phy_def,
  760. &bcm5461_phy_def,
  761. &bcm5462V_phy_def,
  762. &marvell_phy_def,
  763. &genmii_phy_def,
  764. NULL
  765. };
  766. int mii_phy_probe(struct mii_phy *phy, int mii_id)
  767. {
  768. int rc;
  769. u32 id;
  770. struct mii_phy_def* def;
  771. int i;
  772. /* We do not reset the mii_phy structure as the driver
  773. * may re-probe the PHY regulary
  774. */
  775. phy->mii_id = mii_id;
  776. /* Take PHY out of isloate mode and reset it. */
  777. rc = reset_one_mii_phy(phy, mii_id);
  778. if (rc)
  779. goto fail;
  780. /* Read ID and find matching entry */
  781. id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
  782. printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
  783. for (i=0; (def = mii_phy_table[i]) != NULL; i++)
  784. if ((id & def->phy_id_mask) == def->phy_id)
  785. break;
  786. /* Should never be NULL (we have a generic entry), but... */
  787. if (def == NULL)
  788. goto fail;
  789. phy->def = def;
  790. return 0;
  791. fail:
  792. phy->speed = 0;
  793. phy->duplex = 0;
  794. phy->pause = 0;
  795. phy->advertising = 0;
  796. return -ENODEV;
  797. }
  798. EXPORT_SYMBOL(mii_phy_probe);
  799. MODULE_LICENSE("GPL");