1 /* $NetBSD: ausmbus_psc.c,v 1.16 2022/06/18 22:11:00 andvar Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Shigeyuki Fukushima.
5 * All rights reserved.
6 *
7 * Written by Shigeyuki Fukushima.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * 3. The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior
20 * written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ausmbus_psc.c,v 1.16 2022/06/18 22:11:00 andvar Exp $");
37
38 #include "locators.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/errno.h>
44
45 #include <sys/bus.h>
46 #include <machine/cpu.h>
47
48 #include <mips/alchemy/dev/aupscreg.h>
49 #include <mips/alchemy/dev/aupscvar.h>
50 #include <mips/alchemy/dev/ausmbus_pscreg.h>
51
52 #include <dev/i2c/i2cvar.h>
53 #include <dev/i2c/i2c_bitbang.h>
54
55 struct ausmbus_softc {
56 device_t sc_dev;
57
58 /* protocol comoon fields */
59 struct aupsc_controller sc_ctrl;
60
61 /* protocol specific fields */
62 struct i2c_controller sc_i2c;
63 i2c_addr_t sc_smbus_slave_addr;
64 int sc_smbus_timeout;
65 };
66
67 #define ausmbus_reg_read(sc, reg) \
68 bus_space_read_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg)
69 #define ausmbus_reg_write(sc, reg, val) \
70 bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg, \
71 val); \
72 delay(100);
73
74 static int ausmbus_match(device_t, struct cfdata *, void *);
75 static void ausmbus_attach(device_t, device_t, void *);
76
77 CFATTACH_DECL_NEW(ausmbus, sizeof(struct ausmbus_softc),
78 ausmbus_match, ausmbus_attach, NULL, NULL);
79
80 /* functions for i2c_controller */
81 static int ausmbus_acquire_bus(void *, int);
82 static void ausmbus_release_bus(void *, int);
83 static int ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
84 const void *cmd, size_t cmdlen, void *vbuf,
85 size_t buflen, int flags);
86
87 /* subroutine functions for i2c_controller */
88 static int ausmbus_quick_write(struct ausmbus_softc *);
89 static int ausmbus_quick_read(struct ausmbus_softc *);
90 static int ausmbus_receive_1(struct ausmbus_softc *, uint8_t *);
91 static int ausmbus_read_1(struct ausmbus_softc *, uint8_t, uint8_t *);
92 static int ausmbus_read_2(struct ausmbus_softc *, uint8_t, uint16_t *);
93 static int ausmbus_send_1(struct ausmbus_softc *, uint8_t);
94 static int ausmbus_write_1(struct ausmbus_softc *, uint8_t, uint8_t);
95 static int ausmbus_write_2(struct ausmbus_softc *, uint8_t, uint16_t);
96 static int ausmbus_wait_mastertx(struct ausmbus_softc *sc);
97 static int ausmbus_wait_masterrx(struct ausmbus_softc *sc);
98 static int ausmbus_initiate_xfer(void *, i2c_addr_t, int);
99 static int ausmbus_read_byte(void *arg, uint8_t *vp, int flags);
100 static int ausmbus_write_byte(void *arg, uint8_t v, int flags);
101
102
103 static int
ausmbus_match(device_t parent,struct cfdata * cf,void * aux)104 ausmbus_match(device_t parent, struct cfdata *cf, void *aux)
105 {
106 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;
107
108 if (strcmp(aa->aupsc_name, cf->cf_name) != 0)
109 return 0;
110
111 return 1;
112 }
113
114 static void
ausmbus_attach(device_t parent,device_t self,void * aux)115 ausmbus_attach(device_t parent, device_t self, void *aux)
116 {
117 struct ausmbus_softc *sc = device_private(self);
118 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux;
119 struct i2cbus_attach_args iba;
120
121 aprint_normal(": Alchemy PSC SMBus protocol\n");
122
123 sc->sc_dev = self;
124
125 /* Initialize PSC */
126 sc->sc_ctrl = aa->aupsc_ctrl;
127
128 /* Initialize i2c_controller for SMBus */
129 iic_tag_init(&sc->sc_i2c);
130 sc->sc_i2c.ic_cookie = sc;
131 sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus;
132 sc->sc_i2c.ic_release_bus = ausmbus_release_bus;
133 sc->sc_i2c.ic_exec = ausmbus_exec;
134 sc->sc_smbus_timeout = 10;
135
136 memset(&iba, 0, sizeof(iba));
137 iba.iba_tag = &sc->sc_i2c;
138 config_found(self, &iba, iicbus_print, CFARGS_NONE);
139 }
140
141 static int
ausmbus_acquire_bus(void * arg,int flags)142 ausmbus_acquire_bus(void *arg, int flags)
143 {
144 struct ausmbus_softc *sc = arg;
145 uint32_t v;
146
147 /* Select SMBus Protocol & Enable PSC */
148 sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS);
149 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
150 if ((v & SMBUS_STAT_SR) == 0) {
151 /* PSC is not ready */
152 return -1;
153 }
154
155 /* Setup SMBus Configuration register */
156 v = SMBUS_CFG_DD; /* Disable DMA */
157 v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8); /* Rx FIFO 8data */
158 v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8); /* Tx FIFO 8data */
159 v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8); /* pscn_mainclk/8 */
160 v &= ~SMBUS_CFG_SFM; /* Standard Mode */
161 ausmbus_reg_write(sc, AUPSC_SMBCFG, v);
162
163 /* Setup SMBus Protocol Timing register */
164 v = SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH)
165 | SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS)
166 | SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU)
167 | SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH)
168 | SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU)
169 | SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL)
170 | SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH);
171 ausmbus_reg_write(sc, AUPSC_SMBTMR, v);
172
173 /* Setup SMBus Mask register */
174 v = SMBUS_MSK_ALLMASK;
175 ausmbus_reg_write(sc, AUPSC_SMBMSK, v);
176
177 /* SMBus Enable */
178 v = ausmbus_reg_read(sc, AUPSC_SMBCFG);
179 v |= SMBUS_CFG_DE;
180 ausmbus_reg_write(sc, AUPSC_SMBCFG, v);
181 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
182 if ((v & SMBUS_STAT_SR) == 0) {
183 /* SMBus is not ready */
184 return -1;
185 }
186
187 #ifdef AUSMBUS_PSC_DEBUG
188 aprint_normal("AuSMBus enabled.\n");
189 aprint_normal("AuSMBus smbconfig: 0x%08x\n",
190 ausmbus_reg_read(sc, AUPSC_SMBCFG));
191 aprint_normal("AuSMBus smbstatus: 0x%08x\n",
192 ausmbus_reg_read(sc, AUPSC_SMBSTAT));
193 aprint_normal("AuSMBus smbtmr : 0x%08x\n",
194 ausmbus_reg_read(sc, AUPSC_SMBTMR));
195 aprint_normal("AuSMBus smbmask : 0x%08x\n",
196 ausmbus_reg_read(sc, AUPSC_SMBMSK));
197 #endif
198
199 return 0;
200 }
201
202 static void
ausmbus_release_bus(void * arg,int flags)203 ausmbus_release_bus(void *arg, int flags)
204 {
205 struct ausmbus_softc *sc = arg;
206
207 ausmbus_reg_write(sc, AUPSC_SMBCFG, 0);
208 sc->sc_ctrl.psc_disable(sc);
209
210 return;
211 }
212
213 static int
ausmbus_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * vcmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)214 ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
215 size_t cmdlen, void *vbuf, size_t buflen, int flags)
216 {
217 struct ausmbus_softc *sc = (struct ausmbus_softc *)cookie;
218 const uint8_t *cmd = vcmd;
219
220 sc->sc_smbus_slave_addr = addr;
221
222 /* Receive byte */
223 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 1)) {
224 return ausmbus_receive_1(sc, (uint8_t *)vbuf);
225 }
226
227 /* Read byte */
228 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) {
229 return ausmbus_read_1(sc, *cmd, (uint8_t *)vbuf);
230 }
231
232 /* Read word */
233 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) {
234 return ausmbus_read_2(sc, *cmd, (uint16_t *)vbuf);
235 }
236
237 /* Read quick */
238 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 0)) {
239 return ausmbus_quick_read(sc);
240 }
241
242 /* Send byte */
243 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) {
244 return ausmbus_send_1(sc, *((uint8_t *)vbuf));
245 }
246
247 /* Write byte */
248 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) {
249 return ausmbus_write_1(sc, *cmd, *((uint8_t *)vbuf));
250 }
251
252 /* Write word */
253 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) {
254 return ausmbus_write_2(sc, *cmd, *((uint16_t *)vbuf));
255 }
256
257 /* Write quick */
258 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 0)) {
259 return ausmbus_quick_write(sc);
260 }
261
262 /*
263 * XXX: TODO Please Support other protocols defined in SMBus 2.0
264 * - Process call
265 * - Block write/read
266 * - Clock write-block read process cal
267 * - SMBus host notify protocol
268 *
269 * - Read quick and write quick have not been tested!
270 */
271
272 return -1;
273 }
274
275 static int
ausmbus_receive_1(struct ausmbus_softc * sc,uint8_t * vp)276 ausmbus_receive_1(struct ausmbus_softc *sc, uint8_t *vp)
277 {
278 int error;
279
280 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ);
281 if (error != 0) {
282 return error;
283 }
284 error = ausmbus_read_byte(sc, vp, I2C_F_STOP);
285 if (error != 0) {
286 return error;
287 }
288
289 return 0;
290 }
291
292 static int
ausmbus_read_1(struct ausmbus_softc * sc,uint8_t cmd,uint8_t * vp)293 ausmbus_read_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t *vp)
294 {
295 int error;
296
297 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
298 if (error != 0) {
299 return error;
300 }
301
302 error = ausmbus_write_byte(sc, cmd, I2C_F_READ);
303 if (error != 0) {
304 return error;
305 }
306
307 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ);
308 if (error != 0) {
309 return error;
310 }
311
312 error = ausmbus_read_byte(sc, vp, I2C_F_STOP);
313 if (error != 0) {
314 return error;
315 }
316
317 return 0;
318 }
319
320 static int
ausmbus_read_2(struct ausmbus_softc * sc,uint8_t cmd,uint16_t * vp)321 ausmbus_read_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t *vp)
322 {
323 int error;
324 uint8_t high, low;
325
326 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
327 if (error != 0) {
328 return error;
329 }
330
331 error = ausmbus_write_byte(sc, cmd, I2C_F_READ);
332 if (error != 0) {
333 return error;
334 }
335
336 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ);
337 if (error != 0) {
338 return error;
339 }
340
341 error = ausmbus_read_byte(sc, &low, 0);
342 if (error != 0) {
343 return error;
344 }
345
346 error = ausmbus_read_byte(sc, &high, I2C_F_STOP);
347 if (error != 0) {
348 return error;
349 }
350
351 *vp = (high << 8) | low;
352
353 return 0;
354 }
355
356 static int
ausmbus_send_1(struct ausmbus_softc * sc,uint8_t val)357 ausmbus_send_1(struct ausmbus_softc *sc, uint8_t val)
358 {
359 int error;
360
361 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
362 if (error != 0) {
363 return error;
364 }
365
366 error = ausmbus_write_byte(sc, val, I2C_F_STOP);
367 if (error != 0) {
368 return error;
369 }
370
371 return 0;
372 }
373
374 static int
ausmbus_write_1(struct ausmbus_softc * sc,uint8_t cmd,uint8_t val)375 ausmbus_write_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t val)
376 {
377 int error;
378
379 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
380 if (error != 0) {
381 return error;
382 }
383
384 error = ausmbus_write_byte(sc, cmd, 0);
385 if (error != 0) {
386 return error;
387 }
388
389 error = ausmbus_write_byte(sc, val, I2C_F_STOP);
390 if (error != 0) {
391 return error;
392 }
393
394 return 0;
395 }
396
397 static int
ausmbus_write_2(struct ausmbus_softc * sc,uint8_t cmd,uint16_t val)398 ausmbus_write_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t val)
399 {
400 int error;
401 uint8_t high, low;
402
403 high = (val >> 8) & 0xff;
404 low = val & 0xff;
405
406 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE);
407 if (error != 0) {
408 return error;
409 }
410
411 error = ausmbus_write_byte(sc, cmd, 0);
412 if (error != 0) {
413 return error;
414 }
415
416 error = ausmbus_write_byte(sc, low, 0);
417 if (error != 0) {
418 return error;
419 }
420
421 error = ausmbus_write_byte(sc, high, I2C_F_STOP);
422 if (error != 0) {
423 return error;
424 }
425
426 return 0;
427 }
428
429 /*
430 * XXX The quick_write() and quick_read() routines have not been tested!
431 */
432 static int
ausmbus_quick_write(struct ausmbus_softc * sc)433 ausmbus_quick_write(struct ausmbus_softc *sc)
434 {
435 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr,
436 I2C_F_STOP | I2C_F_WRITE);
437 }
438
439 static int
ausmbus_quick_read(struct ausmbus_softc * sc)440 ausmbus_quick_read(struct ausmbus_softc *sc)
441 {
442 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr,
443 I2C_F_STOP | I2C_F_READ);
444 }
445
446 static int
ausmbus_wait_mastertx(struct ausmbus_softc * sc)447 ausmbus_wait_mastertx(struct ausmbus_softc *sc)
448 {
449 uint32_t v;
450 int timeout;
451 int txerr = 0;
452
453 timeout = sc->sc_smbus_timeout;
454
455 do {
456 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT);
457 #ifdef AUSMBUS_PSC_DEBUG
458 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v);
459 #endif
460 if ((v & SMBUS_EVNT_TU) != 0)
461 break;
462 if ((v & SMBUS_EVNT_MD) != 0)
463 break;
464 if ((v & (SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL))
465 != 0) {
466 txerr = 1;
467 break;
468 }
469 timeout--;
470 delay(1);
471 } while (timeout > 0);
472
473 if (txerr != 0) {
474 ausmbus_reg_write(sc, AUPSC_SMBEVNT,
475 SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL);
476 #ifdef AUSMBUS_PSC_DEBUG
477 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n");
478 #endif
479 return -1;
480 }
481
482 /* Reset Event TU (Tx Underflow) */
483 ausmbus_reg_write(sc, AUPSC_SMBEVNT, SMBUS_EVNT_TU | SMBUS_EVNT_MD);
484
485 #ifdef AUSMBUS_PSC_DEBUG
486 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT);
487 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v);
488 #endif
489 return 0;
490 }
491
492 static int
ausmbus_wait_masterrx(struct ausmbus_softc * sc)493 ausmbus_wait_masterrx(struct ausmbus_softc *sc)
494 {
495 uint32_t v;
496 int timeout;
497 timeout = sc->sc_smbus_timeout;
498
499 if (ausmbus_wait_mastertx(sc) != 0)
500 return -1;
501
502 do {
503 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT);
504 #ifdef AUSMBUS_PSC_DEBUG
505 aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v);
506 #endif
507 if ((v & SMBUS_STAT_RE) == 0)
508 break;
509 timeout--;
510 delay(1);
511 } while (timeout > 0);
512
513 return 0;
514 }
515
516 static int
ausmbus_initiate_xfer(void * arg,i2c_addr_t addr,int flags)517 ausmbus_initiate_xfer(void *arg, i2c_addr_t addr, int flags)
518 {
519 struct ausmbus_softc *sc = arg;
520 uint32_t v;
521
522 /* Tx/Rx Slave Address */
523 v = (addr << 1) & SMBUS_TXRX_ADDRDATA;
524 if ((flags & I2C_F_READ) != 0)
525 v |= 1;
526 if ((flags & I2C_F_STOP) != 0)
527 v |= SMBUS_TXRX_STP;
528 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v);
529
530 /* Master Start */
531 ausmbus_reg_write(sc, AUPSC_SMBPCR, SMBUS_PCR_MS);
532
533 if (ausmbus_wait_mastertx(sc) != 0)
534 return -1;
535
536 return 0;
537 }
538
539 static int
ausmbus_read_byte(void * arg,uint8_t * vp,int flags)540 ausmbus_read_byte(void *arg, uint8_t *vp, int flags)
541 {
542 struct ausmbus_softc *sc = arg;
543 uint32_t v;
544
545 if ((flags & I2C_F_STOP) != 0) {
546 ausmbus_reg_write(sc, AUPSC_SMBTXRX, SMBUS_TXRX_STP);
547 } else {
548 ausmbus_reg_write(sc, AUPSC_SMBTXRX, 0);
549 }
550
551 if (ausmbus_wait_masterrx(sc) != 0)
552 return -1;
553
554 v = ausmbus_reg_read(sc, AUPSC_SMBTXRX);
555 *vp = v & SMBUS_TXRX_ADDRDATA;
556
557 return 0;
558 }
559
560 static int
ausmbus_write_byte(void * arg,uint8_t v,int flags)561 ausmbus_write_byte(void *arg, uint8_t v, int flags)
562 {
563 struct ausmbus_softc *sc = arg;
564
565 if ((flags & I2C_F_STOP) != 0) {
566 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_STP));
567 } else if ((flags & I2C_F_READ) != 0) {
568 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_RSR));
569 } else {
570 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v);
571 }
572
573 if (ausmbus_wait_mastertx(sc) != 0)
574 return -1;
575
576 return 0;
577 }
578