fire_i2c.c revision 1.5 1 /* $NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $ */
2
3 /*-
4 * Copyright (c) 2026 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julian Coleman.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $");
34
35 #include <sys/param.h>
36 #include <sys/condvar.h>
37 #include <sys/device.h>
38 #include <sys/intr.h>
39 #include <sys/kernel.h>
40 #include <sys/mutex.h>
41
42 #include <machine/autoconf.h>
43 #include <machine/openfirm.h>
44
45 #include <dev/pci/pcivar.h>
46
47 #include <dev/i2c/i2cvar.h>
48 #include <sparc64/dev/fire_i2creg.h>
49 #include <sparc64/dev/iommureg.h>
50 #include <sparc64/dev/iommuvar.h>
51 #include <sparc64/dev/pyrovar.h>
52
53 #include "ioconf.h"
54
55 #define FIREI2C_DEBUG 0
56 #if FIREI2C_DEBUG > 0
57 int dlvl = 1; /* Set to 2 for verbose i2c ops output */
58 #define DPRINTF(n) if (dlvl >= n) printf
59 #else
60 #define DPRINTF(n) if (0) printf
61 #endif
62
63 #define FIREI2C_SCL_FREQ 100000 /* Target i2c clock frequency */
64 #define FIREI2C_OWN_ADDR 0x08 /* Our i2c slave address */
65
66 /* i2c clocks to match possible system clock frequencies (1/1, 1/2, 1/32) */
67 #define FIREI2C_CLK_FULL 0
68 #define FIREI2C_CLK_HALF 1
69 #define FIREI2C_CLK_TT 2
70 #define FIREI2C_CLK_LEN 3
71
72 /* i2c operations */
73 #define FIREI2C_OP_READ 0x01
74 #define FIREI2C_OP_WRITE 0x02
75 #define FIREI2C_OP_WR_RD 0x04
76
77 /* i2c stages */
78 #define FIREI2C_STAGE_IDLE 0x00
79 #define FIREI2C_STAGE_START 0x01
80 #define FIREI2C_STAGE_WR_ADDR 0x02
81 #define FIREI2C_STAGE_RE_ADDR 0x04
82 #define FIREI2C_STAGE_WRITE 0x08
83 #define FIREI2C_STAGE_REPSTART 0x10
84 #define FIREI2C_STAGE_READ 0x20
85 #define FIREI2C_STAGE_STOP 0x40
86
87 /* mainbus intr map/mask are only used for i2c interrupts, so put them here. */
88 struct mainbus_interrupt_map {
89 uint64_t paddr; /* phys addr mask */
90 uint32_t intr; /* interrupt mask */
91 int32_t cnode; /* child node */
92 uint32_t cintr; /* child interrupt */
93 } __packed;
94
95 struct mainbus_interrupt_map_mask {
96 uint64_t paddr; /* phys addr mask */
97 uint32_t intr; /* interrupt */
98 } __packed;
99
100 struct firei2c_softc {
101 device_t sc_dev;
102 bus_space_tag_t sc_bustag;
103 bus_space_handle_t sc_regh;
104 int sc_node;
105 void *sc_inth;
106
107 uint8_t sc_i2c_clks[FIREI2C_CLK_LEN]; /* Clocks for sys bus speeds */
108
109 struct i2c_controller sc_i2c;
110
111 kmutex_t sc_mutex; /* Interrupt mutex ... */
112 kcondvar_t sc_cv; /* ... and condvar */
113
114 int sc_op; /* Operation to run */
115 int sc_stage; /* Exec stage */
116 i2c_addr_t sc_target; /* Saved exec args */
117 const u_int8_t *sc_cmdbuf; /* ... */
118 size_t sc_cmdlen; /* ... */
119 u_int8_t *sc_buf; /* ... */
120 size_t sc_buflen; /* ... */
121 int sc_i; /* How far through buf */
122 int sc_err; /* Error during transaction */
123
124 };
125
126 static int firei2c_match(device_t, cfdata_t, void *);
127 static void firei2c_attach(device_t, device_t, void *);
128 static void firei2c_intr_establish(struct firei2c_softc *,
129 struct mainbus_attach_args *);
130 static uint8_t firei2c_clock(int);
131 static int firei2c_stop(struct firei2c_softc *);
132 static int firei2c_wait(struct firei2c_softc *, int);
133 int firei2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
134 size_t, void *, size_t, int);
135 static int firei2c_write(struct firei2c_softc *, const uint8_t *, size_t,
136 uint8_t *, size_t, int);
137 static int firei2c_read(struct firei2c_softc *, uint8_t *, size_t, int);
138 int firei2c_intr(void *);
139 static uint8_t firei2c_reg_read(struct firei2c_softc *, bus_size_t);
140 static void firei2c_reg_write(struct firei2c_softc *, bus_size_t, uint8_t);
141
142 CFATTACH_DECL_NEW(firei2c, sizeof(struct firei2c_softc),
143 firei2c_match, firei2c_attach, NULL, NULL);
144
145 static int
146 firei2c_match(device_t parent, cfdata_t cf, void *aux)
147 {
148 struct mainbus_attach_args *ma = aux;
149 char *compat;
150
151 if (strcmp(ma->ma_name, "i2c"))
152 return 0;
153
154 compat = prom_getpropstring(ma->ma_node, "compatible");
155 if (!strcmp(compat, "fire-i2c"))
156 return 1;
157
158 return 0;
159 }
160
161 static void
162 firei2c_attach(device_t parent, device_t self, void *aux)
163 {
164 struct firei2c_softc *sc = device_private(self);
165 struct mainbus_attach_args *ma = aux;
166 int sysclk;
167
168 sc->sc_bustag = ma->ma_bustag;
169 sc->sc_node = ma->ma_node;
170 sc->sc_dev = self;
171
172 if (ma->ma_nreg != 1) {
173 aprint_error(": register count error (%d != 1)\n",
174 ma->ma_nreg);
175 return;
176 }
177 if (ma->ma_reg[0].ur_len < FIREI2C_SRST) {
178 aprint_error(": register length error (%" PRId64 " < %d\n",
179 ma->ma_reg[0].ur_len, FIREI2C_SRST);
180 return;
181 }
182
183 if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr,
184 ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) {
185 aprint_error(": failed to map registers\n");
186 return;
187 }
188
189 aprint_normal(": addr %" PRIx64 ": Fire/MI2C i2c controller\n",
190 ma->ma_reg[0].ur_paddr);
191
192 firei2c_intr_establish(sc, ma);
193
194 /* Calculate clock, software reset, set our address */
195 sysclk = prom_getpropint(findroot(), "clock-frequency", 0);
196 sc->sc_i2c_clks[FIREI2C_CLK_FULL] = firei2c_clock(sysclk);
197 sc->sc_i2c_clks[FIREI2C_CLK_HALF] = firei2c_clock(sysclk / 2);
198 sc->sc_i2c_clks[FIREI2C_CLK_TT] = firei2c_clock(sysclk / 32);
199 firei2c_reg_write(sc, FIREI2C_SRST, FIREI2C_SRST_RST);
200 delay(1000);
201 firei2c_reg_write(sc, FIREI2C_CCR, sc->sc_i2c_clks[FIREI2C_CLK_FULL]);
202 firei2c_reg_write(sc, FIREI2C_ADDR,
203 FIREI2C_OWN_ADDR << FIREI2C_ADDR_SHIFT);
204
205 /* i2c setup */
206 iic_tag_init(&sc->sc_i2c);
207 sc->sc_i2c.ic_cookie = sc;
208 sc->sc_i2c.ic_exec = firei2c_exec;
209
210 /* Synchronisation between exec and intr */
211 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
212 cv_init(&sc->sc_cv, "firei2c");
213 sc->sc_stage = FIREI2C_STAGE_IDLE;
214
215 iicbus_attach(sc->sc_dev, &sc->sc_i2c);
216 return;
217 }
218
219 /*
220 * Use the mainbus (root) interrupt map/mask to find our interrupt number
221 * (ino 60 or 61) and pyro leaf.
222 * Both i2c interrupts must go to the same pyro leaf, but we assume that
223 * OFW has set up the ino and the leaf mapping for us.
224 */
225 #define IMASK_LEN 3
226 #define IMAP_LEN 10
227 static void
228 firei2c_intr_establish(struct firei2c_softc *sc,
229 struct mainbus_attach_args *ma)
230 {
231 struct mainbus_interrupt_map *mb_imap;
232 struct mainbus_interrupt_map_mask *mb_imask;
233 struct pyro_softc *psc = NULL;
234 int64_t paddr;
235 u_int intr;
236 int ihandle, root, size, i;
237
238 sc->sc_inth = NULL; /* Default */
239 ihandle = 0;
240
241 /* Find our mapped interrupt number */
242 root = findroot();
243 mb_imask = NULL;
244 if (prom_getprop(root, "interrupt-map-mask",
245 sizeof(int32_t), &size, (void **) &mb_imask) ||
246 size != IMASK_LEN) {
247 aprint_error(": no interrupt-map-mask\n");
248 return;
249 }
250
251 mb_imap = NULL;
252 if (prom_getprop(root, "interrupt-map",
253 sizeof(int32_t), &size, (void **) &mb_imap) ||
254 size != IMAP_LEN) {
255 aprint_error(": no interrupt-map\n");
256 return;
257 }
258
259 intr = ma->ma_interrupts[0] && mb_imask->intr;
260 DPRINTF(1)("%s: intr %x masked to %x\n",
261 device_xname(sc->sc_dev), ma->ma_interrupts[0], intr);
262 paddr = ma->ma_reg[0].ur_paddr & mb_imask->paddr;
263 DPRINTF(1)("%s: reg 0x%" PRIx64 " masked to 0x%" PRIx64 "\n",
264 device_xname(sc->sc_dev), ma->ma_reg[0].ur_paddr, paddr);
265 for (i = 0; i < 2; i++) {
266 DPRINTF(1)("%s: checking paddr 0x%" PRIx64 ", intr %x\n",
267 device_xname(sc->sc_dev), mb_imap->paddr, mb_imap->intr);
268 if (paddr == mb_imap->paddr && intr == mb_imap->intr) {
269 ihandle = mb_imap->cintr;
270 DPRINTF(1)("%s: found cintr %d, cnode 0x%x\n",
271 device_xname(sc->sc_dev), ihandle, mb_imap->cnode);
272 break;
273 }
274 mb_imap++;
275 }
276 if (ihandle == 0) {
277 aprint_error(": failed to match interrupt\n");
278 return;
279 }
280
281 /* Find the pyro leaf with the matching cnode ) */
282 for (i = 0; i < pyro_cd.cd_ndevs; i++) {
283 device_t dt = device_lookup(&pyro_cd, i);
284 psc = device_private(dt);
285 if (psc && psc->sc_node == mb_imap->cnode) {
286 DPRINTF(1)("%s: matched pyro %d (0x%x)\n",
287 device_xname(sc->sc_dev), i, psc->sc_node);
288 ihandle |= psc->sc_ign;
289 break;
290 }
291 }
292 if (psc == NULL) {
293 aprint_error(": failed to match pyro leaf\n");
294 return;
295 }
296
297 sc->sc_inth = psc->intr_establish_sc(psc,
298 ihandle, IPL_BIO, firei2c_intr, sc, NULL);
299
300 if (sc->sc_inth != NULL) {
301 aprint_normal_dev(sc->sc_dev,
302 "interrupting at ivec %x on pyro%d\n", ihandle, i);
303 }
304
305 return;
306 }
307
308 /*
309 * Sampling frequency: input clock divided by 2^N (N is bits 0:2)
310 * SCL frequency: sampling frequency divided by (M + 1) * 10 (bits 3:6)
311 * i2c SCL is max 100kHz, so find the closest frequency at or below that.
312 *
313 * If the system (JBus) clock frequency changes, we must change our clock.
314 * If increasing: after the JBus change, if decreasing: before the change.
315 * This is to avoid running the i2c clock faster than the specification.
316 */
317 static uint8_t
318 firei2c_clock(int sysclk)
319 {
320 int p, f, best_p, best_f;
321 uint32_t sample, scl;
322 uint32_t min = FIREI2C_SCL_FREQ;
323 uint8_t clkval;
324
325 best_p = 0;
326 best_f = 0;
327 for (p = 0; p <= FIREI2C_CCR_POW2_MAX; p++) {
328 if (p)
329 sample = sysclk / (2 << (p - 1));
330 else
331 sample = sysclk;
332 for (f = 0; f <= FIREI2C_CCR_FACT_MAX; f++) {
333 scl = sample / ((f + 1) * 10);
334 if (scl <= FIREI2C_SCL_FREQ) {
335 if (FIREI2C_SCL_FREQ - scl < min) {
336 best_p = p;
337 best_f = f;
338 min = FIREI2C_SCL_FREQ - scl;
339 }
340 break; /* Already at or below SCL_FREQ */
341 }
342 }
343 if (!min) /* Exactly SCL_FREQ */
344 break;
345 }
346 clkval = best_p + (best_f << FIREI2C_CCR_FACT_SHIFT);
347 return clkval;
348 }
349
350 /* No interrupts for stop, so wait for idle */
351 static int
352 firei2c_stop(struct firei2c_softc *sc)
353 {
354 int i;
355 uint8_t ctrl, val;
356
357 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_STP;
358 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
359 for (i = 0; i < 500; i++) {
360 val = firei2c_reg_read(sc, FIREI2C_STAT);
361 if (val == FIREI2C_STAT_IDLE) {
362 mutex_enter(&sc->sc_mutex);
363 sc->sc_stage = FIREI2C_STAGE_IDLE;
364 mutex_exit(&sc->sc_mutex);
365 return 0;
366 }
367 delay(1000);
368 }
369 /* Clear the interrupt flag if we timed out */
370 ctrl = FIREI2C_CTRL_ENAB;
371 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
372 /* Set the stage to idle, even for timeout */
373 mutex_enter(&sc->sc_mutex);
374 sc->sc_stage = FIREI2C_STAGE_IDLE;
375 mutex_exit(&sc->sc_mutex);
376 return 1;
377 }
378
379
380 static int
381 firei2c_wait(struct firei2c_softc *sc, int flags)
382 {
383 volatile uint8_t ctrl;
384 int i;
385
386 for (i = 0; i < 500; i++) {
387 ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
388 if (ctrl & FIREI2C_CTRL_IFLG)
389 return 0;
390 delay(1000);
391 }
392 return 1;
393 }
394
395 /*
396 * Flow for a "simple" read/write:
397 * 1. Send start
398 * 2. Send addr + R or W
399 * 3. Receive ACK
400 * 4. (nothing)
401 * 5. (nothing)
402 * 6R. Receive data 6W. Send data
403 * 7R. Send ACK or NAK 7W. Receive ACK or NAK
404 * either receive more (6R) or either write more (6W) or
405 * 8. Send stop
406 *
407 * Flow for read/write following a "register" write:
408 * 1. Send start
409 * 2. Send addr + W
410 * 3. Receive ACK
411 * 4. Send register
412 * 5R. Send repeat start + addr + R 5W. (nothing to do)
413 * 6R. Receive data 6W. Send data
414 * 7R. Send ACK or NAK 7W. Receive ACK or NAK
415 * either receive more (6R) or either write more (6W) or
416 * 8. Send stop
417 *
418 * After each step, we receive an interrupt notifying us of the result.
419 * We clear the interrupt flag, check the status, and set up the next step.
420 * If we're polling, we check the flag in a loop instead.
421 */
422 int
423 firei2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmd,
424 size_t cmdlen, void *vbuf, size_t buflen, int flags)
425 {
426 struct firei2c_softc *sc = arg;
427 const uint8_t *cmdbuf = cmd;
428 uint8_t *buf = vbuf;
429 uint8_t ctrl, val, ack, nack;
430 unsigned deadline, rem;
431 int err;
432
433 DPRINTF(1)("%s: exec op: %d addr: 0x%x "
434 "cmdlen: %d buflen: %d flags 0x%x, intr %s, poll %s\n",
435 device_xname(sc->sc_dev), op, addr,
436 (int) cmdlen, (int) buflen, flags,
437 sc->sc_inth == NULL ? "no" : "yes",
438 flags & I2C_F_POLL ? "yes" : "no");
439 val = firei2c_reg_read(sc, FIREI2C_STAT);
440 if (val != FIREI2C_STAT_IDLE) {
441 /* Try sending stop */
442 DPRINTF(1)("%s: not idle, sending stop\n",
443 device_xname(sc->sc_dev));
444 err = firei2c_stop(sc);
445 if (err) {
446 printf("%s: not idle (0x%02x)\n",
447 device_xname(sc->sc_dev), val);
448 return 1;
449 }
450 }
451
452 /* Control defaults - bus enabled, interrupts enabled */
453 ctrl = FIREI2C_CTRL_ENAB;
454 if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) {
455 ctrl |= FIREI2C_CTRL_IEN;
456 sc->sc_target = addr;
457 sc->sc_cmdbuf = cmdbuf;
458 sc->sc_cmdlen = cmdlen;
459 sc->sc_buf = buf;
460 sc->sc_buflen = buflen;
461 sc->sc_i = 0;
462 sc->sc_err = 0;
463 if (I2C_OP_READ_P(op))
464 if (cmdlen > 0)
465 sc->sc_op = FIREI2C_OP_WR_RD;
466 else
467 sc->sc_op = FIREI2C_OP_READ;
468 else
469 sc->sc_op = FIREI2C_OP_WRITE;
470 mutex_enter(&sc->sc_mutex);
471 sc->sc_stage = FIREI2C_STAGE_START;
472 mutex_exit(&sc->sc_mutex);
473 }
474
475 /* Send start */
476 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl | FIREI2C_CTRL_STA);
477
478 /* Interrupt-driven */
479 if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) {
480 /* Wait for the transfer to complete (stop). */
481 deadline = getticks() +
482 /*timeout*/ hz / 10 + 10 * (cmdlen + buflen);
483 mutex_enter(&sc->sc_mutex);
484 while (sc->sc_stage != FIREI2C_STAGE_STOP) {
485 rem = deadline - getticks();
486 if (!rem || rem >= INT_MAX) {
487 printf("%s: intr timeout\n",
488 device_xname(sc->sc_dev));
489 sc->sc_stage = FIREI2C_STAGE_STOP;
490 err = sc->sc_err | 1;
491 break;
492 }
493 cv_timedwait(&sc->sc_cv, &sc->sc_mutex, rem);
494 }
495 mutex_exit(&sc->sc_mutex);
496 err = sc->sc_err;
497 goto stop;
498 }
499
500 /*
501 * If we are writing, write addr, cmd, buf.
502 * If we are reading, either:
503 * write addr, cmd, repeat-start, then read addr to buf, or:
504 * read addr to buf.
505 * Send stop
506 */
507 err = firei2c_wait(sc, flags);
508 val = firei2c_reg_read(sc, FIREI2C_STAT);
509 if (err) {
510 printf("%s: start timeout 0x%x\n",
511 device_xname(sc->sc_dev), val);
512 goto stop;
513 }
514 if (val != FIREI2C_STAT_STA) {
515 printf("%s: start error 0x%x\n",
516 device_xname(sc->sc_dev), val);
517 err = 1;
518 goto stop;
519 }
520
521 /* Address + r/w in data, then send ctrl */
522 val = addr << FIREI2C_DATA_SHIFT;
523 if (I2C_OP_WRITE_P(op) || cmdlen > 0) {
524 ack = FIREI2C_STAT_AWR_ACK;
525 nack = FIREI2C_STAT_AWR_NAK;
526 } else {
527 val |= 0x01;
528 ack = FIREI2C_STAT_ARE_ACK;
529 nack = FIREI2C_STAT_ARE_NAK;
530 }
531 firei2c_reg_write(sc, FIREI2C_DATA, val);
532 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
533 err = firei2c_wait(sc, flags);
534 val = firei2c_reg_read(sc, FIREI2C_STAT);
535 if (err) {
536 printf("%s: addr timeout 0x%x\n",
537 device_xname(sc->sc_dev), val);
538 goto stop;
539 }
540 if (val != ack) {
541 if (val != nack) /* Don't print for NACK */
542 printf("%s: addr error 0x%x\n",
543 device_xname(sc->sc_dev), val);
544 err = 1;
545 goto stop;
546 }
547
548 err = 0;
549 if (I2C_OP_READ_P(op)) {
550 if (cmdlen > 0) {
551 /* Write register */
552 err = firei2c_write(sc, cmd, cmdlen,
553 NULL, 0, flags);
554 if (err)
555 goto stop;
556
557 /* Send repeat start */
558 firei2c_reg_write(sc, FIREI2C_CTRL,
559 ctrl | FIREI2C_CTRL_STA);
560 err = firei2c_wait(sc, flags);
561 val = firei2c_reg_read(sc, FIREI2C_STAT);
562 if (err) {
563 printf("%s: repeat start timeout 0x%x\n",
564 device_xname(sc->sc_dev), val);
565 goto stop;
566 }
567 if (val != FIREI2C_STAT_REPSTA) {
568 printf("%s: repeat start error 0x%x\n",
569 device_xname(sc->sc_dev), val);
570 err = 1;
571 goto stop;
572 }
573
574 /* Address + r in data, then send ctrl */
575 val = addr << FIREI2C_DATA_SHIFT;
576 val |= 0x01;
577 ack = FIREI2C_STAT_ARE_ACK;
578 nack = FIREI2C_STAT_ARE_NAK;
579 firei2c_reg_write(sc, FIREI2C_DATA, val);
580 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
581 err = firei2c_wait(sc, flags);
582 val = firei2c_reg_read(sc, FIREI2C_STAT);
583 if (err) {
584 printf("%s: addr timeout 0x%x\n",
585 device_xname(sc->sc_dev), val);
586 goto stop;
587 }
588 if (val != ack) {
589 if (val != nack)
590 printf("%s: addr error 0x%x\n",
591 device_xname(sc->sc_dev), val);
592 err = 1;
593 goto stop;
594 }
595 }
596
597 /* Read data */
598 err = firei2c_read(sc, buf, buflen, flags);
599 } else
600 /* Write data or register + data */
601 err = firei2c_write(sc, cmd, cmdlen, buf, buflen, flags);
602
603 stop:
604 err |= firei2c_stop(sc);
605
606 return err;
607 }
608
609 static int
610 firei2c_write(struct firei2c_softc *sc, const uint8_t *cmd, size_t cmdlen,
611 uint8_t *buf, size_t buflen, int flags)
612 {
613 uint8_t ctrl, val;
614 int i, err;
615
616 DPRINTF(2)("%s: write %ld\n",
617 device_xname(sc->sc_dev), cmdlen + buflen);
618 ctrl = FIREI2C_CTRL_ENAB;
619 for (i = 0; i < cmdlen + buflen; i++) {
620 /* Bytes in data, then send ctrl */
621 if (i < cmdlen)
622 val = cmd[i];
623 else
624 val = buf[i - cmdlen];
625 firei2c_reg_write(sc, FIREI2C_DATA, val);
626 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
627 err = firei2c_wait(sc, flags);
628 val = firei2c_reg_read(sc, FIREI2C_STAT);
629 if (err) {
630 printf("%s: write timeout 0x%x\n",
631 device_xname(sc->sc_dev), val);
632 return 1;
633 }
634 if (val != FIREI2C_STAT_DAT_ACK) {
635 if (val != FIREI2C_STAT_DAT_NAK)
636 printf("%s: write error 0x%x\n",
637 device_xname(sc->sc_dev), val);
638 return 1;
639 }
640
641 }
642 return 0;
643 }
644
645 static int
646 firei2c_read(struct firei2c_softc *sc, uint8_t *buf, size_t buflen, int flags)
647 {
648 uint8_t ctrl, val, ack;
649 int i, err;
650
651 DPRINTF(2)("%s: read %ld\n", device_xname(sc->sc_dev), buflen);
652 for (i = 0; i < buflen; i++) {
653 /* Send ACK on all but last byte */
654 if (i < buflen - 1) {
655 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_AAK;
656 ack = FIREI2C_STAT_MDAT_ACK;
657 } else {
658 ctrl = FIREI2C_CTRL_ENAB;
659 ack = FIREI2C_STAT_MDAT_NAK;
660 }
661 /* Send ctrl, then bytes in data */
662 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
663 err = firei2c_wait(sc, flags);
664 val = firei2c_reg_read(sc, FIREI2C_STAT);
665 if (err) {
666 printf("%s: read timeout 0x%x\n",
667 device_xname(sc->sc_dev), val);
668 return 1;
669 }
670 if (val != ack) {
671 printf("%s: read error 0x%x\n",
672 device_xname(sc->sc_dev), val);
673 return 1;
674 }
675 buf[i] = firei2c_reg_read(sc, FIREI2C_DATA);
676 }
677 return 0;
678 }
679
680 /*
681 * When we receive an interrupt, check the status versus the step
682 * and set up the next stage.
683 * See the comments before firei2c_exec() for the list of steps.
684 */
685 int
686 firei2c_intr(void *arg)
687 {
688 struct firei2c_softc *sc = arg;
689 uint8_t ctrl, val;
690
691 mutex_enter(&sc->sc_mutex);
692 ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
693 if (ctrl & FIREI2C_CTRL_IFLG) {
694 /* Disable interrupts */
695 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl & ~FIREI2C_CTRL_IEN);
696 }
697
698 if (sc->sc_stage == FIREI2C_STAGE_IDLE) {
699 DPRINTF(1)("%s: intr and idle\n", device_xname(sc->sc_dev));
700 mutex_exit(&sc->sc_mutex);
701 return 0;
702 }
703
704 ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_IEN;
705 val = firei2c_reg_read(sc, FIREI2C_STAT);
706
707 switch (sc->sc_stage) {
708 case FIREI2C_STAGE_START:
709 DPRINTF(2)("%s: intr start, op %x\n",
710 device_xname(sc->sc_dev), sc->sc_op);
711 if (val != FIREI2C_STAT_STA) {
712 printf("%s: intr start error 0x%02x\n",
713 device_xname(sc->sc_dev), val);
714 sc->sc_err = 1;
715 sc->sc_stage = FIREI2C_STAGE_STOP;
716 break;
717 }
718
719 /* Address + r/w in data, then send ctrl */
720 val = sc->sc_target << FIREI2C_DATA_SHIFT;
721 if (sc->sc_op == FIREI2C_OP_READ) {
722 val |= 0x01;
723 sc->sc_stage = FIREI2C_STAGE_RE_ADDR;
724 } else
725 sc->sc_stage = FIREI2C_STAGE_WR_ADDR;
726 firei2c_reg_write(sc, FIREI2C_DATA, val);
727 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
728 break;
729
730 case FIREI2C_STAGE_WR_ADDR:
731 DPRINTF(2)("%s: intr addr(w) 0x%02x = 0x%02x\n",
732 device_xname(sc->sc_dev), sc->sc_target, val);
733 if (val != FIREI2C_STAT_AWR_ACK) {
734 if (val != FIREI2C_STAT_AWR_NAK)
735 printf("%s: intr addr(w) error 0x%02x\n",
736 device_xname(sc->sc_dev), val);
737 sc->sc_err = 1;
738 sc->sc_stage = FIREI2C_STAGE_STOP;
739 break;
740 }
741
742 sc->sc_stage = FIREI2C_STAGE_WRITE;
743 val = FIREI2C_STAT_DAT_ACK; /* For write */
744 /* Fallthrough */
745
746 case FIREI2C_STAGE_WRITE:
747 DPRINTF(2)("%s: intr write 0x%02x = 0x%02x\n",
748 device_xname(sc->sc_dev), sc->sc_target, val);
749 if (val != FIREI2C_STAT_DAT_ACK) {
750 if (val != FIREI2C_STAT_DAT_NAK)
751 printf("%s: intr write error 0x%02x\n",
752 device_xname(sc->sc_dev), val);
753 sc->sc_err = 1;
754 sc->sc_stage = FIREI2C_STAGE_STOP;
755 break;
756 }
757
758 /* Start the write from cmd */
759 if (sc->sc_i < sc->sc_cmdlen) {
760 firei2c_reg_write(sc, FIREI2C_DATA,
761 sc->sc_cmdbuf[sc->sc_i]);
762 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
763 sc->sc_i++;
764 break;
765 }
766
767 /* If a read OP, switch with repeat start after writing cmd */
768 if (sc->sc_op == FIREI2C_OP_WR_RD) {
769 sc->sc_i = 0;
770 sc->sc_stage = FIREI2C_STAGE_REPSTART;
771 ctrl |= FIREI2C_CTRL_STA;
772 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
773 break;
774 }
775
776 /* If a write OP, continue the write, now from buf */
777 if (sc->sc_i < sc->sc_cmdlen + sc->sc_buflen) {
778 firei2c_reg_write(sc, FIREI2C_DATA,
779 sc->sc_buf[sc->sc_i - sc->sc_cmdlen]);
780 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
781 sc->sc_i++;
782 } else {
783 sc->sc_stage = FIREI2C_STAGE_STOP;
784 }
785 break;
786
787 case FIREI2C_STAGE_REPSTART:
788 DPRINTF(2)("%s: intr repstart 0x%02x = 0x%02x\n",
789 device_xname(sc->sc_dev), sc->sc_target, val);
790 if (val != FIREI2C_STAT_REPSTA) {
791 printf("%s: intr repstart error 0x%02x\n",
792 device_xname(sc->sc_dev), val);
793 sc->sc_err = 1;
794 sc->sc_stage = FIREI2C_STAGE_STOP;
795 break;
796 }
797
798 /* Address + r in data, then send ctrl */
799 val = (sc->sc_target << FIREI2C_DATA_SHIFT) | 0x01;
800 sc->sc_stage = FIREI2C_STAGE_RE_ADDR;
801 firei2c_reg_write(sc, FIREI2C_DATA, val);
802 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
803 break;
804
805 case FIREI2C_STAGE_RE_ADDR:
806 DPRINTF(2)("%s: intr addr(r) 0x%02x = 0x%02x\n",
807 device_xname(sc->sc_dev), sc->sc_target, val);
808 if (val != FIREI2C_STAT_ARE_ACK) {
809 if (val != FIREI2C_STAT_ARE_NAK)
810 printf("%s: intr addr(r) error 0x%02x\n",
811 device_xname(sc->sc_dev), val);
812 sc->sc_err = 1;
813 sc->sc_stage = FIREI2C_STAGE_STOP;
814 break;
815 }
816
817 sc->sc_stage = FIREI2C_STAGE_READ;
818 val = FIREI2C_STAT_MDAT_NAK; /* For read */
819 /* Fallthrough */
820
821 case FIREI2C_STAGE_READ:
822 DPRINTF(2)("%s: intr read 0x%02x = 0x%02x\n",
823 device_xname(sc->sc_dev), sc->sc_target, val);
824 if (sc->sc_i > 0 && sc->sc_i < sc->sc_buflen) {
825 if (val != FIREI2C_STAT_MDAT_ACK) {
826 printf("%s: intr read error 0x%02x\n",
827 device_xname(sc->sc_dev), val);
828 sc->sc_err = 1;
829 sc->sc_stage = FIREI2C_STAGE_STOP;
830 break;
831 }
832 } else {
833 if (val != FIREI2C_STAT_MDAT_NAK) {
834 printf("%s: intr read error 0x%02x\n",
835 device_xname(sc->sc_dev), val);
836 sc->sc_err = 1;
837 sc->sc_stage = FIREI2C_STAGE_STOP;
838 break;
839 }
840 }
841
842 /* Data read is 1 cycle behind ctrl */
843 if (sc->sc_i > 0 && sc->sc_i <= sc->sc_buflen) {
844 sc->sc_buf[sc->sc_i - 1] =
845 firei2c_reg_read(sc, FIREI2C_DATA);
846 }
847
848 if (sc->sc_i == sc->sc_buflen) {
849 /* Last data was read */
850 sc->sc_stage = FIREI2C_STAGE_STOP;
851 } else {
852 /* Send ACK on all but last byte */
853 if (sc->sc_i < sc->sc_buflen - 1)
854 ctrl |= FIREI2C_CTRL_AAK;
855 firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
856 sc->sc_i++;
857 }
858 break;
859 }
860
861 if (sc->sc_stage == FIREI2C_STAGE_STOP) {
862 DPRINTF(2)("%s: intr stop (err=%d)\n",
863 device_xname(sc->sc_dev), sc->sc_err);
864 cv_signal(&sc->sc_cv);
865 }
866
867 mutex_exit(&sc->sc_mutex);
868
869 return 1;
870
871 }
872
873 static uint8_t
874 firei2c_reg_read(struct firei2c_softc *sc, bus_size_t reg)
875 {
876 uint32_t val;
877 bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
878 BUS_SPACE_BARRIER_READ);
879 val = bus_space_read_8(sc->sc_bustag, sc->sc_regh, reg);
880 return val & 0xff;
881 }
882
883 static void
884 firei2c_reg_write(struct firei2c_softc *sc, bus_size_t reg, uint8_t val)
885 {
886 bus_space_write_8(sc->sc_bustag, sc->sc_regh, reg, val);
887 bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
888 BUS_SPACE_BARRIER_WRITE);
889 }
890