1/*	$NetBSD: mii_bitbang.c,v 1.12 2008/05/04 17:06:09 xtraeme Exp $	*/
2
3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following didevlaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following didevlaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Common module for bit-bang'ing the MII.
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD$");
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/module.h>
43
44#include <dev/mii/mii.h>
45#include <dev/mii/mii_bitbang.h>
46
47MODULE_VERSION(mii_bitbang, 1);
48
49static void mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops,
50    uint32_t data, int nbits);
51
52#define	MWRITE(x)							\
53do {									\
54	ops->mbo_write(dev, (x));					\
55	DELAY(1);							\
56} while (/* CONSTCOND */ 0)
57
58#define	MREAD		ops->mbo_read(dev)
59
60#define	MDO		ops->mbo_bits[MII_BIT_MDO]
61#define	MDI		ops->mbo_bits[MII_BIT_MDI]
62#define	MDC		ops->mbo_bits[MII_BIT_MDC]
63#define	MDIRPHY		ops->mbo_bits[MII_BIT_DIR_HOST_PHY]
64#define	MDIRHOST	ops->mbo_bits[MII_BIT_DIR_PHY_HOST]
65
66/*
67 * mii_bitbang_sync:
68 *
69 *	Synchronize the MII.
70 */
71void
72mii_bitbang_sync(device_t dev, mii_bitbang_ops_t ops)
73{
74	int i;
75	uint32_t v;
76
77	v = MDIRPHY | MDO;
78
79	MWRITE(v);
80	for (i = 0; i < 32; i++) {
81		MWRITE(v | MDC);
82		MWRITE(v);
83	}
84}
85
86/*
87 * mii_bitbang_sendbits:
88 *
89 *	Send a series of bits to the MII.
90 */
91static void
92mii_bitbang_sendbits(device_t dev, mii_bitbang_ops_t ops, uint32_t data,
93    int nbits)
94{
95	int i;
96	uint32_t v;
97
98	v = MDIRPHY;
99	MWRITE(v);
100
101	for (i = 1 << (nbits - 1); i != 0; i >>= 1) {
102		if (data & i)
103			v |= MDO;
104		else
105			v &= ~MDO;
106		MWRITE(v);
107		MWRITE(v | MDC);
108		MWRITE(v);
109	}
110}
111
112/*
113 * mii_bitbang_readreg:
114 *
115 *	Read a PHY register by bit-bang'ing the MII.
116 */
117int
118mii_bitbang_readreg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg)
119{
120	int i, error, val;
121
122	mii_bitbang_sync(dev, ops);
123
124	mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2);
125	mii_bitbang_sendbits(dev, ops, MII_COMMAND_READ, 2);
126	mii_bitbang_sendbits(dev, ops, phy, 5);
127	mii_bitbang_sendbits(dev, ops, reg, 5);
128
129	/* Switch direction to PHY->host, without a clock transition. */
130	MWRITE(MDIRHOST);
131
132	/* Turnaround clock. */
133	MWRITE(MDIRHOST | MDC);
134	MWRITE(MDIRHOST);
135
136	/* Check for error. */
137	error = MREAD & MDI;
138
139	/* Idle clock. */
140	MWRITE(MDIRHOST | MDC);
141	MWRITE(MDIRHOST);
142
143	val = 0;
144	for (i = 0; i < 16; i++) {
145		val <<= 1;
146		/* Read data prior to clock low-high transition. */
147		if (error == 0 && (MREAD & MDI) != 0)
148			val |= 1;
149
150		MWRITE(MDIRHOST | MDC);
151		MWRITE(MDIRHOST);
152	}
153
154	/* Set direction to host->PHY, without a clock transition. */
155	MWRITE(MDIRPHY);
156
157	return (error != 0 ? 0 : val);
158}
159
160/*
161 * mii_bitbang_writereg:
162 *
163 *	Write a PHY register by bit-bang'ing the MII.
164 */
165void
166mii_bitbang_writereg(device_t dev, mii_bitbang_ops_t ops, int phy, int reg,
167    int val)
168{
169
170	mii_bitbang_sync(dev, ops);
171
172	mii_bitbang_sendbits(dev, ops, MII_COMMAND_START, 2);
173	mii_bitbang_sendbits(dev, ops, MII_COMMAND_WRITE, 2);
174	mii_bitbang_sendbits(dev, ops, phy, 5);
175	mii_bitbang_sendbits(dev, ops, reg, 5);
176	mii_bitbang_sendbits(dev, ops, MII_COMMAND_ACK, 2);
177	mii_bitbang_sendbits(dev, ops, val, 16);
178
179	MWRITE(MDIRPHY);
180}
181