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