xref: /openbsd/sys/arch/sparc64/dev/mgiic.c (revision d415bd75)
1 /*	$OpenBSD: mgiic.c,v 1.4 2021/10/24 17:05:03 mpi Exp $	*/
2 /*
3  * Copyright (c) 2008 Theo de Raadt <deraadt@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/errno.h>
21 #include <sys/malloc.h>
22 #include <sys/systm.h>
23 #include <sys/rwlock.h>
24 
25 #include <uvm/uvm_extern.h>
26 
27 #include <machine/bus.h>
28 #include <machine/autoconf.h>
29 #include <machine/openfirm.h>
30 
31 #include <dev/i2c/i2cvar.h>
32 #include <sparc64/dev/ofwi2cvar.h>
33 
34 #define MGSLAVEADDR		0x00
35 #define MGSLAVEXADDR		0x08
36 #define MGDATA			0x10
37 #define MGCONTROL			0x18
38 #define  MGCONTROL_IEN			0x80
39 #define  MGCONTROL_ENAB			0x40
40 #define  MGCONTROL_STA			0x20
41 #define  MGCONTROL_STP			0x10
42 #define  MGCONTROL_IFLG			0x08
43 #define  MGCONTROL_AAK			0x04
44 #define MGSTATUS		0x20
45 #define  MGSTATUS_BUSERR		0x00
46 #define  MGSTATUS_STARTSENT		0x08
47 #define	 MGSTATUS_REPEATSTART		0x10
48 #define  MGSTATUS_ADDR_W_ACKR		0x18
49 #define  MGSTATUS_ADDR_W_NOACKR		0x20
50 #define  MGSTATUS_MDATA_ACKR		0x28
51 #define  MGSTATUS_MDATA_NOACKR		0x30
52 #define  MGSTATUS_ARBLOST		0x38
53 #define  MGSTATUS_ADDR_R_ACKR		0x40
54 #define  MGSTATUS_ADDR_R_NOACKR		0x48
55 #define  MGSTATUS_MDATA_ACKT		0x50
56 #define  MGSTATUS_MDATA_NOACKT		0x58
57 #define  MGSTATUS_SADDR_W_ACKT		0x60
58 #define  MGSTATUS_ARBLOST_SLW_ACKT	0x68
59 #define  MGSTATUS_GC_TACK		0x70
60 #define  MGSTATUS_ARBLOST_GC_ACKT	0x78
61 #define  MGSTATUS_IDLE			0xf8
62 #define MGCLOCKCONTROL		0x28
63 #define MGSOFTRESET		0x30
64 
65 struct mgiic_softc {
66 	struct device sc_dev;
67 
68 	bus_space_tag_t		sc_bt;
69 	bus_space_handle_t	sc_regh;
70 
71 
72 	int			sc_poll;
73 
74 	struct i2c_controller	sc_i2c;
75 	struct rwlock		sc_lock;
76 };
77 
78 int			mgiic_match(struct device *, void *, void *);
79 void			mgiic_attach(struct device *, struct device *, void *);
80 
81 struct cfdriver mgiic_cd = {
82         NULL, "mgiic", DV_DULL
83 };
84 
85 const struct cfattach mgiic_ca = {
86         sizeof(struct mgiic_softc), mgiic_match, mgiic_attach
87 };
88 
89 int			mgiic_i2c_acquire_bus(void *, int);
90 void			mgiic_i2c_release_bus(void *, int);
91 int			mgiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
92 			    size_t, void *, size_t, int);
93 
94 int			mgiic_xmit(struct mgiic_softc *, u_int8_t, const u_int8_t *,
95 			    size_t);
96 int			mgiic_recv(struct mgiic_softc *, u_int8_t, u_int8_t *, size_t);
97 volatile u_int8_t	mgiic_read(struct mgiic_softc *, bus_size_t);
98 volatile void		mgiic_write(struct mgiic_softc *, bus_size_t, u_int8_t);
99 volatile void		mgiic_control(struct mgiic_softc *, u_int8_t, u_int8_t);
100 int			mgiic_poll(struct mgiic_softc *);
101 
102 int
103 mgiic_match(struct device *parent, void *match, void *aux)
104 {
105 	struct mainbus_attach_args *ma = aux;
106 	char compat[32];
107 
108 	if (strcmp(ma->ma_name, "i2c") != 0)
109 		return (0);
110 	if (OF_getprop(ma->ma_node, "compatible", compat, sizeof(compat)) == -1)
111 		return (0);
112 	if (strcmp(compat, "fire-i2c") == 0)
113 		return (1);
114 	return (0);
115 }
116 
117 void
118 mgiic_attach(struct device *parent, struct device *self, void *aux)
119 {
120 	struct mgiic_softc *sc = (struct mgiic_softc *)self;
121 	struct mainbus_attach_args *ma = aux;
122 	struct i2cbus_attach_args iba;
123 
124 	sc->sc_bt = ma->ma_bustag;
125 
126 	if (bus_space_map(sc->sc_bt, ma->ma_reg[0].ur_paddr,
127 	    ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) {
128 		printf(": failed to map preg\n");
129 		return;
130 	}
131 
132 	rw_init(&sc->sc_lock, "iiclk");
133 	sc->sc_i2c.ic_cookie = sc;
134 	sc->sc_i2c.ic_acquire_bus = mgiic_i2c_acquire_bus;
135 	sc->sc_i2c.ic_release_bus = mgiic_i2c_release_bus;
136 	sc->sc_i2c.ic_exec = mgiic_i2c_exec;
137 
138 	printf("\n");
139 
140 	bzero(&iba, sizeof(iba));
141 	iba.iba_name = "iic";
142 	iba.iba_tag = &sc->sc_i2c;
143 	iba.iba_bus_scan = ofwiic_scan;
144 	iba.iba_bus_scan_arg = &ma->ma_node;
145 	config_found(&sc->sc_dev, &iba, iicbus_print);
146 }
147 
148 int
149 mgiic_i2c_acquire_bus(void *arg, int flags)
150 {
151 	struct mgiic_softc     *sc = arg;
152 
153 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
154 		return (0);
155 
156 	return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
157 }
158 
159 void
160 mgiic_i2c_release_bus(void *arg, int flags)
161 {
162 	struct mgiic_softc     *sc = arg;
163 
164 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
165 		return;
166 
167 	rw_exit(&sc->sc_lock);
168 }
169 
170 int
171 mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
172     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
173 {
174 	struct mgiic_softc	*sc = arg;
175 	int			ret = 0;
176 
177 	if (addr & ~0x7f)
178 		return (1);
179 
180 	if (cold || sc->sc_poll)
181 		flags |= I2C_F_POLL;
182 
183 	if (cmdlen > 0) {
184 		ret = mgiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen);
185 		if (ret != 0)
186 			goto done;
187 	}
188 
189 	if (len > 0) {
190 		if (I2C_OP_WRITE_P(op))
191 			ret = mgiic_xmit(sc, addr & 0x7f, buf, len);
192 		else
193 			ret = mgiic_recv(sc, addr & 0x7f, buf, len);
194 	}
195 done:
196 	printf("e%d\n", ret);
197 	return (ret);
198 }
199 
200 int
201 mgiic_xmit(struct mgiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
202     size_t len)
203 {
204 	int err = 1, i = 0;
205 
206 top:
207 	printf("xmit s%02x STA ", mgiic_read(sc, MGSTATUS));
208 	mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG);
209 
210 	if (mgiic_poll(sc))
211 		goto bail;
212 	printf("s%02x ", mgiic_read(sc, MGSTATUS));
213 	if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT)
214 		goto bail;
215 
216 	mgiic_write(sc, MGDATA, addr << 1);
217 	printf("a%02x ", addr << 1);
218 	mgiic_control(sc, 0, MGCONTROL_IFLG);
219 
220 	while (i < len) {
221 		if (mgiic_poll(sc))
222 			 goto bail;
223 		printf("s%02x ", mgiic_read(sc, MGSTATUS));
224 		switch (mgiic_read(sc, MGSTATUS)) {
225 		case MGSTATUS_ADDR_W_ACKR:
226 		case MGSTATUS_MDATA_ACKR:
227 			mgiic_write(sc, MGDATA, buf[i]);
228 			printf("w%02x ", buf[i]);
229 			i++;
230 			mgiic_control(sc, 0, MGCONTROL_IFLG);
231 			break;
232 		case MGSTATUS_ADDR_W_NOACKR:
233 		case MGSTATUS_MDATA_NOACKR:
234 			mgiic_write(sc, MGDATA, buf[i]);
235 			printf("w%02x ", buf[i]);
236 			mgiic_control(sc, 0, MGCONTROL_IFLG);
237 			break;
238 		case MGSTATUS_BUSERR:
239 			mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG);
240 			i = 0;
241 			if (mgiic_poll(sc))
242 				goto bail;
243 			goto top;
244 		case MGSTATUS_IDLE:
245 		default:
246 			err = 1;
247 			goto bail;
248 		}
249 	}
250 	printf("OK ");
251 	err = 0;
252 bail:
253 	if (err)
254 		printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS));
255 	mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG);
256 	while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE)
257 		;
258 	printf("s%02x\n", mgiic_read(sc, MGSTATUS));
259 	return (err);
260 }
261 
262 int
263 mgiic_recv(struct mgiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
264 {
265 	int err = 1, i = 0;
266 
267 	printf("recv s%02x ", mgiic_read(sc, MGSTATUS));
268 	mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG);
269 	if (mgiic_poll(sc))
270 		goto bail;
271 
272 	printf("s%02x ", mgiic_read(sc, MGSTATUS));
273 	if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT)
274 		goto bail;
275 
276 re_address:
277 	mgiic_write(sc, MGDATA, (addr << 1) | 0x01);
278 	printf("a%02x ", (addr << 1) | 0x01);
279 	mgiic_control(sc, 0, MGCONTROL_IFLG);
280 
281 	while (i < len) {
282 		if (mgiic_poll(sc))
283 			goto bail;
284 		printf("s%02x ", mgiic_read(sc, MGSTATUS));
285 		switch (mgiic_read(sc, MGSTATUS)) {
286 		case MGSTATUS_ADDR_R_ACKR:
287 			if (len - i > 1)
288 				mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG);
289 			else
290 				mgiic_control(sc, 0, MGCONTROL_IFLG);
291 			break;
292 		case MGSTATUS_ADDR_R_NOACKR:
293 			mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG);
294 			break;
295 		case MGSTATUS_REPEATSTART:
296 			goto re_address;
297 		case MGSTATUS_MDATA_ACKT:
298 			buf[i] = mgiic_read(sc, MGDATA);
299 			printf("r%02x ", buf[i]);
300 			i++;
301 			if (len - i > 1)
302 				mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG);
303 			else
304 				mgiic_control(sc, 0, MGCONTROL_IFLG|MGCONTROL_AAK);
305 			break;
306 		case MGSTATUS_MDATA_NOACKT:
307 			buf[i] = mgiic_read(sc, MGDATA);
308 			printf("r%02x ", buf[i]);
309 			i++;
310 			if (len == i) {
311 				printf("DONE ");
312 				err = 0;
313 				goto bail;
314 			}
315 			printf("SHORT ");
316 			goto bail;
317 			break;
318 		default:
319 			printf("BAD");
320 			goto bail;
321 		}
322 	}
323 	printf("OK ");
324 	err = 0;
325 bail:
326 	if (err)
327 		printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS));
328 	mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG | MGCONTROL_AAK);
329 	while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE)
330 		;
331 	printf("s%02x\n", mgiic_read(sc, MGSTATUS));
332 	return (err);
333 }
334 
335 volatile u_int8_t
336 mgiic_read(struct mgiic_softc *sc, bus_size_t r)
337 {
338 	bus_space_barrier(sc->sc_bt, sc->sc_regh, r, 8,
339 	    BUS_SPACE_BARRIER_READ);
340 	return (bus_space_read_8(sc->sc_bt, sc->sc_regh, r)) & 0xff;
341 }
342 
343 volatile void
344 mgiic_write(struct mgiic_softc *sc, bus_size_t r, u_int8_t v)
345 {
346 	u_int64_t val = v;
347 
348 	bus_space_write_8(sc->sc_bt, sc->sc_regh, r, val);
349 	bus_space_barrier(sc->sc_bt, sc->sc_regh, r, 8,
350 	    BUS_SPACE_BARRIER_WRITE);
351 }
352 
353 volatile void
354 mgiic_control(struct mgiic_softc *sc, u_int8_t on, u_int8_t off)
355 {
356 	u_int8_t val;
357 
358 	val = (mgiic_read(sc, MGCONTROL) | on) & ~off;
359 	mgiic_write(sc, MGCONTROL, val);
360 }
361 
362 int
363 mgiic_poll(struct mgiic_softc *sc)
364 {
365 	int		i;
366 
367 	for (i = 0; i < 1000; i++) {
368 		if (mgiic_read(sc, MGCONTROL) & MGCONTROL_IFLG)
369 			return (0);
370 		delay(100);
371 	}
372 	return (1);
373 }
374