xref: /rk3399_rockchip-uboot/drivers/net/phy/miiphybb.c (revision d7fb9bcfb29a1cbdbda7006658e76c2d9da0f66f)
155195773SJean-Christophe PLAGNIOL-VILLARD /*
24ba31ab3SLuigi 'Comio' Mantellini  * (C) Copyright 2009 Industrie Dial Face S.p.A.
34ba31ab3SLuigi 'Comio' Mantellini  * Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com>
44ba31ab3SLuigi 'Comio' Mantellini  *
555195773SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2001
655195773SJean-Christophe PLAGNIOL-VILLARD  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
755195773SJean-Christophe PLAGNIOL-VILLARD  *
855195773SJean-Christophe PLAGNIOL-VILLARD  * See file CREDITS for list of people who contributed to this
955195773SJean-Christophe PLAGNIOL-VILLARD  * project.
1055195773SJean-Christophe PLAGNIOL-VILLARD  *
1155195773SJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or
1255195773SJean-Christophe PLAGNIOL-VILLARD  * modify it under the terms of the GNU General Public License as
1355195773SJean-Christophe PLAGNIOL-VILLARD  * published by the Free Software Foundation; either version 2 of
1455195773SJean-Christophe PLAGNIOL-VILLARD  * the License, or (at your option) any later version.
1555195773SJean-Christophe PLAGNIOL-VILLARD  *
1655195773SJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
1755195773SJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1855195773SJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1955195773SJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
2055195773SJean-Christophe PLAGNIOL-VILLARD  *
2155195773SJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
2255195773SJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
2355195773SJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
2455195773SJean-Christophe PLAGNIOL-VILLARD  * MA 02111-1307 USA
2555195773SJean-Christophe PLAGNIOL-VILLARD  */
2655195773SJean-Christophe PLAGNIOL-VILLARD 
2755195773SJean-Christophe PLAGNIOL-VILLARD /*
2855195773SJean-Christophe PLAGNIOL-VILLARD  * This provides a bit-banged interface to the ethernet MII management
2955195773SJean-Christophe PLAGNIOL-VILLARD  * channel.
3055195773SJean-Christophe PLAGNIOL-VILLARD  */
3155195773SJean-Christophe PLAGNIOL-VILLARD 
3255195773SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
3355195773SJean-Christophe PLAGNIOL-VILLARD #include <ioports.h>
3455195773SJean-Christophe PLAGNIOL-VILLARD #include <ppc_asm.tmpl>
354ba31ab3SLuigi 'Comio' Mantellini #include <miiphy.h>
364ba31ab3SLuigi 'Comio' Mantellini 
374ba31ab3SLuigi 'Comio' Mantellini #define BB_MII_RELOCATE(v,off) (v += (v?off:0))
384ba31ab3SLuigi 'Comio' Mantellini 
394ba31ab3SLuigi 'Comio' Mantellini DECLARE_GLOBAL_DATA_PTR;
404ba31ab3SLuigi 'Comio' Mantellini 
414ba31ab3SLuigi 'Comio' Mantellini #ifndef CONFIG_BITBANGMII_MULTI
424ba31ab3SLuigi 'Comio' Mantellini 
434ba31ab3SLuigi 'Comio' Mantellini /*
444ba31ab3SLuigi 'Comio' Mantellini  * If CONFIG_BITBANGMII_MULTI is not defined we use a
454ba31ab3SLuigi 'Comio' Mantellini  * compatibility layer with the previous miiphybb implementation
464ba31ab3SLuigi 'Comio' Mantellini  * based on macros usage.
474ba31ab3SLuigi 'Comio' Mantellini  *
484ba31ab3SLuigi 'Comio' Mantellini  */
494ba31ab3SLuigi 'Comio' Mantellini static int bb_mii_init_wrap(struct bb_miiphy_bus *bus)
504ba31ab3SLuigi 'Comio' Mantellini {
514ba31ab3SLuigi 'Comio' Mantellini #ifdef MII_INIT
524ba31ab3SLuigi 'Comio' Mantellini 	MII_INIT;
534ba31ab3SLuigi 'Comio' Mantellini #endif
544ba31ab3SLuigi 'Comio' Mantellini 	return 0;
554ba31ab3SLuigi 'Comio' Mantellini }
564ba31ab3SLuigi 'Comio' Mantellini 
574ba31ab3SLuigi 'Comio' Mantellini static int bb_mdio_active_wrap(struct bb_miiphy_bus *bus)
584ba31ab3SLuigi 'Comio' Mantellini {
594ba31ab3SLuigi 'Comio' Mantellini #ifdef MDIO_DECLARE
604ba31ab3SLuigi 'Comio' Mantellini 	MDIO_DECLARE;
614ba31ab3SLuigi 'Comio' Mantellini #endif
624ba31ab3SLuigi 'Comio' Mantellini 	MDIO_ACTIVE;
634ba31ab3SLuigi 'Comio' Mantellini 	return 0;
644ba31ab3SLuigi 'Comio' Mantellini }
654ba31ab3SLuigi 'Comio' Mantellini 
664ba31ab3SLuigi 'Comio' Mantellini static int bb_mdio_tristate_wrap(struct bb_miiphy_bus *bus)
674ba31ab3SLuigi 'Comio' Mantellini {
684ba31ab3SLuigi 'Comio' Mantellini #ifdef MDIO_DECLARE
694ba31ab3SLuigi 'Comio' Mantellini 	MDIO_DECLARE;
704ba31ab3SLuigi 'Comio' Mantellini #endif
714ba31ab3SLuigi 'Comio' Mantellini 	MDIO_TRISTATE;
724ba31ab3SLuigi 'Comio' Mantellini 	return 0;
734ba31ab3SLuigi 'Comio' Mantellini }
744ba31ab3SLuigi 'Comio' Mantellini 
754ba31ab3SLuigi 'Comio' Mantellini static int bb_set_mdio_wrap(struct bb_miiphy_bus *bus, int v)
764ba31ab3SLuigi 'Comio' Mantellini {
774ba31ab3SLuigi 'Comio' Mantellini #ifdef MDIO_DECLARE
784ba31ab3SLuigi 'Comio' Mantellini 	MDIO_DECLARE;
794ba31ab3SLuigi 'Comio' Mantellini #endif
804ba31ab3SLuigi 'Comio' Mantellini 	MDIO(v);
814ba31ab3SLuigi 'Comio' Mantellini 	return 0;
824ba31ab3SLuigi 'Comio' Mantellini }
834ba31ab3SLuigi 'Comio' Mantellini 
844ba31ab3SLuigi 'Comio' Mantellini static int bb_get_mdio_wrap(struct bb_miiphy_bus *bus, int *v)
854ba31ab3SLuigi 'Comio' Mantellini {
864ba31ab3SLuigi 'Comio' Mantellini #ifdef MDIO_DECLARE
874ba31ab3SLuigi 'Comio' Mantellini 	MDIO_DECLARE;
884ba31ab3SLuigi 'Comio' Mantellini #endif
894ba31ab3SLuigi 'Comio' Mantellini 	*v = MDIO_READ;
904ba31ab3SLuigi 'Comio' Mantellini 	return 0;
914ba31ab3SLuigi 'Comio' Mantellini }
924ba31ab3SLuigi 'Comio' Mantellini 
934ba31ab3SLuigi 'Comio' Mantellini static int bb_set_mdc_wrap(struct bb_miiphy_bus *bus, int v)
944ba31ab3SLuigi 'Comio' Mantellini {
954ba31ab3SLuigi 'Comio' Mantellini #ifdef MDC_DECLARE
964ba31ab3SLuigi 'Comio' Mantellini 	MDC_DECLARE;
974ba31ab3SLuigi 'Comio' Mantellini #endif
984ba31ab3SLuigi 'Comio' Mantellini 	MDC(v);
994ba31ab3SLuigi 'Comio' Mantellini 	return 0;
1004ba31ab3SLuigi 'Comio' Mantellini }
1014ba31ab3SLuigi 'Comio' Mantellini 
1024ba31ab3SLuigi 'Comio' Mantellini static int bb_delay_wrap(struct bb_miiphy_bus *bus)
1034ba31ab3SLuigi 'Comio' Mantellini {
1044ba31ab3SLuigi 'Comio' Mantellini 	MIIDELAY;
1054ba31ab3SLuigi 'Comio' Mantellini 	return 0;
1064ba31ab3SLuigi 'Comio' Mantellini }
1074ba31ab3SLuigi 'Comio' Mantellini 
1084ba31ab3SLuigi 'Comio' Mantellini struct bb_miiphy_bus bb_miiphy_buses[] = {
1094ba31ab3SLuigi 'Comio' Mantellini 	{
1104ba31ab3SLuigi 'Comio' Mantellini 		.name = BB_MII_DEVNAME,
1114ba31ab3SLuigi 'Comio' Mantellini 		.init = bb_mii_init_wrap,
1124ba31ab3SLuigi 'Comio' Mantellini 		.mdio_active = bb_mdio_active_wrap,
1134ba31ab3SLuigi 'Comio' Mantellini 		.mdio_tristate = bb_mdio_tristate_wrap,
1144ba31ab3SLuigi 'Comio' Mantellini 		.set_mdio = bb_set_mdio_wrap,
1154ba31ab3SLuigi 'Comio' Mantellini 		.get_mdio = bb_get_mdio_wrap,
1164ba31ab3SLuigi 'Comio' Mantellini 		.set_mdc = bb_set_mdc_wrap,
1174ba31ab3SLuigi 'Comio' Mantellini 		.delay = bb_delay_wrap,
1184ba31ab3SLuigi 'Comio' Mantellini 	}
1194ba31ab3SLuigi 'Comio' Mantellini };
1204ba31ab3SLuigi 'Comio' Mantellini 
1214ba31ab3SLuigi 'Comio' Mantellini int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
1224ba31ab3SLuigi 'Comio' Mantellini 			  sizeof(bb_miiphy_buses[0]);
1234ba31ab3SLuigi 'Comio' Mantellini #endif
1244ba31ab3SLuigi 'Comio' Mantellini 
1254ba31ab3SLuigi 'Comio' Mantellini void bb_miiphy_init(void)
1264ba31ab3SLuigi 'Comio' Mantellini {
1274ba31ab3SLuigi 'Comio' Mantellini 	int i;
1284ba31ab3SLuigi 'Comio' Mantellini 
1294ba31ab3SLuigi 'Comio' Mantellini 	for (i = 0; i < bb_miiphy_buses_num; i++) {
1304ba31ab3SLuigi 'Comio' Mantellini #if !defined(CONFIG_RELOC_FIXUP_WORKS)
1314ba31ab3SLuigi 'Comio' Mantellini 		/* Relocate the hook pointers*/
1324ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].init, gd->reloc_off);
1334ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_active, gd->reloc_off);
1344ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_tristate, gd->reloc_off);
1354ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdio, gd->reloc_off);
1364ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].get_mdio, gd->reloc_off);
1374ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdc, gd->reloc_off);
1384ba31ab3SLuigi 'Comio' Mantellini 		BB_MII_RELOCATE(bb_miiphy_buses[i].delay, gd->reloc_off);
1394ba31ab3SLuigi 'Comio' Mantellini #endif
1404ba31ab3SLuigi 'Comio' Mantellini 		if (bb_miiphy_buses[i].init != NULL) {
1414ba31ab3SLuigi 'Comio' Mantellini 			bb_miiphy_buses[i].init(&bb_miiphy_buses[i]);
1424ba31ab3SLuigi 'Comio' Mantellini 		}
1434ba31ab3SLuigi 'Comio' Mantellini 	}
1444ba31ab3SLuigi 'Comio' Mantellini }
1454ba31ab3SLuigi 'Comio' Mantellini 
146*d7fb9bcfSBen Warren static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname)
1474ba31ab3SLuigi 'Comio' Mantellini {
1484ba31ab3SLuigi 'Comio' Mantellini #ifdef CONFIG_BITBANGMII_MULTI
1494ba31ab3SLuigi 'Comio' Mantellini 	int i;
1504ba31ab3SLuigi 'Comio' Mantellini 
1514ba31ab3SLuigi 'Comio' Mantellini 	/* Search the correct bus */
1524ba31ab3SLuigi 'Comio' Mantellini 	for (i = 0; i < bb_miiphy_buses_num; i++) {
1534ba31ab3SLuigi 'Comio' Mantellini 		if (!strcmp(bb_miiphy_buses[i].name, devname)) {
1544ba31ab3SLuigi 'Comio' Mantellini 			return &bb_miiphy_buses[i];
1554ba31ab3SLuigi 'Comio' Mantellini 		}
1564ba31ab3SLuigi 'Comio' Mantellini 	}
1574ba31ab3SLuigi 'Comio' Mantellini 	return NULL;
1584ba31ab3SLuigi 'Comio' Mantellini #else
1594ba31ab3SLuigi 'Comio' Mantellini 	/* We have just one bitbanging bus */
1604ba31ab3SLuigi 'Comio' Mantellini 	return &bb_miiphy_buses[0];
1614ba31ab3SLuigi 'Comio' Mantellini #endif
1624ba31ab3SLuigi 'Comio' Mantellini }
16355195773SJean-Christophe PLAGNIOL-VILLARD 
16455195773SJean-Christophe PLAGNIOL-VILLARD /*****************************************************************************
16555195773SJean-Christophe PLAGNIOL-VILLARD  *
16655195773SJean-Christophe PLAGNIOL-VILLARD  * Utility to send the preamble, address, and register (common to read
16755195773SJean-Christophe PLAGNIOL-VILLARD  * and write).
16855195773SJean-Christophe PLAGNIOL-VILLARD  */
1694ba31ab3SLuigi 'Comio' Mantellini static void miiphy_pre(struct bb_miiphy_bus *bus, char read,
1704ba31ab3SLuigi 'Comio' Mantellini 		       unsigned char addr, unsigned char reg)
17155195773SJean-Christophe PLAGNIOL-VILLARD {
1724ba31ab3SLuigi 'Comio' Mantellini 	int j;
17355195773SJean-Christophe PLAGNIOL-VILLARD 
17455195773SJean-Christophe PLAGNIOL-VILLARD 	/*
17555195773SJean-Christophe PLAGNIOL-VILLARD 	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
17655195773SJean-Christophe PLAGNIOL-VILLARD 	 * The IEEE spec says this is a PHY optional requirement.  The AMD
17755195773SJean-Christophe PLAGNIOL-VILLARD 	 * 79C874 requires one after power up and one after a MII communications
17855195773SJean-Christophe PLAGNIOL-VILLARD 	 * error.  This means that we are doing more preambles than we need,
17955195773SJean-Christophe PLAGNIOL-VILLARD 	 * but it is safer and will be much more robust.
18055195773SJean-Christophe PLAGNIOL-VILLARD 	 */
18155195773SJean-Christophe PLAGNIOL-VILLARD 
1824ba31ab3SLuigi 'Comio' Mantellini 	bus->mdio_active(bus);
1834ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, 1);
18455195773SJean-Christophe PLAGNIOL-VILLARD 	for (j = 0; j < 32; j++) {
1854ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 0);
1864ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
1874ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 1);
1884ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
18955195773SJean-Christophe PLAGNIOL-VILLARD 	}
19055195773SJean-Christophe PLAGNIOL-VILLARD 
19155195773SJean-Christophe PLAGNIOL-VILLARD 	/* send the start bit (01) and the read opcode (10) or write (10) */
1924ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
1934ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, 0);
1944ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
1954ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
1964ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
1974ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
1984ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, 1);
1994ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2004ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
2014ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2024ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
2034ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, read);
2044ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2054ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
2064ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2074ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
2084ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, !read);
2094ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2104ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
2114ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
21255195773SJean-Christophe PLAGNIOL-VILLARD 
21355195773SJean-Christophe PLAGNIOL-VILLARD 	/* send the PHY address */
21455195773SJean-Christophe PLAGNIOL-VILLARD 	for (j = 0; j < 5; j++) {
2154ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 0);
21655195773SJean-Christophe PLAGNIOL-VILLARD 		if ((addr & 0x10) == 0) {
2174ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 0);
21855195773SJean-Christophe PLAGNIOL-VILLARD 		} else {
2194ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 1);
22055195773SJean-Christophe PLAGNIOL-VILLARD 		}
2214ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
2224ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 1);
2234ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
22455195773SJean-Christophe PLAGNIOL-VILLARD 		addr <<= 1;
22555195773SJean-Christophe PLAGNIOL-VILLARD 	}
22655195773SJean-Christophe PLAGNIOL-VILLARD 
22755195773SJean-Christophe PLAGNIOL-VILLARD 	/* send the register address */
22855195773SJean-Christophe PLAGNIOL-VILLARD 	for (j = 0; j < 5; j++) {
2294ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 0);
23055195773SJean-Christophe PLAGNIOL-VILLARD 		if ((reg & 0x10) == 0) {
2314ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 0);
23255195773SJean-Christophe PLAGNIOL-VILLARD 		} else {
2334ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 1);
23455195773SJean-Christophe PLAGNIOL-VILLARD 		}
2354ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
2364ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 1);
2374ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
23855195773SJean-Christophe PLAGNIOL-VILLARD 		reg <<= 1;
23955195773SJean-Christophe PLAGNIOL-VILLARD 	}
24055195773SJean-Christophe PLAGNIOL-VILLARD }
24155195773SJean-Christophe PLAGNIOL-VILLARD 
24255195773SJean-Christophe PLAGNIOL-VILLARD /*****************************************************************************
24355195773SJean-Christophe PLAGNIOL-VILLARD  *
24455195773SJean-Christophe PLAGNIOL-VILLARD  * Read a MII PHY register.
24555195773SJean-Christophe PLAGNIOL-VILLARD  *
24655195773SJean-Christophe PLAGNIOL-VILLARD  * Returns:
24755195773SJean-Christophe PLAGNIOL-VILLARD  *   0 on success
24855195773SJean-Christophe PLAGNIOL-VILLARD  */
249*d7fb9bcfSBen Warren int bb_miiphy_read(const char *devname, unsigned char addr,
25055195773SJean-Christophe PLAGNIOL-VILLARD 		   unsigned char reg, unsigned short *value)
25155195773SJean-Christophe PLAGNIOL-VILLARD {
25255195773SJean-Christophe PLAGNIOL-VILLARD 	short rdreg; /* register working value */
2534ba31ab3SLuigi 'Comio' Mantellini 	int v;
25455195773SJean-Christophe PLAGNIOL-VILLARD 	int j; /* counter */
2554ba31ab3SLuigi 'Comio' Mantellini 	struct bb_miiphy_bus *bus;
2564ba31ab3SLuigi 'Comio' Mantellini 
2574ba31ab3SLuigi 'Comio' Mantellini 	bus = bb_miiphy_getbus(devname);
2584ba31ab3SLuigi 'Comio' Mantellini 	if (bus == NULL) {
2594ba31ab3SLuigi 'Comio' Mantellini 		return -1;
2604ba31ab3SLuigi 'Comio' Mantellini 	}
26155195773SJean-Christophe PLAGNIOL-VILLARD 
2623f6b18ffSRichard Retanubun 	if (value == NULL) {
2633f6b18ffSRichard Retanubun 		puts("NULL value pointer\n");
2644ba31ab3SLuigi 'Comio' Mantellini 		return -1;
2653f6b18ffSRichard Retanubun 	}
2663f6b18ffSRichard Retanubun 
2674ba31ab3SLuigi 'Comio' Mantellini 	miiphy_pre (bus, 1, addr, reg);
26855195773SJean-Christophe PLAGNIOL-VILLARD 
26955195773SJean-Christophe PLAGNIOL-VILLARD 	/* tri-state our MDIO I/O pin so we can read */
2704ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
2714ba31ab3SLuigi 'Comio' Mantellini 	bus->mdio_tristate(bus);
2724ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
2734ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
2744ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
27555195773SJean-Christophe PLAGNIOL-VILLARD 
27655195773SJean-Christophe PLAGNIOL-VILLARD 	/* check the turnaround bit: the PHY should be driving it to zero */
2774ba31ab3SLuigi 'Comio' Mantellini 	bus->get_mdio(bus, &v);
2784ba31ab3SLuigi 'Comio' Mantellini 	if (v != 0) {
27955195773SJean-Christophe PLAGNIOL-VILLARD 		/* puts ("PHY didn't drive TA low\n"); */
28055195773SJean-Christophe PLAGNIOL-VILLARD 		for (j = 0; j < 32; j++) {
2814ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdc(bus, 0);
2824ba31ab3SLuigi 'Comio' Mantellini 			bus->delay(bus);
2834ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdc(bus, 1);
2844ba31ab3SLuigi 'Comio' Mantellini 			bus->delay(bus);
28555195773SJean-Christophe PLAGNIOL-VILLARD 		}
2863f6b18ffSRichard Retanubun 		/* There is no PHY, set value to 0xFFFF and return */
2873f6b18ffSRichard Retanubun 		*value = 0xFFFF;
2884ba31ab3SLuigi 'Comio' Mantellini 		return -1;
28955195773SJean-Christophe PLAGNIOL-VILLARD 	}
29055195773SJean-Christophe PLAGNIOL-VILLARD 
2914ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
2924ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
29355195773SJean-Christophe PLAGNIOL-VILLARD 
29455195773SJean-Christophe PLAGNIOL-VILLARD 	/* read 16 bits of register data, MSB first */
29555195773SJean-Christophe PLAGNIOL-VILLARD 	rdreg = 0;
29655195773SJean-Christophe PLAGNIOL-VILLARD 	for (j = 0; j < 16; j++) {
2974ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 1);
2984ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
29955195773SJean-Christophe PLAGNIOL-VILLARD 		rdreg <<= 1;
3004ba31ab3SLuigi 'Comio' Mantellini 		bus->get_mdio(bus, &v);
3014ba31ab3SLuigi 'Comio' Mantellini 		rdreg |= (v & 0x1);
3024ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 0);
3034ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
30455195773SJean-Christophe PLAGNIOL-VILLARD 	}
30555195773SJean-Christophe PLAGNIOL-VILLARD 
3064ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
3074ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3084ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
3094ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3104ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
3114ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
31255195773SJean-Christophe PLAGNIOL-VILLARD 
31355195773SJean-Christophe PLAGNIOL-VILLARD 	*value = rdreg;
31455195773SJean-Christophe PLAGNIOL-VILLARD 
31555195773SJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
31655195773SJean-Christophe PLAGNIOL-VILLARD 	printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
31755195773SJean-Christophe PLAGNIOL-VILLARD #endif
31855195773SJean-Christophe PLAGNIOL-VILLARD 
31955195773SJean-Christophe PLAGNIOL-VILLARD 	return 0;
32055195773SJean-Christophe PLAGNIOL-VILLARD }
32155195773SJean-Christophe PLAGNIOL-VILLARD 
32255195773SJean-Christophe PLAGNIOL-VILLARD 
32355195773SJean-Christophe PLAGNIOL-VILLARD /*****************************************************************************
32455195773SJean-Christophe PLAGNIOL-VILLARD  *
32555195773SJean-Christophe PLAGNIOL-VILLARD  * Write a MII PHY register.
32655195773SJean-Christophe PLAGNIOL-VILLARD  *
32755195773SJean-Christophe PLAGNIOL-VILLARD  * Returns:
32855195773SJean-Christophe PLAGNIOL-VILLARD  *   0 on success
32955195773SJean-Christophe PLAGNIOL-VILLARD  */
330*d7fb9bcfSBen Warren int bb_miiphy_write (const char *devname, unsigned char addr,
33155195773SJean-Christophe PLAGNIOL-VILLARD 		     unsigned char reg, unsigned short value)
33255195773SJean-Christophe PLAGNIOL-VILLARD {
3334ba31ab3SLuigi 'Comio' Mantellini 	struct bb_miiphy_bus *bus;
33455195773SJean-Christophe PLAGNIOL-VILLARD 	int j;			/* counter */
33555195773SJean-Christophe PLAGNIOL-VILLARD 
3364ba31ab3SLuigi 'Comio' Mantellini 	bus = bb_miiphy_getbus(devname);
3374ba31ab3SLuigi 'Comio' Mantellini 	if (bus == NULL) {
3384ba31ab3SLuigi 'Comio' Mantellini 		/* Bus not found! */
3394ba31ab3SLuigi 'Comio' Mantellini 		return -1;
3404ba31ab3SLuigi 'Comio' Mantellini 	}
3414ba31ab3SLuigi 'Comio' Mantellini 
3424ba31ab3SLuigi 'Comio' Mantellini 	miiphy_pre (bus, 0, addr, reg);
34355195773SJean-Christophe PLAGNIOL-VILLARD 
34455195773SJean-Christophe PLAGNIOL-VILLARD 	/* send the turnaround (10) */
3454ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
3464ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, 1);
3474ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3484ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
3494ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3504ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
3514ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdio(bus, 0);
3524ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3534ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
3544ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
35555195773SJean-Christophe PLAGNIOL-VILLARD 
35655195773SJean-Christophe PLAGNIOL-VILLARD 	/* write 16 bits of register data, MSB first */
35755195773SJean-Christophe PLAGNIOL-VILLARD 	for (j = 0; j < 16; j++) {
3584ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 0);
35955195773SJean-Christophe PLAGNIOL-VILLARD 		if ((value & 0x00008000) == 0) {
3604ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 0);
36155195773SJean-Christophe PLAGNIOL-VILLARD 		} else {
3624ba31ab3SLuigi 'Comio' Mantellini 			bus->set_mdio(bus, 1);
36355195773SJean-Christophe PLAGNIOL-VILLARD 		}
3644ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
3654ba31ab3SLuigi 'Comio' Mantellini 		bus->set_mdc(bus, 1);
3664ba31ab3SLuigi 'Comio' Mantellini 		bus->delay(bus);
36755195773SJean-Christophe PLAGNIOL-VILLARD 		value <<= 1;
36855195773SJean-Christophe PLAGNIOL-VILLARD 	}
36955195773SJean-Christophe PLAGNIOL-VILLARD 
37055195773SJean-Christophe PLAGNIOL-VILLARD 	/*
37155195773SJean-Christophe PLAGNIOL-VILLARD 	 * Tri-state the MDIO line.
37255195773SJean-Christophe PLAGNIOL-VILLARD 	 */
3734ba31ab3SLuigi 'Comio' Mantellini 	bus->mdio_tristate(bus);
3744ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 0);
3754ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
3764ba31ab3SLuigi 'Comio' Mantellini 	bus->set_mdc(bus, 1);
3774ba31ab3SLuigi 'Comio' Mantellini 	bus->delay(bus);
37855195773SJean-Christophe PLAGNIOL-VILLARD 
37955195773SJean-Christophe PLAGNIOL-VILLARD 	return 0;
38055195773SJean-Christophe PLAGNIOL-VILLARD }
381