pcfiic_ebus.c revision 1.7.16.2 1 /* $NetBSD: pcfiic_ebus.c,v 1.7.16.2 2021/09/12 23:13:02 thorpej Exp $ */
2 /* $OpenBSD: pcfiic_ebus.c,v 1.13 2008/06/08 03:07:40 deraadt Exp $ */
3
4 /*
5 * Copyright (c) 2021 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe.
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 disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer 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 * Copyright (c) 2006 David Gwynne <dlg (at) openbsd.org>
35 *
36 * Permission to use, copy, modify, and distribute this software for any
37 * purpose with or without fee is hereby granted, provided that the above
38 * copyright notice and this permission notice appear in all copies.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47 */
48
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: pcfiic_ebus.c,v 1.7.16.2 2021/09/12 23:13:02 thorpej Exp $");
51
52 /*
53 * Device specific driver for the EBus i2c devices found on some sun4u
54 * systems. On systems not having a boot-bus controller the i2c devices
55 * are PCF8584.
56 */
57
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/device.h>
61 #include <sys/kernel.h>
62 #include <sys/kmem.h>
63 #include <sys/mutex.h>
64
65 #include <sys/bus.h>
66 #include <machine/openfirm.h>
67 #include <machine/autoconf.h>
68
69 #include <dev/ebus/ebusreg.h>
70 #include <dev/ebus/ebusvar.h>
71
72 #include <dev/i2c/i2cvar.h>
73
74 #include <dev/ic/pcf8584var.h>
75 #include <dev/ic/pcf8584reg.h>
76
77 struct pcfiic_ebus_softc {
78 struct pcfiic_softc esc_sc;
79
80 kmutex_t esc_ctrl_lock;
81 bus_space_handle_t esc_ioh; /* for channel selection */
82
83 void *esc_ih;
84 };
85
86 static void
87 bbc_select_channel(struct pcfiic_ebus_softc *esc, uint8_t channel)
88 {
89 bus_space_write_1(esc->esc_sc.sc_iot, esc->esc_ioh, 0, channel);
90 bus_space_barrier(esc->esc_sc.sc_iot, esc->esc_ioh, 0, 1,
91 BUS_SPACE_BARRIER_WRITE);
92 }
93
94 static int
95 bbc_acquire_bus(void *v, int flags)
96 {
97 struct pcfiic_channel *ch = v;
98 struct pcfiic_ebus_softc *esc = container_of(ch->ch_sc,
99 struct pcfiic_ebus_softc, esc_sc);
100
101 if (flags & I2C_F_POLL) {
102 if (! mutex_tryenter(&esc->esc_ctrl_lock)) {
103 return EBUSY;
104 }
105 } else {
106 mutex_enter(&esc->esc_ctrl_lock);
107 }
108
109 bbc_select_channel(esc, (uint8_t)ch->ch_channel);
110 return 0;
111 }
112
113 static void
114 bbc_release_bus(void *v, int flags)
115 {
116 struct pcfiic_channel *ch = v;
117 struct pcfiic_ebus_softc *esc = container_of(ch->ch_sc,
118 struct pcfiic_ebus_softc, esc_sc);
119
120 mutex_exit(&esc->esc_ctrl_lock);
121 }
122
123 static void
124 bbc_initialize_channels(struct pcfiic_ebus_softc *esc)
125 {
126 struct pcfiic_softc *sc = &esc->esc_sc;
127 struct pcfiic_channel *ch;
128 devhandle_t devhandle = device_handle(sc->sc_dev);
129 unsigned int busmap = 0;
130 int node = devhandle_to_of(devhandle);
131 uint32_t reg[2];
132 uint32_t channel;
133 int i, nchannels;
134
135 /*
136 * Two physical I2C busses share a single controller. The
137 * devices are not distinct, so it's not easy to treat it
138 * it as a mux.
139 *
140 * The locking order is:
141 *
142 * iic bus mutex -> ctrl_lock
143 *
144 * ctrl_lock is taken in bbc_acquire_bus.
145 */
146 mutex_init(&esc->esc_ctrl_lock, MUTEX_DEFAULT, IPL_NONE);
147 sc->sc_acquire_bus = bbc_acquire_bus;
148 sc->sc_release_bus = bbc_release_bus;
149
150 /*
151 * The Sun device tree has all devices, no matter the
152 * channel, as direct children of this node. Figure
153 * out which channel numbers are listed, count them,
154 * and then populate the channel structures.
155 */
156 for (node = OF_child(node); node != 0; node = OF_peer(node)) {
157 if (OF_getprop(node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
158 continue;
159 }
160
161 /* Channel is in the first cell. */
162 channel = be32toh(reg[0]);
163 KASSERT(channel < 32);
164
165 busmap |= __BIT(channel);
166 }
167
168 nchannels = popcount(busmap);
169 if (nchannels == 0) {
170 /*
171 * No child devices in the device tree. This is fine;
172 * the generic code will just assume a single channel
173 * and attach a bus instance, but our MUX will still
174 * get programmed correctly because we've initialized
175 * the acquire/release bus funcitons.
176 */
177 return;
178 }
179
180 ch = kmem_alloc(nchannels * sizeof(*ch), KM_SLEEP);
181 for (i = 0; i < nchannels; i++) {
182 channel = ffs(busmap);
183 KASSERT(channel != 0);
184 channel--; /* ffs() returns 0 if no bits set. */
185 busmap &= ~__BIT(channel);
186
187 ch[i].ch_channel = channel;
188 ch[i].ch_devhandle = devhandle;
189 }
190
191 sc->sc_channels = ch;
192 sc->sc_nchannels = nchannels;
193 }
194
195 static int
196 pcfiic_ebus_match(device_t parent, struct cfdata *match, void *aux)
197 {
198 struct ebus_attach_args *ea = aux;
199 char compat[32];
200
201 if (strcmp(ea->ea_name, "SUNW,envctrl") == 0 ||
202 strcmp(ea->ea_name, "SUNW,envctrltwo") == 0)
203 return (1);
204
205 if (strcmp(ea->ea_name, "i2c") != 0)
206 return (0);
207
208 if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
209 return (0);
210
211 if (strcmp(compat, "pcf8584") == 0 ||
212 strcmp(compat, "i2cpcf,8584") == 0 ||
213 strcmp(compat, "SUNW,i2c-pic16f747") == 0 ||
214 strcmp(compat, "SUNW,bbc-i2c") == 0)
215 return (1);
216
217 return (0);
218 }
219
220 static void
221 pcfiic_ebus_attach(device_t parent, device_t self, void *aux)
222 {
223 struct pcfiic_ebus_softc *esc = device_private(self);
224 struct pcfiic_softc *sc = &esc->esc_sc;
225 struct ebus_attach_args *ea = aux;
226 char compat[32];
227 uint32_t addr[2];
228 uint8_t clock = PCF8584_CLK_12 | PCF8584_SCL_90;
229 int swapregs = 0;
230
231 if (ea->ea_nreg < 1 || ea->ea_nreg > 2) {
232 printf(": expected 1 or 2 registers, got %d\n", ea->ea_nreg);
233 return;
234 }
235
236 /* E450 and E250 have a different clock */
237 if ((strcmp(ea->ea_name, "SUNW,envctrl") == 0) ||
238 (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0))
239 clock = PCF8584_CLK_12 | PCF8584_SCL_45;
240
241 sc->sc_dev = self;
242 if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) > 0 &&
243 strcmp(compat, "SUNW,bbc-i2c") == 0) {
244 /*
245 * On BBC-based machines, Sun swapped the order of
246 * the registers on their clone pcf, plus they feed
247 * it a non-standard clock.
248 */
249 int clk = prom_getpropint(findroot(), "clock-frequency", 0);
250
251 if (clk < 105000000)
252 clock = PCF8584_CLK_3 | PCF8584_SCL_90;
253 else if (clk < 160000000)
254 clock = PCF8584_CLK_4_43 | PCF8584_SCL_90;
255 swapregs = 1;
256 }
257
258 if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
259 addr[0] = 0;
260 addr[1] = 0x55 << 1;
261 } else if (addr[1] == 0x00 || addr[1] > 0xff) {
262 printf(": invalid address on I2C bus");
263 return;
264 }
265
266 if (bus_space_map(ea->ea_bustag, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
267 ea->ea_reg[0].size, 0, &sc->sc_ioh) == 0) {
268 sc->sc_iot = ea->ea_bustag;
269 } else {
270 printf(": can't map register space\n");
271 return;
272 }
273
274 if (ea->ea_nreg == 2) {
275 /*
276 * Second register only occurs on BBC-based machines,
277 * and is likely not prom mapped
278 */
279 if (bus_space_map(sc->sc_iot,
280 EBUS_ADDR_FROM_REG(&ea->ea_reg[1]),
281 ea->ea_reg[1].size, 0, &esc->esc_ioh) != 0) {
282 printf(": can't map 2nd register space\n");
283 return;
284 }
285 bbc_initialize_channels(esc);
286 }
287
288 if (ea->ea_nintr >= 1)
289 esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intr[0],
290 IPL_BIO, pcfiic_intr, sc);
291 else
292 esc->esc_ih = NULL;
293
294 if (esc->esc_ih == NULL)
295 sc->sc_poll = 1;
296
297 pcfiic_attach(sc, (i2c_addr_t)(addr[1] >> 1), clock, swapregs);
298 }
299
300 CFATTACH_DECL_NEW(pcfiic, sizeof(struct pcfiic_ebus_softc),
301 pcfiic_ebus_match, pcfiic_ebus_attach, NULL, NULL);
302