xref: /openbsd/sys/dev/mii/ytphy.c (revision 9d7a05f9)
1 /*	$OpenBSD: ytphy.c,v 1.6 2024/03/12 16:26:46 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2001 Theo de Raadt
4  * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/socket.h>
23 #include <sys/errno.h>
24 
25 #include <net/if.h>
26 #include <net/if_var.h>
27 #include <net/if_media.h>
28 
29 #include <dev/mii/mii.h>
30 #include <dev/mii/miivar.h>
31 #include <dev/mii/miidevs.h>
32 
33 #ifdef __HAVE_FDT
34 #include <machine/fdt.h>
35 #include <dev/ofw/openfirm.h>
36 #endif
37 
38 #define MII_MODEL_MOTORCOMM_YT8511	0x10
39 #define MII_MODEL_MOTORCOMM_YT8521	0x11
40 
41 #define YT8511_REG_ADDR		0x1e
42 #define YT8511_REG_DATA		0x1f
43 
44 #define YT8511_EXT_CLK_GATE		0x0c
45 #define  YT8511_TX_CLK_DELAY_SEL_MASK	(0xf << 4)
46 #define  YT8511_TX_CLK_DELAY_SEL_EN	(0xf << 4)
47 #define  YT8511_TX_CLK_DELAY_SEL_DIS	(0x2 << 4)
48 #define  YT8511_CLK_25M_SEL_MASK	(0x3 << 1)
49 #define  YT8511_CLK_25M_SEL_125M	(0x3 << 1)
50 #define  YT8511_RX_CLK_DELAY_EN		(1 << 0)
51 #define YT8511_EXT_DELAY_DRIVE		0x0d
52 #define  YT8511_TXC_DELAY_SEL_FE_MASK	(0xf << 12)
53 #define  YT8511_TXC_DELAY_SEL_FE_EN	(0xf << 12)
54 #define  YT8511_TXC_DELAY_SEL_FE_DIS	(0x2 << 12)
55 #define YT8511_EXT_SLEEP_CTRL		0x27
56 #define  YT8511_PLL_ON_IN_SLEEP		(1 << 14)
57 
58 #define YT8521_EXT_CHIP_CONFIG		0xa001
59 #define  YT8521_RXC_DLY_EN		(1 << 8)
60 #define  YT8521_CFG_LDO_MASK		(0x3 << 4)
61 #define  YT8521_CFG_LDO_3V3		(0x0 << 4)
62 #define  YT8521_CFG_LDO_2V5		(0x1 << 4)
63 #define  YT8521_CFG_LDO_1V8		(0x2 << 4)	/* or 0x3 */
64 #define YT8521_EXT_RGMII_CONFIG1	0xa003
65 #define  YT8521_TX_CLK_SEL		(1 << 14)
66 #define  YT8521_RX_DELAY_SEL_MASK	(0xf << 10)
67 #define  YT8521_RX_DELAY_SEL_SHIFT	10
68 #define  YT8521_TX_DELAY_SEL_MASK	(0xf << 0)
69 #define  YT8521_TX_DELAY_SEL_SHIFT	0
70 #define YT8521_EXT_PAD_DRIVE_STRENGTH	0xa010
71 #define  YT8531_RGMII_RXC_DS_MASK	(0x7 << 13)
72 #define  YT8531_RGMII_RXC_DS_SHIFT	13
73 #define  YT8531_RGMII_RXD_DS_MASK	((0x1 << 12) | (0x3 << 4))
74 #define  YT8531_RGMII_RXD_DS_LOW(x)	(((x) & 0x3) << 4)
75 #define  YT8531_RGMII_RXD_DS_HIGH(x)	(((x) >> 2) << 12)
76 #define YT8521_EXT_SYNCE_CFG		0xa012
77 #define  YT8531_EN_SYNC_E		(1 << 6)
78 #define  YT8531_CLK_FRE_SEL_125M	(1 << 4)
79 #define  YT8531_CLK_SRC_SEL_MASK	(0x7 << 1)
80 #define  YT8531_CLK_SRC_SEL_PLL_125M	(0x0 << 1)
81 #define  YT8531_CLK_SRC_SEL_REF_25M	(0x4 << 1)
82 
83 int	ytphy_match(struct device *, void *, void *);
84 void	ytphy_attach(struct device *, struct device *, void *);
85 
86 const struct cfattach ytphy_ca = {
87 	sizeof(struct mii_softc), ytphy_match, ytphy_attach, mii_phy_detach
88 };
89 
90 struct cfdriver ytphy_cd = {
91 	NULL, "ytphy", DV_DULL
92 };
93 
94 int	ytphy_service(struct mii_softc *, struct mii_data *, int);
95 void	ytphy_yt8511_init(struct mii_softc *);
96 void	ytphy_yt8521_init(struct mii_softc *);
97 void	ytphy_yt8521_update(struct mii_softc *);
98 void	ytphy_yt8531_init(struct mii_softc *);
99 
100 const struct mii_phy_funcs ytphy_funcs = {
101 	ytphy_service, ukphy_status, mii_phy_reset,
102 };
103 
104 static const struct mii_phydesc ytphys[] = {
105 	{ MII_OUI_MOTORCOMM,	MII_MODEL_MOTORCOMM_YT8531,
106 	  MII_STR_MOTORCOMM_YT8531 },
107 	{ 0,			0,
108 	  NULL },
109 };
110 
111 int
ytphy_match(struct device * parent,void * match,void * aux)112 ytphy_match(struct device *parent, void *match, void *aux)
113 {
114 	struct mii_attach_args *ma = aux;
115 
116 	/*
117 	 * The MotorComm YT8511 and TY8521 have bogus MII OUIs, so
118 	 * match the complete ID including the rev.
119 	 */
120 	if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
121 		return (10);
122 	if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x011a)
123 		return (10);
124 
125 	if (mii_phy_match(ma, ytphys) != NULL)
126 		return (10);
127 
128 	return (0);
129 }
130 
131 void
ytphy_attach(struct device * parent,struct device * self,void * aux)132 ytphy_attach(struct device *parent, struct device *self, void *aux)
133 {
134 	struct mii_softc *sc = (struct mii_softc *)self;
135 	struct mii_attach_args *ma = aux;
136 	struct mii_data *mii = ma->mii_data;
137 	const struct mii_phydesc *mpd;
138 
139 	mpd = mii_phy_match(ma, ytphys);
140 
141 	if (mpd)
142 		printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
143 	else if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
144 		printf(": YT8511 10/100/1000 PHY\n");
145 	else
146 		printf(": YT8521 10/100/1000 PHY\n");
147 
148 	sc->mii_inst = mii->mii_instance;
149 	sc->mii_phy = ma->mii_phyno;
150 	sc->mii_funcs = &ytphy_funcs;
151 	sc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
152 	sc->mii_model = MII_MODEL(ma->mii_id2);
153 	sc->mii_pdata = mii;
154 	sc->mii_flags = ma->mii_flags;
155 
156 	if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
157 		ytphy_yt8511_init(sc);
158 	else if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x011a)
159 		ytphy_yt8521_init(sc);
160 	else
161 		ytphy_yt8531_init(sc);
162 
163 	sc->mii_capabilities =
164 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
165 	if (sc->mii_capabilities & BMSR_EXTSTAT)
166 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
167 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) ||
168 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK))
169 		mii_phy_add_media(sc);
170 
171 	PHY_RESET(sc);
172 }
173 
174 int
ytphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)175 ytphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
176 {
177 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
178 	int reg;
179 
180 	if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
181 		return (ENXIO);
182 
183 	switch (cmd) {
184 	case MII_POLLSTAT:
185 		/*
186 		 * If we're not polling our PHY instance, just return.
187 		 */
188 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
189 			return (0);
190 		break;
191 
192 	case MII_MEDIACHG:
193 		/*
194 		 * If the media indicates a different PHY instance,
195 		 * isolate ourselves.
196 		 */
197 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
198 			reg = PHY_READ(sc, MII_BMCR);
199 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
200 			return (0);
201 		}
202 
203 		/*
204 		 * If the interface is not up, don't do anything.
205 		 */
206 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
207 			break;
208 
209 		mii_phy_setmedia(sc);
210 		break;
211 
212 	case MII_TICK:
213 		/*
214 		 * If we're not currently selected, just return.
215 		 */
216 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
217 			return (0);
218 
219 		if (mii_phy_tick(sc) == EJUSTRETURN)
220 			return (0);
221 		break;
222 
223 	case MII_DOWN:
224 		mii_phy_down(sc);
225 		return (0);
226 	}
227 
228 	/* Update the media status. */
229 	mii_phy_status(sc);
230 
231 	/* Callback if something changed. */
232 	if (sc->mii_model != MII_MODEL_MOTORCOMM_YT8511)
233 		ytphy_yt8521_update(sc);
234 	mii_phy_update(sc, cmd);
235 	return (0);
236 }
237 
238 void
ytphy_yt8511_init(struct mii_softc * sc)239 ytphy_yt8511_init(struct mii_softc *sc)
240 {
241 	uint16_t tx_clk_delay_sel;
242 	uint16_t rx_clk_delay_en;
243 	uint16_t txc_delay_sel_fe;
244 	uint16_t addr, data;
245 
246 	if (sc->mii_flags & MIIF_RXID)
247 		rx_clk_delay_en = YT8511_RX_CLK_DELAY_EN;
248 	else
249 		rx_clk_delay_en = 0;
250 
251 	if (sc->mii_flags & MIIF_TXID) {
252 		tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_EN;
253 		txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_EN;
254 	} else {
255 		tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_DIS;
256 		txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_DIS;
257 	}
258 
259 	/* Save address register. */
260 	addr = PHY_READ(sc, YT8511_REG_ADDR);
261 
262 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_CLK_GATE);
263 	data = PHY_READ(sc, YT8511_REG_DATA);
264 	data &= ~YT8511_TX_CLK_DELAY_SEL_MASK;
265 	data &= ~YT8511_RX_CLK_DELAY_EN;
266 	data &= ~YT8511_CLK_25M_SEL_MASK;
267 	data |= tx_clk_delay_sel;
268 	data |= rx_clk_delay_en;
269 	data |= YT8511_CLK_25M_SEL_125M;
270 	PHY_WRITE(sc, YT8511_REG_DATA, data);
271 
272 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_DELAY_DRIVE);
273 	data = PHY_READ(sc, YT8511_REG_DATA);
274 	data &= ~YT8511_TXC_DELAY_SEL_FE_MASK;
275 	data |= txc_delay_sel_fe;
276 	PHY_WRITE(sc, YT8511_REG_DATA, data);
277 
278 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_SLEEP_CTRL);
279 	data = PHY_READ(sc, YT8511_REG_DATA);
280 	data |= YT8511_PLL_ON_IN_SLEEP;
281 	PHY_WRITE(sc, YT8511_REG_DATA, data);
282 
283 	/* Restore address register. */
284 	PHY_WRITE(sc, YT8511_REG_ADDR, addr);
285 }
286 
287 void
ytphy_yt8521_init(struct mii_softc * sc)288 ytphy_yt8521_init(struct mii_softc *sc)
289 {
290 	uint32_t rx_delay = 1950;
291 	uint32_t tx_delay = 1950;
292 	int rx_delay_en = 0;
293 	uint16_t addr, data;
294 
295 #ifdef __HAVE_FDT
296 	if (sc->mii_pdata->mii_node) {
297 		rx_delay = OF_getpropint(sc->mii_pdata->mii_node,
298 		    "rx-internal-delay-ps", rx_delay);
299 		tx_delay = OF_getpropint(sc->mii_pdata->mii_node,
300 		    "tx-internal-delay-ps", tx_delay);
301 	}
302 #endif
303 
304 	/* Save address register. */
305 	addr = PHY_READ(sc, YT8511_REG_ADDR);
306 
307 	if ((sc->mii_flags & MIIF_RXID) == 0)
308 		rx_delay = 0;
309 	if ((sc->mii_flags & MIIF_TXID) == 0)
310 		tx_delay = 0;
311 
312 	if (rx_delay >= 1900 && ((rx_delay - 1900) % 150) == 0) {
313 		rx_delay -= 1900;
314 		rx_delay_en = 1;
315 	}
316 
317 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
318 	data = PHY_READ(sc, YT8511_REG_DATA);
319 	if (rx_delay_en)
320 		data |= YT8521_RXC_DLY_EN;
321 	else
322 		data &= ~YT8521_RXC_DLY_EN;
323 	PHY_WRITE(sc, YT8511_REG_DATA, data);
324 
325 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
326 	data = PHY_READ(sc, YT8511_REG_DATA);
327 	data &= ~YT8521_RX_DELAY_SEL_MASK;
328 	data |= (((rx_delay + 75) / 150) << YT8521_RX_DELAY_SEL_SHIFT);
329 	data &= ~YT8521_TX_DELAY_SEL_MASK;
330 	data |= (((tx_delay + 75) / 150) << YT8521_TX_DELAY_SEL_SHIFT);
331 	PHY_WRITE(sc, YT8511_REG_DATA, data);
332 
333 	/* Restore address register. */
334 	PHY_WRITE(sc, YT8511_REG_ADDR, addr);
335 }
336 
337 void
ytphy_yt8521_update(struct mii_softc * sc)338 ytphy_yt8521_update(struct mii_softc *sc)
339 {
340 #ifdef __HAVE_FDT
341 	struct mii_data *mii = sc->mii_pdata;
342 	int tx_clk_adj_en;
343 	int tx_clk_inv = 0;
344 	uint16_t addr, data;
345 
346 	if (sc->mii_media_active == mii->mii_media_active)
347 		return;
348 
349 	tx_clk_adj_en = OF_getpropbool(mii->mii_node,
350 	    "motorcomm,tx-clk-adj-enabled");
351 	if (!tx_clk_adj_en)
352 		return;
353 
354 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
355 	case IFM_1000_T:
356 		tx_clk_inv = OF_getpropbool(mii->mii_node,
357 		    "motorcomm,tx-clk-1000-inverted");
358 		break;
359 	case IFM_100_TX:
360 		tx_clk_inv = OF_getpropbool(mii->mii_node,
361 		    "motorcomm,tx-clk-100-inverted");
362 		break;
363 	case IFM_10_T:
364 		tx_clk_inv = OF_getpropbool(mii->mii_node,
365 		    "motorcomm,tx-clk-10-inverted");
366 		break;
367 	}
368 
369 	/* Save address register. */
370 	addr = PHY_READ(sc, YT8511_REG_ADDR);
371 
372 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
373 	data = PHY_READ(sc, YT8511_REG_DATA);
374 	if (tx_clk_inv)
375 		data |= YT8521_TX_CLK_SEL;
376 	else
377 		data &= ~YT8521_TX_CLK_SEL;
378 	PHY_WRITE(sc, YT8511_REG_DATA, data);
379 
380 	/* Restore address register. */
381 	PHY_WRITE(sc, YT8511_REG_ADDR, addr);
382 #endif
383 }
384 
385 /* The RGMII drive strength depends on the voltage level. */
386 
387 struct ytphy_ds_map {
388 	uint32_t volt;		/* mV */
389 	uint16_t amp;		/* uA */
390 	uint16_t ds;
391 };
392 
393 struct ytphy_ds_map ytphy_yt8531_ds_map[] = {
394 	{ 1800, 1200, 0 },
395 	{ 1800, 2100, 1 },
396 	{ 1800, 2700, 2 },
397 	{ 1800, 2910, 3 },
398 	{ 1800, 3110, 4 },
399 	{ 1800, 3600, 5 },
400 	{ 1800, 3970, 6 },
401 	{ 1800, 4350, 7 },
402 	{ 3300, 3070, 0 },
403 	{ 3300, 4080, 1 },
404 	{ 3300, 4370, 2 },
405 	{ 3300, 4680, 3 },
406 	{ 3300, 5020, 4 },
407 	{ 3300, 5450, 5 },
408 	{ 3300, 5740, 6 },
409 	{ 3300, 6140, 7 },
410 };
411 
412 uint32_t
ytphy_yt8531_ds(struct mii_softc * sc,uint32_t volt,uint32_t amp)413 ytphy_yt8531_ds(struct mii_softc *sc, uint32_t volt, uint32_t amp)
414 {
415 	int i;
416 
417 	for (i = 0; i < nitems(ytphy_yt8531_ds_map); i++) {
418 		if (ytphy_yt8531_ds_map[i].volt == volt &&
419 		    ytphy_yt8531_ds_map[i].amp == amp)
420 			return ytphy_yt8531_ds_map[i].ds;
421 	}
422 
423 	if (amp) {
424 		printf("%s: unknown drive strength (%d uA at %d mV)\n",
425 		    sc->mii_dev.dv_xname, amp, volt);
426 	}
427 
428 	/* Default drive strength. */
429 	return 3;
430 }
431 
432 void
ytphy_yt8531_init(struct mii_softc * sc)433 ytphy_yt8531_init(struct mii_softc *sc)
434 {
435 	uint32_t rx_clk_drv = 0;
436 	uint32_t rx_data_drv = 0;
437 	uint32_t clk_out_freq = 0;
438 	uint16_t addr, data;
439 	uint16_t volt;
440 
441 	ytphy_yt8521_init(sc);
442 
443 #ifdef __HAVE_FDT
444 	if (sc->mii_pdata->mii_node) {
445 		rx_clk_drv = OF_getpropint(sc->mii_pdata->mii_node,
446 		    "motorcomm,rx-clk-drv-microamp", 0);
447 		rx_data_drv = OF_getpropint(sc->mii_pdata->mii_node,
448 		    "motorcomm,rx-data-drv-microamp", 0);
449 		clk_out_freq = OF_getpropint(sc->mii_pdata->mii_node,
450 		    "motorcomm,clk-out-frequency-hz", 0);
451 	}
452 #endif
453 
454 	/* Save address register. */
455 	addr = PHY_READ(sc, YT8511_REG_ADDR);
456 
457 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
458 	data = PHY_READ(sc, YT8511_REG_DATA);
459 	if ((data & YT8521_CFG_LDO_MASK) == YT8521_CFG_LDO_3V3)
460 		volt = 3300;
461 	else if ((data & YT8521_CFG_LDO_MASK) == YT8521_CFG_LDO_2V5)
462 		volt = 2500;
463 	else
464 		volt = 1800;
465 
466 	rx_clk_drv = ytphy_yt8531_ds(sc, volt, rx_clk_drv);
467 	rx_data_drv = ytphy_yt8531_ds(sc, volt, rx_data_drv);
468 
469 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_PAD_DRIVE_STRENGTH);
470 	data = PHY_READ(sc, YT8511_REG_DATA);
471 	data &= ~YT8531_RGMII_RXC_DS_MASK;
472 	data |= rx_clk_drv << YT8531_RGMII_RXC_DS_SHIFT;
473 	data &= ~YT8531_RGMII_RXD_DS_MASK;
474 	data |= YT8531_RGMII_RXD_DS_LOW(rx_data_drv);
475 	data |= YT8531_RGMII_RXD_DS_HIGH(rx_data_drv);
476 	PHY_WRITE(sc, YT8511_REG_DATA, data);
477 
478 	PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_SYNCE_CFG);
479 	data = PHY_READ(sc, YT8511_REG_DATA);
480 	switch (clk_out_freq) {
481 	case 125000000:
482 		data |= YT8531_EN_SYNC_E;
483 		data |= YT8531_CLK_FRE_SEL_125M;
484 		data &= ~YT8531_CLK_SRC_SEL_MASK;
485 		data |= YT8531_CLK_SRC_SEL_PLL_125M;
486 		break;
487 	case 25000000:
488 		data |= YT8531_EN_SYNC_E;
489 		data &= ~YT8531_CLK_FRE_SEL_125M;
490 		data &= ~YT8531_CLK_SRC_SEL_MASK;
491 		data |= YT8531_CLK_SRC_SEL_REF_25M;
492 		break;
493 	default:
494 		data &= ~YT8531_EN_SYNC_E;
495 		break;
496 	}
497 	PHY_WRITE(sc, YT8511_REG_DATA, data);
498 
499 	/* Restore address register. */
500 	PHY_WRITE(sc, YT8511_REG_ADDR, addr);
501 }
502