791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724
  1. From 70479a40954cf353e87a486997a3477108c75aa9 Mon Sep 17 00:00:00 2001
  2. From: Frank <[email protected]>
  3. Date: Fri, 28 Oct 2022 17:26:21 +0800
  4. Subject: [PATCH] net: phy: Add driver for Motorcomm yt8521 gigabit ethernet
  5. phy
  6. Add a driver for the motorcomm yt8521 gigabit ethernet phy. We have verified
  7. the driver on StarFive VisionFive development board, which is developed by
  8. Shanghai StarFive Technology Co., Ltd.. On the board, yt8521 gigabit ethernet
  9. phy works in utp mode, RGMII interface, supports 1000M/100M/10M speeds, and
  10. wol(magic package).
  11. Signed-off-by: Frank <[email protected]>
  12. Reviewed-by: Andrew Lunn <[email protected]>
  13. Signed-off-by: David S. Miller <[email protected]>
  14. ---
  15. MAINTAINERS | 1 +
  16. drivers/net/phy/Kconfig | 2 +-
  17. drivers/net/phy/motorcomm.c | 1635 ++++++++++++++++++++++++++++++++++-
  18. 3 files changed, 1635 insertions(+), 3 deletions(-)
  19. --- a/MAINTAINERS
  20. +++ b/MAINTAINERS
  21. @@ -13964,6 +13964,7 @@ F: include/uapi/linux/meye.h
  22. MOTORCOMM PHY DRIVER
  23. M: Peter Geis <[email protected]>
  24. +M: Frank <[email protected]>
  25. L: [email protected]
  26. S: Maintained
  27. F: drivers/net/phy/motorcomm.c
  28. --- a/drivers/net/phy/Kconfig
  29. +++ b/drivers/net/phy/Kconfig
  30. @@ -257,7 +257,7 @@ config MOTORCOMM_PHY
  31. tristate "Motorcomm PHYs"
  32. help
  33. Enables support for Motorcomm network PHYs.
  34. - Currently supports the YT8511 gigabit PHY.
  35. + Currently supports the YT8511, YT8521 Gigabit Ethernet PHYs.
  36. config NATIONAL_PHY
  37. tristate "National Semiconductor PHYs"
  38. --- a/drivers/net/phy/motorcomm.c
  39. +++ b/drivers/net/phy/motorcomm.c
  40. @@ -1,15 +1,106 @@
  41. // SPDX-License-Identifier: GPL-2.0+
  42. /*
  43. - * Driver for Motorcomm PHYs
  44. + * Motorcomm 8511/8521 PHY driver.
  45. *
  46. * Author: Peter Geis <[email protected]>
  47. + * Author: Frank <[email protected]>
  48. */
  49. +#include <linux/etherdevice.h>
  50. #include <linux/kernel.h>
  51. #include <linux/module.h>
  52. #include <linux/phy.h>
  53. #define PHY_ID_YT8511 0x0000010a
  54. +#define PHY_ID_YT8521 0x0000011A
  55. +
  56. +/* YT8521 Register Overview
  57. + * UTP Register space | FIBER Register space
  58. + * ------------------------------------------------------------
  59. + * | UTP MII | FIBER MII |
  60. + * | UTP MMD | |
  61. + * | UTP Extended | FIBER Extended |
  62. + * ------------------------------------------------------------
  63. + * | Common Extended |
  64. + * ------------------------------------------------------------
  65. + */
  66. +
  67. +/* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */
  68. +
  69. +/* Specific Function Control Register */
  70. +#define YTPHY_SPECIFIC_FUNCTION_CONTROL_REG 0x10
  71. +
  72. +/* 2b00 Manual MDI configuration
  73. + * 2b01 Manual MDIX configuration
  74. + * 2b10 Reserved
  75. + * 2b11 Enable automatic crossover for all modes *default*
  76. + */
  77. +#define YTPHY_SFCR_MDI_CROSSOVER_MODE_MASK (BIT(6) | BIT(5))
  78. +#define YTPHY_SFCR_CROSSOVER_EN BIT(3)
  79. +#define YTPHY_SFCR_SQE_TEST_EN BIT(2)
  80. +#define YTPHY_SFCR_POLARITY_REVERSAL_EN BIT(1)
  81. +#define YTPHY_SFCR_JABBER_DIS BIT(0)
  82. +
  83. +/* Specific Status Register */
  84. +#define YTPHY_SPECIFIC_STATUS_REG 0x11
  85. +#define YTPHY_SSR_SPEED_MODE_OFFSET 14
  86. +
  87. +#define YTPHY_SSR_SPEED_MODE_MASK (BIT(15) | BIT(14))
  88. +#define YTPHY_SSR_SPEED_10M 0x0
  89. +#define YTPHY_SSR_SPEED_100M 0x1
  90. +#define YTPHY_SSR_SPEED_1000M 0x2
  91. +#define YTPHY_SSR_DUPLEX_OFFSET 13
  92. +#define YTPHY_SSR_DUPLEX BIT(13)
  93. +#define YTPHY_SSR_PAGE_RECEIVED BIT(12)
  94. +#define YTPHY_SSR_SPEED_DUPLEX_RESOLVED BIT(11)
  95. +#define YTPHY_SSR_LINK BIT(10)
  96. +#define YTPHY_SSR_MDIX_CROSSOVER BIT(6)
  97. +#define YTPHY_SSR_DOWNGRADE BIT(5)
  98. +#define YTPHY_SSR_TRANSMIT_PAUSE BIT(3)
  99. +#define YTPHY_SSR_RECEIVE_PAUSE BIT(2)
  100. +#define YTPHY_SSR_POLARITY BIT(1)
  101. +#define YTPHY_SSR_JABBER BIT(0)
  102. +
  103. +/* Interrupt enable Register */
  104. +#define YTPHY_INTERRUPT_ENABLE_REG 0x12
  105. +#define YTPHY_IER_WOL BIT(6)
  106. +
  107. +/* Interrupt Status Register */
  108. +#define YTPHY_INTERRUPT_STATUS_REG 0x13
  109. +#define YTPHY_ISR_AUTONEG_ERR BIT(15)
  110. +#define YTPHY_ISR_SPEED_CHANGED BIT(14)
  111. +#define YTPHY_ISR_DUPLEX_CHANGED BIT(13)
  112. +#define YTPHY_ISR_PAGE_RECEIVED BIT(12)
  113. +#define YTPHY_ISR_LINK_FAILED BIT(11)
  114. +#define YTPHY_ISR_LINK_SUCCESSED BIT(10)
  115. +#define YTPHY_ISR_WOL BIT(6)
  116. +#define YTPHY_ISR_WIRESPEED_DOWNGRADE BIT(5)
  117. +#define YTPHY_ISR_SERDES_LINK_FAILED BIT(3)
  118. +#define YTPHY_ISR_SERDES_LINK_SUCCESSED BIT(2)
  119. +#define YTPHY_ISR_POLARITY_CHANGED BIT(1)
  120. +#define YTPHY_ISR_JABBER_HAPPENED BIT(0)
  121. +
  122. +/* Speed Auto Downgrade Control Register */
  123. +#define YTPHY_SPEED_AUTO_DOWNGRADE_CONTROL_REG 0x14
  124. +#define YTPHY_SADCR_SPEED_DOWNGRADE_EN BIT(5)
  125. +
  126. +/* If these bits are set to 3, the PHY attempts five times ( 3(set value) +
  127. + * additional 2) before downgrading, default 0x3
  128. + */
  129. +#define YTPHY_SADCR_SPEED_RETRY_LIMIT (0x3 << 2)
  130. +
  131. +/* Rx Error Counter Register */
  132. +#define YTPHY_RX_ERROR_COUNTER_REG 0x15
  133. +
  134. +/* Extended Register's Address Offset Register */
  135. +#define YTPHY_PAGE_SELECT 0x1E
  136. +
  137. +/* Extended Register's Data Register */
  138. +#define YTPHY_PAGE_DATA 0x1F
  139. +
  140. +/* FIBER Auto-Negotiation link partner ability */
  141. +#define YTPHY_FLPA_PAUSE (0x3 << 7)
  142. +#define YTPHY_FLPA_ASYM_PAUSE (0x2 << 7)
  143. #define YT8511_PAGE_SELECT 0x1e
  144. #define YT8511_PAGE 0x1f
  145. @@ -38,6 +129,352 @@
  146. #define YT8511_DELAY_FE_TX_EN (0xf << 12)
  147. #define YT8511_DELAY_FE_TX_DIS (0x2 << 12)
  148. +/* Extended register is different from MMD Register and MII Register.
  149. + * We can use ytphy_read_ext/ytphy_write_ext/ytphy_modify_ext function to
  150. + * operate extended register.
  151. + * Extended Register start
  152. + */
  153. +
  154. +/* Phy gmii clock gating Register */
  155. +#define YT8521_CLOCK_GATING_REG 0xC
  156. +#define YT8521_CGR_RX_CLK_EN BIT(12)
  157. +
  158. +#define YT8521_EXTREG_SLEEP_CONTROL1_REG 0x27
  159. +#define YT8521_ESC1R_SLEEP_SW BIT(15)
  160. +#define YT8521_ESC1R_PLLON_SLP BIT(14)
  161. +
  162. +/* Phy fiber Link timer cfg2 Register */
  163. +#define YT8521_LINK_TIMER_CFG2_REG 0xA5
  164. +#define YT8521_LTCR_EN_AUTOSEN BIT(15)
  165. +
  166. +/* 0xA000, 0xA001, 0xA003 ,and 0xA006 ~ 0xA00A are common ext registers
  167. + * of yt8521 phy. There is no need to switch reg space when operating these
  168. + * registers.
  169. + */
  170. +
  171. +#define YT8521_REG_SPACE_SELECT_REG 0xA000
  172. +#define YT8521_RSSR_SPACE_MASK BIT(1)
  173. +#define YT8521_RSSR_FIBER_SPACE (0x1 << 1)
  174. +#define YT8521_RSSR_UTP_SPACE (0x0 << 1)
  175. +#define YT8521_RSSR_TO_BE_ARBITRATED (0xFF)
  176. +
  177. +#define YT8521_CHIP_CONFIG_REG 0xA001
  178. +#define YT8521_CCR_SW_RST BIT(15)
  179. +
  180. +#define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0))
  181. +#define YT8521_CCR_MODE_UTP_TO_RGMII 0
  182. +#define YT8521_CCR_MODE_FIBER_TO_RGMII 1
  183. +#define YT8521_CCR_MODE_UTP_FIBER_TO_RGMII 2
  184. +#define YT8521_CCR_MODE_UTP_TO_SGMII 3
  185. +#define YT8521_CCR_MODE_SGPHY_TO_RGMAC 4
  186. +#define YT8521_CCR_MODE_SGMAC_TO_RGPHY 5
  187. +#define YT8521_CCR_MODE_UTP_TO_FIBER_AUTO 6
  188. +#define YT8521_CCR_MODE_UTP_TO_FIBER_FORCE 7
  189. +
  190. +/* 3 phy polling modes,poll mode combines utp and fiber mode*/
  191. +#define YT8521_MODE_FIBER 0x1
  192. +#define YT8521_MODE_UTP 0x2
  193. +#define YT8521_MODE_POLL 0x3
  194. +
  195. +#define YT8521_RGMII_CONFIG1_REG 0xA003
  196. +
  197. +/* TX Gig-E Delay is bits 3:0, default 0x1
  198. + * TX Fast-E Delay is bits 7:4, default 0xf
  199. + * RX Delay is bits 13:10, default 0x0
  200. + * Delay = 150ps * N
  201. + * On = 2250ps, off = 0ps
  202. + */
  203. +#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10)
  204. +#define YT8521_RC1R_RX_DELAY_EN (0xF << 10)
  205. +#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10)
  206. +#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4)
  207. +#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4)
  208. +#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4)
  209. +#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0)
  210. +#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0)
  211. +#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0)
  212. +
  213. +#define YTPHY_MISC_CONFIG_REG 0xA006
  214. +#define YTPHY_MCR_FIBER_SPEED_MASK BIT(0)
  215. +#define YTPHY_MCR_FIBER_1000BX (0x1 << 0)
  216. +#define YTPHY_MCR_FIBER_100FX (0x0 << 0)
  217. +
  218. +/* WOL MAC ADDR: MACADDR2(highest), MACADDR1(middle), MACADDR0(lowest) */
  219. +#define YTPHY_WOL_MACADDR2_REG 0xA007
  220. +#define YTPHY_WOL_MACADDR1_REG 0xA008
  221. +#define YTPHY_WOL_MACADDR0_REG 0xA009
  222. +
  223. +#define YTPHY_WOL_CONFIG_REG 0xA00A
  224. +#define YTPHY_WCR_INTR_SEL BIT(6)
  225. +#define YTPHY_WCR_ENABLE BIT(3)
  226. +
  227. +/* 2b00 84ms
  228. + * 2b01 168ms *default*
  229. + * 2b10 336ms
  230. + * 2b11 672ms
  231. + */
  232. +#define YTPHY_WCR_PULSE_WIDTH_MASK (BIT(2) | BIT(1))
  233. +#define YTPHY_WCR_PULSE_WIDTH_672MS (BIT(2) | BIT(1))
  234. +
  235. +/* 1b0 Interrupt and WOL events is level triggered and active LOW *default*
  236. + * 1b1 Interrupt and WOL events is pulse triggered and active LOW
  237. + */
  238. +#define YTPHY_WCR_TYPE_PULSE BIT(0)
  239. +
  240. +/* Extended Register end */
  241. +
  242. +struct yt8521_priv {
  243. + /* combo_advertising is used for case of YT8521 in combo mode,
  244. + * this means that yt8521 may work in utp or fiber mode which depends
  245. + * on which media is connected (YT8521_RSSR_TO_BE_ARBITRATED).
  246. + */
  247. + __ETHTOOL_DECLARE_LINK_MODE_MASK(combo_advertising);
  248. +
  249. + /* YT8521_MODE_FIBER / YT8521_MODE_UTP / YT8521_MODE_POLL*/
  250. + u8 polling_mode;
  251. + u8 strap_mode; /* 8 working modes */
  252. + /* current reg page of yt8521 phy:
  253. + * YT8521_RSSR_UTP_SPACE
  254. + * YT8521_RSSR_FIBER_SPACE
  255. + * YT8521_RSSR_TO_BE_ARBITRATED
  256. + */
  257. + u8 reg_page;
  258. +};
  259. +
  260. +/**
  261. + * ytphy_read_ext() - read a PHY's extended register
  262. + * @phydev: a pointer to a &struct phy_device
  263. + * @regnum: register number to read
  264. + *
  265. + * NOTE:The caller must have taken the MDIO bus lock.
  266. + *
  267. + * returns the value of regnum reg or negative error code
  268. + */
  269. +static int ytphy_read_ext(struct phy_device *phydev, u16 regnum)
  270. +{
  271. + int ret;
  272. +
  273. + ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
  274. + if (ret < 0)
  275. + return ret;
  276. +
  277. + return __phy_read(phydev, YTPHY_PAGE_DATA);
  278. +}
  279. +
  280. +/**
  281. + * ytphy_read_ext_with_lock() - read a PHY's extended register
  282. + * @phydev: a pointer to a &struct phy_device
  283. + * @regnum: register number to read
  284. + *
  285. + * returns the value of regnum reg or negative error code
  286. + */
  287. +static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)
  288. +{
  289. + int ret;
  290. +
  291. + phy_lock_mdio_bus(phydev);
  292. + ret = ytphy_read_ext(phydev, regnum);
  293. + phy_unlock_mdio_bus(phydev);
  294. +
  295. + return ret;
  296. +}
  297. +
  298. +/**
  299. + * ytphy_write_ext() - write a PHY's extended register
  300. + * @phydev: a pointer to a &struct phy_device
  301. + * @regnum: register number to write
  302. + * @val: value to write to @regnum
  303. + *
  304. + * NOTE:The caller must have taken the MDIO bus lock.
  305. + *
  306. + * returns 0 or negative error code
  307. + */
  308. +static int ytphy_write_ext(struct phy_device *phydev, u16 regnum, u16 val)
  309. +{
  310. + int ret;
  311. +
  312. + ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
  313. + if (ret < 0)
  314. + return ret;
  315. +
  316. + return __phy_write(phydev, YTPHY_PAGE_DATA, val);
  317. +}
  318. +
  319. +/**
  320. + * ytphy_write_ext_with_lock() - write a PHY's extended register
  321. + * @phydev: a pointer to a &struct phy_device
  322. + * @regnum: register number to write
  323. + * @val: value to write to @regnum
  324. + *
  325. + * returns 0 or negative error code
  326. + */
  327. +static int ytphy_write_ext_with_lock(struct phy_device *phydev, u16 regnum,
  328. + u16 val)
  329. +{
  330. + int ret;
  331. +
  332. + phy_lock_mdio_bus(phydev);
  333. + ret = ytphy_write_ext(phydev, regnum, val);
  334. + phy_unlock_mdio_bus(phydev);
  335. +
  336. + return ret;
  337. +}
  338. +
  339. +/**
  340. + * ytphy_modify_ext() - bits modify a PHY's extended register
  341. + * @phydev: a pointer to a &struct phy_device
  342. + * @regnum: register number to write
  343. + * @mask: bit mask of bits to clear
  344. + * @set: bit mask of bits to set
  345. + *
  346. + * NOTE: Convenience function which allows a PHY's extended register to be
  347. + * modified as new register value = (old register value & ~mask) | set.
  348. + * The caller must have taken the MDIO bus lock.
  349. + *
  350. + * returns 0 or negative error code
  351. + */
  352. +static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask,
  353. + u16 set)
  354. +{
  355. + int ret;
  356. +
  357. + ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum);
  358. + if (ret < 0)
  359. + return ret;
  360. +
  361. + return __phy_modify(phydev, YTPHY_PAGE_DATA, mask, set);
  362. +}
  363. +
  364. +/**
  365. + * ytphy_modify_ext_with_lock() - bits modify a PHY's extended register
  366. + * @phydev: a pointer to a &struct phy_device
  367. + * @regnum: register number to write
  368. + * @mask: bit mask of bits to clear
  369. + * @set: bit mask of bits to set
  370. + *
  371. + * NOTE: Convenience function which allows a PHY's extended register to be
  372. + * modified as new register value = (old register value & ~mask) | set.
  373. + *
  374. + * returns 0 or negative error code
  375. + */
  376. +static int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum,
  377. + u16 mask, u16 set)
  378. +{
  379. + int ret;
  380. +
  381. + phy_lock_mdio_bus(phydev);
  382. + ret = ytphy_modify_ext(phydev, regnum, mask, set);
  383. + phy_unlock_mdio_bus(phydev);
  384. +
  385. + return ret;
  386. +}
  387. +
  388. +/**
  389. + * ytphy_get_wol() - report whether wake-on-lan is enabled
  390. + * @phydev: a pointer to a &struct phy_device
  391. + * @wol: a pointer to a &struct ethtool_wolinfo
  392. + *
  393. + * NOTE: YTPHY_WOL_CONFIG_REG is common ext reg.
  394. + */
  395. +static void ytphy_get_wol(struct phy_device *phydev,
  396. + struct ethtool_wolinfo *wol)
  397. +{
  398. + int wol_config;
  399. +
  400. + wol->supported = WAKE_MAGIC;
  401. + wol->wolopts = 0;
  402. +
  403. + wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
  404. + if (wol_config < 0)
  405. + return;
  406. +
  407. + if (wol_config & YTPHY_WCR_ENABLE)
  408. + wol->wolopts |= WAKE_MAGIC;
  409. +}
  410. +
  411. +/**
  412. + * ytphy_set_wol() - turn wake-on-lan on or off
  413. + * @phydev: a pointer to a &struct phy_device
  414. + * @wol: a pointer to a &struct ethtool_wolinfo
  415. + *
  416. + * NOTE: YTPHY_WOL_CONFIG_REG, YTPHY_WOL_MACADDR2_REG, YTPHY_WOL_MACADDR1_REG
  417. + * and YTPHY_WOL_MACADDR0_REG are common ext reg. The
  418. + * YTPHY_INTERRUPT_ENABLE_REG of UTP is special, fiber also use this register.
  419. + *
  420. + * returns 0 or negative errno code
  421. + */
  422. +static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
  423. +{
  424. + struct net_device *p_attached_dev;
  425. + const u16 mac_addr_reg[] = {
  426. + YTPHY_WOL_MACADDR2_REG,
  427. + YTPHY_WOL_MACADDR1_REG,
  428. + YTPHY_WOL_MACADDR0_REG,
  429. + };
  430. + const u8 *mac_addr;
  431. + int old_page;
  432. + int ret = 0;
  433. + u16 mask;
  434. + u16 val;
  435. + u8 i;
  436. +
  437. + if (wol->wolopts & WAKE_MAGIC) {
  438. + p_attached_dev = phydev->attached_dev;
  439. + if (!p_attached_dev)
  440. + return -ENODEV;
  441. +
  442. + mac_addr = (const u8 *)p_attached_dev->dev_addr;
  443. + if (!is_valid_ether_addr(mac_addr))
  444. + return -EINVAL;
  445. +
  446. + /* lock mdio bus then switch to utp reg space */
  447. + old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
  448. + if (old_page < 0)
  449. + goto err_restore_page;
  450. +
  451. + /* Store the device address for the magic packet */
  452. + for (i = 0; i < 3; i++) {
  453. + ret = ytphy_write_ext(phydev, mac_addr_reg[i],
  454. + ((mac_addr[i * 2] << 8)) |
  455. + (mac_addr[i * 2 + 1]));
  456. + if (ret < 0)
  457. + goto err_restore_page;
  458. + }
  459. +
  460. + /* Enable WOL feature */
  461. + mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;
  462. + val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
  463. + val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;
  464. + ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, val);
  465. + if (ret < 0)
  466. + goto err_restore_page;
  467. +
  468. + /* Enable WOL interrupt */
  469. + ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,
  470. + YTPHY_IER_WOL);
  471. + if (ret < 0)
  472. + goto err_restore_page;
  473. +
  474. + } else {
  475. + old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
  476. + if (old_page < 0)
  477. + goto err_restore_page;
  478. +
  479. + /* Disable WOL feature */
  480. + mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
  481. + ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0);
  482. +
  483. + /* Disable WOL interrupt */
  484. + ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
  485. + YTPHY_IER_WOL, 0);
  486. + if (ret < 0)
  487. + goto err_restore_page;
  488. + }
  489. +
  490. +err_restore_page:
  491. + return phy_restore_page(phydev, old_page, ret);
  492. +}
  493. +
  494. static int yt8511_read_page(struct phy_device *phydev)
  495. {
  496. return __phy_read(phydev, YT8511_PAGE_SELECT);
  497. @@ -111,6 +548,1181 @@ err_restore_page:
  498. return phy_restore_page(phydev, oldpage, ret);
  499. }
  500. +/**
  501. + * yt8521_read_page() - read reg page
  502. + * @phydev: a pointer to a &struct phy_device
  503. + *
  504. + * returns current reg space of yt8521 (YT8521_RSSR_FIBER_SPACE/
  505. + * YT8521_RSSR_UTP_SPACE) or negative errno code
  506. + */
  507. +static int yt8521_read_page(struct phy_device *phydev)
  508. +{
  509. + int old_page;
  510. +
  511. + old_page = ytphy_read_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
  512. + if (old_page < 0)
  513. + return old_page;
  514. +
  515. + if ((old_page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE)
  516. + return YT8521_RSSR_FIBER_SPACE;
  517. +
  518. + return YT8521_RSSR_UTP_SPACE;
  519. +};
  520. +
  521. +/**
  522. + * yt8521_write_page() - write reg page
  523. + * @phydev: a pointer to a &struct phy_device
  524. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to write.
  525. + *
  526. + * returns 0 or negative errno code
  527. + */
  528. +static int yt8521_write_page(struct phy_device *phydev, int page)
  529. +{
  530. + int mask = YT8521_RSSR_SPACE_MASK;
  531. + int set;
  532. +
  533. + if ((page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE)
  534. + set = YT8521_RSSR_FIBER_SPACE;
  535. + else
  536. + set = YT8521_RSSR_UTP_SPACE;
  537. +
  538. + return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set);
  539. +};
  540. +
  541. +/**
  542. + * yt8521_probe() - read chip config then set suitable polling_mode
  543. + * @phydev: a pointer to a &struct phy_device
  544. + *
  545. + * returns 0 or negative errno code
  546. + */
  547. +static int yt8521_probe(struct phy_device *phydev)
  548. +{
  549. + struct device *dev = &phydev->mdio.dev;
  550. + struct yt8521_priv *priv;
  551. + int chip_config;
  552. + int ret;
  553. +
  554. + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  555. + if (!priv)
  556. + return -ENOMEM;
  557. +
  558. + phydev->priv = priv;
  559. +
  560. + chip_config = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
  561. + if (chip_config < 0)
  562. + return chip_config;
  563. +
  564. + priv->strap_mode = chip_config & YT8521_CCR_MODE_SEL_MASK;
  565. + switch (priv->strap_mode) {
  566. + case YT8521_CCR_MODE_FIBER_TO_RGMII:
  567. + case YT8521_CCR_MODE_SGPHY_TO_RGMAC:
  568. + case YT8521_CCR_MODE_SGMAC_TO_RGPHY:
  569. + priv->polling_mode = YT8521_MODE_FIBER;
  570. + priv->reg_page = YT8521_RSSR_FIBER_SPACE;
  571. + phydev->port = PORT_FIBRE;
  572. + break;
  573. + case YT8521_CCR_MODE_UTP_FIBER_TO_RGMII:
  574. + case YT8521_CCR_MODE_UTP_TO_FIBER_AUTO:
  575. + case YT8521_CCR_MODE_UTP_TO_FIBER_FORCE:
  576. + priv->polling_mode = YT8521_MODE_POLL;
  577. + priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED;
  578. + phydev->port = PORT_NONE;
  579. + break;
  580. + case YT8521_CCR_MODE_UTP_TO_SGMII:
  581. + case YT8521_CCR_MODE_UTP_TO_RGMII:
  582. + priv->polling_mode = YT8521_MODE_UTP;
  583. + priv->reg_page = YT8521_RSSR_UTP_SPACE;
  584. + phydev->port = PORT_TP;
  585. + break;
  586. + }
  587. + /* set default reg space */
  588. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  589. + ret = ytphy_write_ext_with_lock(phydev,
  590. + YT8521_REG_SPACE_SELECT_REG,
  591. + priv->reg_page);
  592. + if (ret < 0)
  593. + return ret;
  594. + }
  595. +
  596. + return 0;
  597. +}
  598. +
  599. +/**
  600. + * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
  601. + * @phydev: a pointer to a &struct phy_device
  602. + *
  603. + * NOTE:The caller must have taken the MDIO bus lock.
  604. + *
  605. + * returns 0 or negative errno code
  606. + */
  607. +static int ytphy_utp_read_lpa(struct phy_device *phydev)
  608. +{
  609. + int lpa, lpagb;
  610. +
  611. + if (phydev->autoneg == AUTONEG_ENABLE) {
  612. + if (!phydev->autoneg_complete) {
  613. + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
  614. + 0);
  615. + mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
  616. + return 0;
  617. + }
  618. +
  619. + if (phydev->is_gigabit_capable) {
  620. + lpagb = __phy_read(phydev, MII_STAT1000);
  621. + if (lpagb < 0)
  622. + return lpagb;
  623. +
  624. + if (lpagb & LPA_1000MSFAIL) {
  625. + int adv = __phy_read(phydev, MII_CTRL1000);
  626. +
  627. + if (adv < 0)
  628. + return adv;
  629. +
  630. + if (adv & CTL1000_ENABLE_MASTER)
  631. + phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n");
  632. + else
  633. + phydev_err(phydev, "Master/Slave resolution failed\n");
  634. + return -ENOLINK;
  635. + }
  636. +
  637. + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
  638. + lpagb);
  639. + }
  640. +
  641. + lpa = __phy_read(phydev, MII_LPA);
  642. + if (lpa < 0)
  643. + return lpa;
  644. +
  645. + mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
  646. + } else {
  647. + linkmode_zero(phydev->lp_advertising);
  648. + }
  649. +
  650. + return 0;
  651. +}
  652. +
  653. +/**
  654. + * yt8521_adjust_status() - update speed and duplex to phydev. when in fiber
  655. + * mode, adjust speed and duplex.
  656. + * @phydev: a pointer to a &struct phy_device
  657. + * @status: yt8521 status read from YTPHY_SPECIFIC_STATUS_REG
  658. + * @is_utp: false(yt8521 work in fiber mode) or true(yt8521 work in utp mode)
  659. + *
  660. + * NOTE:The caller must have taken the MDIO bus lock.
  661. + *
  662. + * returns 0
  663. + */
  664. +static int yt8521_adjust_status(struct phy_device *phydev, int status,
  665. + bool is_utp)
  666. +{
  667. + int speed_mode, duplex;
  668. + int speed;
  669. + int err;
  670. + int lpa;
  671. +
  672. + if (is_utp)
  673. + duplex = (status & YTPHY_SSR_DUPLEX) >> YTPHY_SSR_DUPLEX_OFFSET;
  674. + else
  675. + duplex = DUPLEX_FULL; /* for fiber, it always DUPLEX_FULL */
  676. +
  677. + speed_mode = (status & YTPHY_SSR_SPEED_MODE_MASK) >>
  678. + YTPHY_SSR_SPEED_MODE_OFFSET;
  679. +
  680. + switch (speed_mode) {
  681. + case YTPHY_SSR_SPEED_10M:
  682. + if (is_utp)
  683. + speed = SPEED_10;
  684. + else
  685. + /* for fiber, it will never run here, default to
  686. + * SPEED_UNKNOWN
  687. + */
  688. + speed = SPEED_UNKNOWN;
  689. + break;
  690. + case YTPHY_SSR_SPEED_100M:
  691. + speed = SPEED_100;
  692. + break;
  693. + case YTPHY_SSR_SPEED_1000M:
  694. + speed = SPEED_1000;
  695. + break;
  696. + default:
  697. + speed = SPEED_UNKNOWN;
  698. + break;
  699. + }
  700. +
  701. + phydev->speed = speed;
  702. + phydev->duplex = duplex;
  703. +
  704. + if (is_utp) {
  705. + err = ytphy_utp_read_lpa(phydev);
  706. + if (err < 0)
  707. + return err;
  708. +
  709. + phy_resolve_aneg_pause(phydev);
  710. + } else {
  711. + lpa = __phy_read(phydev, MII_LPA);
  712. + if (lpa < 0)
  713. + return lpa;
  714. +
  715. + /* only support 1000baseX Full */
  716. + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
  717. + phydev->lp_advertising, lpa & LPA_1000XFULL);
  718. +
  719. + if (!(lpa & YTPHY_FLPA_PAUSE)) {
  720. + phydev->pause = 0;
  721. + phydev->asym_pause = 0;
  722. + } else if ((lpa & YTPHY_FLPA_ASYM_PAUSE)) {
  723. + phydev->pause = 1;
  724. + phydev->asym_pause = 1;
  725. + } else {
  726. + phydev->pause = 1;
  727. + phydev->asym_pause = 0;
  728. + }
  729. + }
  730. +
  731. + return 0;
  732. +}
  733. +
  734. +/**
  735. + * yt8521_read_status_paged() - determines the speed and duplex of one page
  736. + * @phydev: a pointer to a &struct phy_device
  737. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
  738. + * operate.
  739. + *
  740. + * returns 1 (utp or fiber link),0 (no link) or negative errno code
  741. + */
  742. +static int yt8521_read_status_paged(struct phy_device *phydev, int page)
  743. +{
  744. + int fiber_latch_val;
  745. + int fiber_curr_val;
  746. + int old_page;
  747. + int ret = 0;
  748. + int status;
  749. + int link;
  750. +
  751. + linkmode_zero(phydev->lp_advertising);
  752. + phydev->duplex = DUPLEX_UNKNOWN;
  753. + phydev->speed = SPEED_UNKNOWN;
  754. + phydev->asym_pause = 0;
  755. + phydev->pause = 0;
  756. +
  757. + /* YT8521 has two reg space (utp/fiber) for linkup with utp/fiber
  758. + * respectively. but for utp/fiber combo mode, reg space should be
  759. + * arbitrated based on media priority. by default, utp takes
  760. + * priority. reg space should be properly set before read
  761. + * YTPHY_SPECIFIC_STATUS_REG.
  762. + */
  763. +
  764. + page &= YT8521_RSSR_SPACE_MASK;
  765. + old_page = phy_select_page(phydev, page);
  766. + if (old_page < 0)
  767. + goto err_restore_page;
  768. +
  769. + /* Read YTPHY_SPECIFIC_STATUS_REG, which indicates the speed and duplex
  770. + * of the PHY is actually using.
  771. + */
  772. + ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
  773. + if (ret < 0)
  774. + goto err_restore_page;
  775. +
  776. + status = ret;
  777. + link = !!(status & YTPHY_SSR_LINK);
  778. +
  779. + /* When PHY is in fiber mode, speed transferred from 1000Mbps to
  780. + * 100Mbps,there is not link down from YTPHY_SPECIFIC_STATUS_REG, so
  781. + * we need check MII_BMSR to identify such case.
  782. + */
  783. + if (page == YT8521_RSSR_FIBER_SPACE) {
  784. + ret = __phy_read(phydev, MII_BMSR);
  785. + if (ret < 0)
  786. + goto err_restore_page;
  787. +
  788. + fiber_latch_val = ret;
  789. + ret = __phy_read(phydev, MII_BMSR);
  790. + if (ret < 0)
  791. + goto err_restore_page;
  792. +
  793. + fiber_curr_val = ret;
  794. + if (link && fiber_latch_val != fiber_curr_val) {
  795. + link = 0;
  796. + phydev_info(phydev,
  797. + "%s, fiber link down detect, latch = %04x, curr = %04x\n",
  798. + __func__, fiber_latch_val, fiber_curr_val);
  799. + }
  800. + } else {
  801. + /* Read autonegotiation status */
  802. + ret = __phy_read(phydev, MII_BMSR);
  803. + if (ret < 0)
  804. + goto err_restore_page;
  805. +
  806. + phydev->autoneg_complete = ret & BMSR_ANEGCOMPLETE ? 1 : 0;
  807. + }
  808. +
  809. + if (link) {
  810. + if (page == YT8521_RSSR_UTP_SPACE)
  811. + yt8521_adjust_status(phydev, status, true);
  812. + else
  813. + yt8521_adjust_status(phydev, status, false);
  814. + }
  815. + return phy_restore_page(phydev, old_page, link);
  816. +
  817. +err_restore_page:
  818. + return phy_restore_page(phydev, old_page, ret);
  819. +}
  820. +
  821. +/**
  822. + * yt8521_read_status() - determines the negotiated speed and duplex
  823. + * @phydev: a pointer to a &struct phy_device
  824. + *
  825. + * returns 0 or negative errno code
  826. + */
  827. +static int yt8521_read_status(struct phy_device *phydev)
  828. +{
  829. + struct yt8521_priv *priv = phydev->priv;
  830. + int link_fiber = 0;
  831. + int link_utp;
  832. + int link;
  833. + int ret;
  834. +
  835. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  836. + link = yt8521_read_status_paged(phydev, priv->reg_page);
  837. + if (link < 0)
  838. + return link;
  839. + } else {
  840. + /* when page is YT8521_RSSR_TO_BE_ARBITRATED, arbitration is
  841. + * needed. by default, utp is higher priority.
  842. + */
  843. +
  844. + link_utp = yt8521_read_status_paged(phydev,
  845. + YT8521_RSSR_UTP_SPACE);
  846. + if (link_utp < 0)
  847. + return link_utp;
  848. +
  849. + if (!link_utp) {
  850. + link_fiber = yt8521_read_status_paged(phydev,
  851. + YT8521_RSSR_FIBER_SPACE);
  852. + if (link_fiber < 0)
  853. + return link_fiber;
  854. + }
  855. +
  856. + link = link_utp || link_fiber;
  857. + }
  858. +
  859. + if (link) {
  860. + if (phydev->link == 0) {
  861. + /* arbitrate reg space based on linkup media type. */
  862. + if (priv->polling_mode == YT8521_MODE_POLL &&
  863. + priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) {
  864. + if (link_fiber)
  865. + priv->reg_page =
  866. + YT8521_RSSR_FIBER_SPACE;
  867. + else
  868. + priv->reg_page = YT8521_RSSR_UTP_SPACE;
  869. +
  870. + ret = ytphy_write_ext_with_lock(phydev,
  871. + YT8521_REG_SPACE_SELECT_REG,
  872. + priv->reg_page);
  873. + if (ret < 0)
  874. + return ret;
  875. +
  876. + phydev->port = link_fiber ? PORT_FIBRE : PORT_TP;
  877. +
  878. + phydev_info(phydev, "%s, link up, media: %s\n",
  879. + __func__,
  880. + (phydev->port == PORT_TP) ?
  881. + "UTP" : "Fiber");
  882. + }
  883. + }
  884. + phydev->link = 1;
  885. + } else {
  886. + if (phydev->link == 1) {
  887. + phydev_info(phydev, "%s, link down, media: %s\n",
  888. + __func__, (phydev->port == PORT_TP) ?
  889. + "UTP" : "Fiber");
  890. +
  891. + /* When in YT8521_MODE_POLL mode, need prepare for next
  892. + * arbitration.
  893. + */
  894. + if (priv->polling_mode == YT8521_MODE_POLL) {
  895. + priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED;
  896. + phydev->port = PORT_NONE;
  897. + }
  898. + }
  899. +
  900. + phydev->link = 0;
  901. + }
  902. +
  903. + return 0;
  904. +}
  905. +
  906. +/**
  907. + * yt8521_modify_bmcr_paged - bits modify a PHY's BMCR register of one page
  908. + * @phydev: the phy_device struct
  909. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to operate
  910. + * @mask: bit mask of bits to clear
  911. + * @set: bit mask of bits to set
  912. + *
  913. + * NOTE: Convenience function which allows a PHY's BMCR register to be
  914. + * modified as new register value = (old register value & ~mask) | set.
  915. + * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space
  916. + * has MII_BMCR. poll mode combines utp and faber,so need do both.
  917. + * If it is reset, it will wait for completion.
  918. + *
  919. + * returns 0 or negative errno code
  920. + */
  921. +static int yt8521_modify_bmcr_paged(struct phy_device *phydev, int page,
  922. + u16 mask, u16 set)
  923. +{
  924. + int max_cnt = 500; /* the max wait time of reset ~ 500 ms */
  925. + int old_page;
  926. + int ret = 0;
  927. +
  928. + old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK);
  929. + if (old_page < 0)
  930. + goto err_restore_page;
  931. +
  932. + ret = __phy_modify(phydev, MII_BMCR, mask, set);
  933. + if (ret < 0)
  934. + goto err_restore_page;
  935. +
  936. + /* If it is reset, need to wait for the reset to complete */
  937. + if (set == BMCR_RESET) {
  938. + while (max_cnt--) {
  939. + usleep_range(1000, 1100);
  940. + ret = __phy_read(phydev, MII_BMCR);
  941. + if (ret < 0)
  942. + goto err_restore_page;
  943. +
  944. + if (!(ret & BMCR_RESET))
  945. + return phy_restore_page(phydev, old_page, 0);
  946. + }
  947. + }
  948. +
  949. +err_restore_page:
  950. + return phy_restore_page(phydev, old_page, ret);
  951. +}
  952. +
  953. +/**
  954. + * yt8521_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register
  955. + * @phydev: the phy_device struct
  956. + * @mask: bit mask of bits to clear
  957. + * @set: bit mask of bits to set
  958. + *
  959. + * NOTE: Convenience function which allows a PHY's BMCR register to be
  960. + * modified as new register value = (old register value & ~mask) | set.
  961. + * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space
  962. + * has MII_BMCR. poll mode combines utp and faber,so need do both.
  963. + *
  964. + * returns 0 or negative errno code
  965. + */
  966. +static int yt8521_modify_utp_fiber_bmcr(struct phy_device *phydev, u16 mask,
  967. + u16 set)
  968. +{
  969. + struct yt8521_priv *priv = phydev->priv;
  970. + int ret;
  971. +
  972. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  973. + ret = yt8521_modify_bmcr_paged(phydev, priv->reg_page, mask,
  974. + set);
  975. + if (ret < 0)
  976. + return ret;
  977. + } else {
  978. + ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_UTP_SPACE,
  979. + mask, set);
  980. + if (ret < 0)
  981. + return ret;
  982. +
  983. + ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_FIBER_SPACE,
  984. + mask, set);
  985. + if (ret < 0)
  986. + return ret;
  987. + }
  988. + return 0;
  989. +}
  990. +
  991. +/**
  992. + * yt8521_soft_reset() - called to issue a PHY software reset
  993. + * @phydev: a pointer to a &struct phy_device
  994. + *
  995. + * returns 0 or negative errno code
  996. + */
  997. +static int yt8521_soft_reset(struct phy_device *phydev)
  998. +{
  999. + return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_RESET);
  1000. +}
  1001. +
  1002. +/**
  1003. + * yt8521_suspend() - suspend the hardware
  1004. + * @phydev: a pointer to a &struct phy_device
  1005. + *
  1006. + * returns 0 or negative errno code
  1007. + */
  1008. +static int yt8521_suspend(struct phy_device *phydev)
  1009. +{
  1010. + int wol_config;
  1011. +
  1012. + /* YTPHY_WOL_CONFIG_REG is common ext reg */
  1013. + wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
  1014. + if (wol_config < 0)
  1015. + return wol_config;
  1016. +
  1017. + /* if wol enable, do nothing */
  1018. + if (wol_config & YTPHY_WCR_ENABLE)
  1019. + return 0;
  1020. +
  1021. + return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_PDOWN);
  1022. +}
  1023. +
  1024. +/**
  1025. + * yt8521_resume() - resume the hardware
  1026. + * @phydev: a pointer to a &struct phy_device
  1027. + *
  1028. + * returns 0 or negative errno code
  1029. + */
  1030. +static int yt8521_resume(struct phy_device *phydev)
  1031. +{
  1032. + int ret;
  1033. + int wol_config;
  1034. +
  1035. + /* disable auto sleep */
  1036. + ret = ytphy_modify_ext_with_lock(phydev,
  1037. + YT8521_EXTREG_SLEEP_CONTROL1_REG,
  1038. + YT8521_ESC1R_SLEEP_SW, 0);
  1039. + if (ret < 0)
  1040. + return ret;
  1041. +
  1042. + wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG);
  1043. + if (wol_config < 0)
  1044. + return wol_config;
  1045. +
  1046. + /* if wol enable, do nothing */
  1047. + if (wol_config & YTPHY_WCR_ENABLE)
  1048. + return 0;
  1049. +
  1050. + return yt8521_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
  1051. +}
  1052. +
  1053. +/**
  1054. + * yt8521_config_init() - called to initialize the PHY
  1055. + * @phydev: a pointer to a &struct phy_device
  1056. + *
  1057. + * returns 0 or negative errno code
  1058. + */
  1059. +static int yt8521_config_init(struct phy_device *phydev)
  1060. +{
  1061. + int old_page;
  1062. + int ret = 0;
  1063. + u16 val;
  1064. +
  1065. + old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
  1066. + if (old_page < 0)
  1067. + goto err_restore_page;
  1068. +
  1069. + switch (phydev->interface) {
  1070. + case PHY_INTERFACE_MODE_RGMII:
  1071. + val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS;
  1072. + val |= YT8521_RC1R_RX_DELAY_DIS;
  1073. + break;
  1074. + case PHY_INTERFACE_MODE_RGMII_RXID:
  1075. + val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS;
  1076. + val |= YT8521_RC1R_RX_DELAY_EN;
  1077. + break;
  1078. + case PHY_INTERFACE_MODE_RGMII_TXID:
  1079. + val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN;
  1080. + val |= YT8521_RC1R_RX_DELAY_DIS;
  1081. + break;
  1082. + case PHY_INTERFACE_MODE_RGMII_ID:
  1083. + val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN;
  1084. + val |= YT8521_RC1R_RX_DELAY_EN;
  1085. + break;
  1086. + case PHY_INTERFACE_MODE_SGMII:
  1087. + break;
  1088. + default: /* do not support other modes */
  1089. + ret = -EOPNOTSUPP;
  1090. + goto err_restore_page;
  1091. + }
  1092. +
  1093. + /* set rgmii delay mode */
  1094. + if (phydev->interface != PHY_INTERFACE_MODE_SGMII) {
  1095. + ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG,
  1096. + (YT8521_RC1R_RX_DELAY_MASK |
  1097. + YT8521_RC1R_FE_TX_DELAY_MASK |
  1098. + YT8521_RC1R_GE_TX_DELAY_MASK),
  1099. + val);
  1100. + if (ret < 0)
  1101. + goto err_restore_page;
  1102. + }
  1103. +
  1104. + /* disable auto sleep */
  1105. + ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
  1106. + YT8521_ESC1R_SLEEP_SW, 0);
  1107. + if (ret < 0)
  1108. + goto err_restore_page;
  1109. +
  1110. + /* enable RXC clock when no wire plug */
  1111. + ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
  1112. + YT8521_CGR_RX_CLK_EN, 0);
  1113. + if (ret < 0)
  1114. + goto err_restore_page;
  1115. +
  1116. +err_restore_page:
  1117. + return phy_restore_page(phydev, old_page, ret);
  1118. +}
  1119. +
  1120. +/**
  1121. + * yt8521_prepare_fiber_features() - A small helper function that setup
  1122. + * fiber's features.
  1123. + * @phydev: a pointer to a &struct phy_device
  1124. + * @dst: a pointer to store fiber's features
  1125. + */
  1126. +static void yt8521_prepare_fiber_features(struct phy_device *phydev,
  1127. + unsigned long *dst)
  1128. +{
  1129. + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, dst);
  1130. + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, dst);
  1131. + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, dst);
  1132. + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, dst);
  1133. +}
  1134. +
  1135. +/**
  1136. + * yt8521_fiber_setup_forced - configures/forces speed from @phydev
  1137. + * @phydev: target phy_device struct
  1138. + *
  1139. + * NOTE:The caller must have taken the MDIO bus lock.
  1140. + *
  1141. + * returns 0 or negative errno code
  1142. + */
  1143. +static int yt8521_fiber_setup_forced(struct phy_device *phydev)
  1144. +{
  1145. + u16 val;
  1146. + int ret;
  1147. +
  1148. + if (phydev->speed == SPEED_1000)
  1149. + val = YTPHY_MCR_FIBER_1000BX;
  1150. + else if (phydev->speed == SPEED_100)
  1151. + val = YTPHY_MCR_FIBER_100FX;
  1152. + else
  1153. + return -EINVAL;
  1154. +
  1155. + ret = __phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
  1156. + if (ret < 0)
  1157. + return ret;
  1158. +
  1159. + /* disable Fiber auto sensing */
  1160. + ret = ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG,
  1161. + YT8521_LTCR_EN_AUTOSEN, 0);
  1162. + if (ret < 0)
  1163. + return ret;
  1164. +
  1165. + ret = ytphy_modify_ext(phydev, YTPHY_MISC_CONFIG_REG,
  1166. + YTPHY_MCR_FIBER_SPEED_MASK, val);
  1167. + if (ret < 0)
  1168. + return ret;
  1169. +
  1170. + return ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
  1171. + YT8521_CCR_SW_RST, 0);
  1172. +}
  1173. +
  1174. +/**
  1175. + * ytphy_check_and_restart_aneg - Enable and restart auto-negotiation
  1176. + * @phydev: target phy_device struct
  1177. + * @restart: whether aneg restart is requested
  1178. + *
  1179. + * NOTE:The caller must have taken the MDIO bus lock.
  1180. + *
  1181. + * returns 0 or negative errno code
  1182. + */
  1183. +static int ytphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
  1184. +{
  1185. + int ret;
  1186. +
  1187. + if (!restart) {
  1188. + /* Advertisement hasn't changed, but maybe aneg was never on to
  1189. + * begin with? Or maybe phy was isolated?
  1190. + */
  1191. + ret = __phy_read(phydev, MII_BMCR);
  1192. + if (ret < 0)
  1193. + return ret;
  1194. +
  1195. + if (!(ret & BMCR_ANENABLE) || (ret & BMCR_ISOLATE))
  1196. + restart = true;
  1197. + }
  1198. + /* Enable and Restart Autonegotiation
  1199. + * Don't isolate the PHY if we're negotiating
  1200. + */
  1201. + if (restart)
  1202. + return __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE,
  1203. + BMCR_ANENABLE | BMCR_ANRESTART);
  1204. +
  1205. + return 0;
  1206. +}
  1207. +
  1208. +/**
  1209. + * yt8521_fiber_config_aneg - restart auto-negotiation or write
  1210. + * YTPHY_MISC_CONFIG_REG.
  1211. + * @phydev: target phy_device struct
  1212. + *
  1213. + * NOTE:The caller must have taken the MDIO bus lock.
  1214. + *
  1215. + * returns 0 or negative errno code
  1216. + */
  1217. +static int yt8521_fiber_config_aneg(struct phy_device *phydev)
  1218. +{
  1219. + int err, changed = 0;
  1220. + int bmcr;
  1221. + u16 adv;
  1222. +
  1223. + if (phydev->autoneg != AUTONEG_ENABLE)
  1224. + return yt8521_fiber_setup_forced(phydev);
  1225. +
  1226. + /* enable Fiber auto sensing */
  1227. + err = ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG,
  1228. + 0, YT8521_LTCR_EN_AUTOSEN);
  1229. + if (err < 0)
  1230. + return err;
  1231. +
  1232. + err = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
  1233. + YT8521_CCR_SW_RST, 0);
  1234. + if (err < 0)
  1235. + return err;
  1236. +
  1237. + bmcr = __phy_read(phydev, MII_BMCR);
  1238. + if (bmcr < 0)
  1239. + return bmcr;
  1240. +
  1241. + /* When it is coming from fiber forced mode, add bmcr power down
  1242. + * and power up to let aneg work fine.
  1243. + */
  1244. + if (!(bmcr & BMCR_ANENABLE)) {
  1245. + __phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
  1246. + usleep_range(1000, 1100);
  1247. + __phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
  1248. + }
  1249. +
  1250. + adv = linkmode_adv_to_mii_adv_x(phydev->advertising,
  1251. + ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
  1252. +
  1253. + /* Setup fiber advertisement */
  1254. + err = __phy_modify_changed(phydev, MII_ADVERTISE,
  1255. + ADVERTISE_1000XHALF | ADVERTISE_1000XFULL |
  1256. + ADVERTISE_1000XPAUSE |
  1257. + ADVERTISE_1000XPSE_ASYM,
  1258. + adv);
  1259. + if (err < 0)
  1260. + return err;
  1261. +
  1262. + if (err > 0)
  1263. + changed = 1;
  1264. +
  1265. + return ytphy_check_and_restart_aneg(phydev, changed);
  1266. +}
  1267. +
  1268. +/**
  1269. + * ytphy_setup_master_slave
  1270. + * @phydev: target phy_device struct
  1271. + *
  1272. + * NOTE: The caller must have taken the MDIO bus lock.
  1273. + *
  1274. + * returns 0 or negative errno code
  1275. + */
  1276. +static int ytphy_setup_master_slave(struct phy_device *phydev)
  1277. +{
  1278. + u16 ctl = 0;
  1279. +
  1280. + if (!phydev->is_gigabit_capable)
  1281. + return 0;
  1282. +
  1283. + switch (phydev->master_slave_set) {
  1284. + case MASTER_SLAVE_CFG_MASTER_PREFERRED:
  1285. + ctl |= CTL1000_PREFER_MASTER;
  1286. + break;
  1287. + case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
  1288. + break;
  1289. + case MASTER_SLAVE_CFG_MASTER_FORCE:
  1290. + ctl |= CTL1000_AS_MASTER;
  1291. + fallthrough;
  1292. + case MASTER_SLAVE_CFG_SLAVE_FORCE:
  1293. + ctl |= CTL1000_ENABLE_MASTER;
  1294. + break;
  1295. + case MASTER_SLAVE_CFG_UNKNOWN:
  1296. + case MASTER_SLAVE_CFG_UNSUPPORTED:
  1297. + return 0;
  1298. + default:
  1299. + phydev_warn(phydev, "Unsupported Master/Slave mode\n");
  1300. + return -EOPNOTSUPP;
  1301. + }
  1302. +
  1303. + return __phy_modify_changed(phydev, MII_CTRL1000,
  1304. + (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER |
  1305. + CTL1000_PREFER_MASTER), ctl);
  1306. +}
  1307. +
  1308. +/**
  1309. + * ytphy_utp_config_advert - sanitize and advertise auto-negotiation parameters
  1310. + * @phydev: target phy_device struct
  1311. + *
  1312. + * NOTE: Writes MII_ADVERTISE with the appropriate values,
  1313. + * after sanitizing the values to make sure we only advertise
  1314. + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
  1315. + * hasn't changed, and > 0 if it has changed.
  1316. + * The caller must have taken the MDIO bus lock.
  1317. + *
  1318. + * returns 0 or negative errno code
  1319. + */
  1320. +static int ytphy_utp_config_advert(struct phy_device *phydev)
  1321. +{
  1322. + int err, bmsr, changed = 0;
  1323. + u32 adv;
  1324. +
  1325. + /* Only allow advertising what this PHY supports */
  1326. + linkmode_and(phydev->advertising, phydev->advertising,
  1327. + phydev->supported);
  1328. +
  1329. + adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
  1330. +
  1331. + /* Setup standard advertisement */
  1332. + err = __phy_modify_changed(phydev, MII_ADVERTISE,
  1333. + ADVERTISE_ALL | ADVERTISE_100BASE4 |
  1334. + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
  1335. + adv);
  1336. + if (err < 0)
  1337. + return err;
  1338. + if (err > 0)
  1339. + changed = 1;
  1340. +
  1341. + bmsr = __phy_read(phydev, MII_BMSR);
  1342. + if (bmsr < 0)
  1343. + return bmsr;
  1344. +
  1345. + /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
  1346. + * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
  1347. + * logical 1.
  1348. + */
  1349. + if (!(bmsr & BMSR_ESTATEN))
  1350. + return changed;
  1351. +
  1352. + adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
  1353. +
  1354. + err = __phy_modify_changed(phydev, MII_CTRL1000,
  1355. + ADVERTISE_1000FULL | ADVERTISE_1000HALF,
  1356. + adv);
  1357. + if (err < 0)
  1358. + return err;
  1359. + if (err > 0)
  1360. + changed = 1;
  1361. +
  1362. + return changed;
  1363. +}
  1364. +
  1365. +/**
  1366. + * ytphy_utp_config_aneg - restart auto-negotiation or write BMCR
  1367. + * @phydev: target phy_device struct
  1368. + * @changed: whether autoneg is requested
  1369. + *
  1370. + * NOTE: If auto-negotiation is enabled, we configure the
  1371. + * advertising, and then restart auto-negotiation. If it is not
  1372. + * enabled, then we write the BMCR.
  1373. + * The caller must have taken the MDIO bus lock.
  1374. + *
  1375. + * returns 0 or negative errno code
  1376. + */
  1377. +static int ytphy_utp_config_aneg(struct phy_device *phydev, bool changed)
  1378. +{
  1379. + int err;
  1380. + u16 ctl;
  1381. +
  1382. + err = ytphy_setup_master_slave(phydev);
  1383. + if (err < 0)
  1384. + return err;
  1385. + else if (err)
  1386. + changed = true;
  1387. +
  1388. + if (phydev->autoneg != AUTONEG_ENABLE) {
  1389. + /* configures/forces speed/duplex from @phydev */
  1390. +
  1391. + ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
  1392. +
  1393. + return __phy_modify(phydev, MII_BMCR, ~(BMCR_LOOPBACK |
  1394. + BMCR_ISOLATE | BMCR_PDOWN), ctl);
  1395. + }
  1396. +
  1397. + err = ytphy_utp_config_advert(phydev);
  1398. + if (err < 0) /* error */
  1399. + return err;
  1400. + else if (err)
  1401. + changed = true;
  1402. +
  1403. + return ytphy_check_and_restart_aneg(phydev, changed);
  1404. +}
  1405. +
  1406. +/**
  1407. + * yt8521_config_aneg_paged() - switch reg space then call genphy_config_aneg
  1408. + * of one page
  1409. + * @phydev: a pointer to a &struct phy_device
  1410. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
  1411. + * operate.
  1412. + *
  1413. + * returns 0 or negative errno code
  1414. + */
  1415. +static int yt8521_config_aneg_paged(struct phy_device *phydev, int page)
  1416. +{
  1417. + __ETHTOOL_DECLARE_LINK_MODE_MASK(fiber_supported);
  1418. + struct yt8521_priv *priv = phydev->priv;
  1419. + int old_page;
  1420. + int ret = 0;
  1421. +
  1422. + page &= YT8521_RSSR_SPACE_MASK;
  1423. +
  1424. + old_page = phy_select_page(phydev, page);
  1425. + if (old_page < 0)
  1426. + goto err_restore_page;
  1427. +
  1428. + /* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED,
  1429. + * phydev->advertising should be updated.
  1430. + */
  1431. + if (priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) {
  1432. + linkmode_zero(fiber_supported);
  1433. + yt8521_prepare_fiber_features(phydev, fiber_supported);
  1434. +
  1435. + /* prepare fiber_supported, then setup advertising. */
  1436. + if (page == YT8521_RSSR_FIBER_SPACE) {
  1437. + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
  1438. + fiber_supported);
  1439. + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
  1440. + fiber_supported);
  1441. + linkmode_and(phydev->advertising,
  1442. + priv->combo_advertising, fiber_supported);
  1443. + } else {
  1444. + /* ETHTOOL_LINK_MODE_Autoneg_BIT is also used in utp */
  1445. + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
  1446. + fiber_supported);
  1447. + linkmode_andnot(phydev->advertising,
  1448. + priv->combo_advertising,
  1449. + fiber_supported);
  1450. + }
  1451. + }
  1452. +
  1453. + if (page == YT8521_RSSR_FIBER_SPACE)
  1454. + ret = yt8521_fiber_config_aneg(phydev);
  1455. + else
  1456. + ret = ytphy_utp_config_aneg(phydev, false);
  1457. +
  1458. +err_restore_page:
  1459. + return phy_restore_page(phydev, old_page, ret);
  1460. +}
  1461. +
  1462. +/**
  1463. + * yt8521_config_aneg() - change reg space then call yt8521_config_aneg_paged
  1464. + * @phydev: a pointer to a &struct phy_device
  1465. + *
  1466. + * returns 0 or negative errno code
  1467. + */
  1468. +static int yt8521_config_aneg(struct phy_device *phydev)
  1469. +{
  1470. + struct yt8521_priv *priv = phydev->priv;
  1471. + int ret;
  1472. +
  1473. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  1474. + ret = yt8521_config_aneg_paged(phydev, priv->reg_page);
  1475. + if (ret < 0)
  1476. + return ret;
  1477. + } else {
  1478. + /* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED,
  1479. + * phydev->advertising need to be saved at first run.
  1480. + * Because it contains the advertising which supported by both
  1481. + * mac and yt8521(utp and fiber).
  1482. + */
  1483. + if (linkmode_empty(priv->combo_advertising)) {
  1484. + linkmode_copy(priv->combo_advertising,
  1485. + phydev->advertising);
  1486. + }
  1487. +
  1488. + ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_UTP_SPACE);
  1489. + if (ret < 0)
  1490. + return ret;
  1491. +
  1492. + ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_FIBER_SPACE);
  1493. + if (ret < 0)
  1494. + return ret;
  1495. +
  1496. + /* we don't known which will be link, so restore
  1497. + * phydev->advertising as default value.
  1498. + */
  1499. + linkmode_copy(phydev->advertising, priv->combo_advertising);
  1500. + }
  1501. + return 0;
  1502. +}
  1503. +
  1504. +/**
  1505. + * yt8521_aneg_done_paged() - determines the auto negotiation result of one
  1506. + * page.
  1507. + * @phydev: a pointer to a &struct phy_device
  1508. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
  1509. + * operate.
  1510. + *
  1511. + * returns 0(no link)or 1(fiber or utp link) or negative errno code
  1512. + */
  1513. +static int yt8521_aneg_done_paged(struct phy_device *phydev, int page)
  1514. +{
  1515. + int old_page;
  1516. + int ret = 0;
  1517. + int link;
  1518. +
  1519. + old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK);
  1520. + if (old_page < 0)
  1521. + goto err_restore_page;
  1522. +
  1523. + ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
  1524. + if (ret < 0)
  1525. + goto err_restore_page;
  1526. +
  1527. + link = !!(ret & YTPHY_SSR_LINK);
  1528. + ret = link;
  1529. +
  1530. +err_restore_page:
  1531. + return phy_restore_page(phydev, old_page, ret);
  1532. +}
  1533. +
  1534. +/**
  1535. + * yt8521_aneg_done() - determines the auto negotiation result
  1536. + * @phydev: a pointer to a &struct phy_device
  1537. + *
  1538. + * returns 0(no link)or 1(fiber or utp link) or negative errno code
  1539. + */
  1540. +static int yt8521_aneg_done(struct phy_device *phydev)
  1541. +{
  1542. + struct yt8521_priv *priv = phydev->priv;
  1543. + int link_fiber = 0;
  1544. + int link_utp;
  1545. + int link;
  1546. +
  1547. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  1548. + link = yt8521_aneg_done_paged(phydev, priv->reg_page);
  1549. + } else {
  1550. + link_utp = yt8521_aneg_done_paged(phydev,
  1551. + YT8521_RSSR_UTP_SPACE);
  1552. + if (link_utp < 0)
  1553. + return link_utp;
  1554. +
  1555. + if (!link_utp) {
  1556. + link_fiber = yt8521_aneg_done_paged(phydev,
  1557. + YT8521_RSSR_FIBER_SPACE);
  1558. + if (link_fiber < 0)
  1559. + return link_fiber;
  1560. + }
  1561. + link = link_fiber || link_utp;
  1562. + phydev_info(phydev, "%s, link_fiber: %d, link_utp: %d\n",
  1563. + __func__, link_fiber, link_utp);
  1564. + }
  1565. +
  1566. + return link;
  1567. +}
  1568. +
  1569. +/**
  1570. + * ytphy_utp_read_abilities - read PHY abilities from Clause 22 registers
  1571. + * @phydev: target phy_device struct
  1572. + *
  1573. + * NOTE: Reads the PHY's abilities and populates
  1574. + * phydev->supported accordingly.
  1575. + * The caller must have taken the MDIO bus lock.
  1576. + *
  1577. + * returns 0 or negative errno code
  1578. + */
  1579. +static int ytphy_utp_read_abilities(struct phy_device *phydev)
  1580. +{
  1581. + int val;
  1582. +
  1583. + linkmode_set_bit_array(phy_basic_ports_array,
  1584. + ARRAY_SIZE(phy_basic_ports_array),
  1585. + phydev->supported);
  1586. +
  1587. + val = __phy_read(phydev, MII_BMSR);
  1588. + if (val < 0)
  1589. + return val;
  1590. +
  1591. + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported,
  1592. + val & BMSR_ANEGCAPABLE);
  1593. +
  1594. + linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported,
  1595. + val & BMSR_100FULL);
  1596. + linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, phydev->supported,
  1597. + val & BMSR_100HALF);
  1598. + linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, phydev->supported,
  1599. + val & BMSR_10FULL);
  1600. + linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, phydev->supported,
  1601. + val & BMSR_10HALF);
  1602. +
  1603. + if (val & BMSR_ESTATEN) {
  1604. + val = __phy_read(phydev, MII_ESTATUS);
  1605. + if (val < 0)
  1606. + return val;
  1607. +
  1608. + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
  1609. + phydev->supported, val & ESTATUS_1000_TFULL);
  1610. + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
  1611. + phydev->supported, val & ESTATUS_1000_THALF);
  1612. + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
  1613. + phydev->supported, val & ESTATUS_1000_XFULL);
  1614. + }
  1615. +
  1616. + return 0;
  1617. +}
  1618. +
  1619. +/**
  1620. + * yt8521_get_features_paged() - read supported link modes for one page
  1621. + * @phydev: a pointer to a &struct phy_device
  1622. + * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to
  1623. + * operate.
  1624. + *
  1625. + * returns 0 or negative errno code
  1626. + */
  1627. +static int yt8521_get_features_paged(struct phy_device *phydev, int page)
  1628. +{
  1629. + int old_page;
  1630. + int ret = 0;
  1631. +
  1632. + page &= YT8521_RSSR_SPACE_MASK;
  1633. + old_page = phy_select_page(phydev, page);
  1634. + if (old_page < 0)
  1635. + goto err_restore_page;
  1636. +
  1637. + if (page == YT8521_RSSR_FIBER_SPACE) {
  1638. + linkmode_zero(phydev->supported);
  1639. + yt8521_prepare_fiber_features(phydev, phydev->supported);
  1640. + } else {
  1641. + ret = ytphy_utp_read_abilities(phydev);
  1642. + if (ret < 0)
  1643. + goto err_restore_page;
  1644. + }
  1645. +
  1646. +err_restore_page:
  1647. + return phy_restore_page(phydev, old_page, ret);
  1648. +}
  1649. +
  1650. +/**
  1651. + * yt8521_get_features - switch reg space then call yt8521_get_features_paged
  1652. + * @phydev: target phy_device struct
  1653. + *
  1654. + * returns 0 or negative errno code
  1655. + */
  1656. +static int yt8521_get_features(struct phy_device *phydev)
  1657. +{
  1658. + struct yt8521_priv *priv = phydev->priv;
  1659. + int ret;
  1660. +
  1661. + if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) {
  1662. + ret = yt8521_get_features_paged(phydev, priv->reg_page);
  1663. + } else {
  1664. + ret = yt8521_get_features_paged(phydev,
  1665. + YT8521_RSSR_UTP_SPACE);
  1666. + if (ret < 0)
  1667. + return ret;
  1668. +
  1669. + /* add fiber's features to phydev->supported */
  1670. + yt8521_prepare_fiber_features(phydev, phydev->supported);
  1671. + }
  1672. + return ret;
  1673. +}
  1674. +
  1675. static struct phy_driver motorcomm_phy_drvs[] = {
  1676. {
  1677. PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
  1678. @@ -121,16 +1733,35 @@ static struct phy_driver motorcomm_phy_d
  1679. .read_page = yt8511_read_page,
  1680. .write_page = yt8511_write_page,
  1681. },
  1682. + {
  1683. + PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
  1684. + .name = "YT8521 Gigabit Ethernet",
  1685. + .get_features = yt8521_get_features,
  1686. + .probe = yt8521_probe,
  1687. + .read_page = yt8521_read_page,
  1688. + .write_page = yt8521_write_page,
  1689. + .get_wol = ytphy_get_wol,
  1690. + .set_wol = ytphy_set_wol,
  1691. + .config_aneg = yt8521_config_aneg,
  1692. + .aneg_done = yt8521_aneg_done,
  1693. + .config_init = yt8521_config_init,
  1694. + .read_status = yt8521_read_status,
  1695. + .soft_reset = yt8521_soft_reset,
  1696. + .suspend = yt8521_suspend,
  1697. + .resume = yt8521_resume,
  1698. + },
  1699. };
  1700. module_phy_driver(motorcomm_phy_drvs);
  1701. -MODULE_DESCRIPTION("Motorcomm PHY driver");
  1702. +MODULE_DESCRIPTION("Motorcomm 8511/8521 PHY driver");
  1703. MODULE_AUTHOR("Peter Geis");
  1704. +MODULE_AUTHOR("Frank");
  1705. MODULE_LICENSE("GPL");
  1706. static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
  1707. { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
  1708. + { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
  1709. { /* sentinal */ }
  1710. };