xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_twsi.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
1 /*	$NetBSD: octeon_twsi.c,v 1.1 2015/04/29 08:32:01 hikaru Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Internet Initiative Japan, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #undef	TWSIDEBUG
30 #undef	TWSITEST
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: octeon_twsi.c,v 1.1 2015/04/29 08:32:01 hikaru Exp $");
34 
35 #include "opt_octeon.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <sys/device.h>
41 #include <sys/lock.h>
42 
43 #include <sys/bus.h>
44 
45 #include <dev/i2c/i2cvar.h>
46 
47 #include <mips/cavium/include/iobusvar.h>
48 #include <mips/cavium/dev/octeon_twsireg.h>
49 
50 #ifdef TWSIDEBUG
51 #define	DPRINTF(x)	printf x
52 #else
53 #define	DPRINTF(x)
54 #endif
55 
56 struct octeon_twsi_reg;
57 
58 struct octeon_twsi_softc {
59 	device_t		sc_dev;
60 	bus_space_tag_t		sc_regt;
61 	bus_space_handle_t	sc_regh;
62 
63 	void *sc_ih;
64 
65 	struct i2c_controller	sc_i2c;
66 	struct lock		sc_lock;
67 
68 	/* ... */
69 };
70 
71 /* Auto-configuration */
72 
73 static int		octeon_twsi_match(device_t, struct cfdata *,
74 			    void *);
75 static void		octeon_twsi_attach(device_t, device_t,
76 			    void *);
77 
78 /* High-Level Controller Master */
79 
80 #ifdef notyet
81 static uint8_t		octeon_twsi_hlcm_read_1(struct octeon_twsi_softc *,
82 			    ...)
83 static uint64_t		octeon_twsi_hlcm_read_4(struct octeon_twsi_softc *,
84 			    ...)
85 static void		octeon_twsi_hlcm_read(struct octeon_twsi_softc *,
86 			    ...)
87 static void		octeon_twsi_hlcm_write_1(struct octeon_twsi_softc *,
88 			    ...)
89 static void		octeon_twsi_hlcm_write_4(struct octeon_twsi_softc *,
90 			    ...)
91 static void		octeon_twsi_hlcm_write(struct octeon_twsi_softc *,
92 			    ...)
93 #endif
94 
95 /* High-Level Controller Slave */
96 
97 /* XXX */
98 
99 /* Control Register */
100 
101 #ifdef notyet
102 #define	_CONTROL_READ(sc, reg) \
103 	octeon_twsi_control_read((sc), MIO_TWS_SW_TWSI_EOP_IA_##reg)
104 #define	_CONTROL_WRITE(sc, reg, value) \
105 	octeon_twsi_control_write((sc), MIO_TWS_SW_TWSI_EOP_IA_##reg, value)
106 static uint8_t		octeon_twsi_control_read(struct octeon_twsi_softc *sc,
107 			    uint64_t);
108 static void		octeon_twsi_control_write(struct octeon_twsi_softc *sc,
109 			    uint64_t, uint8_t);
110 #endif
111 
112 /* Register accessors */
113 
114 static inline uint64_t	octeon_twsi_reg_rd(struct octeon_twsi_softc *, int);
115 static inline void	octeon_twsi_reg_wr(struct octeon_twsi_softc *, int,
116 			    uint64_t);
117 #ifdef TWSIDEBUG
118 static inline void	octeon_twsi_reg_dump(struct octeon_twsi_softc *, int);
119 #endif
120 
121 /* Test functions */
122 
123 #ifdef TWSIDEBUG
124 static void		octeon_twsi_test(struct octeon_twsi_softc *);
125 #endif
126 
127 /* Debug functions */
128 
129 #ifdef TWSIDEBUG
130 static inline void	octeon_twsi_debug_reg_dump(struct octeon_twsi_softc *,
131 			    int);
132 static void		octeon_twsi_debug_dumpregs(struct octeon_twsi_softc *);
133 static void		octeon_twsi_debug_dumpreg(struct octeon_twsi_softc *,
134 			    const struct octeon_twsi_reg *);
135 #endif
136 
137 /* -------------------------------------------------------------------------- */
138 
139 /*
140  * Auto-configuration
141  */
142 
143 CFATTACH_DECL_NEW(octeon_twsi, sizeof(struct octeon_twsi_softc),
144     octeon_twsi_match, octeon_twsi_attach, NULL, NULL);
145 
146 static int
147 octeon_twsi_match(device_t parent, struct cfdata *cf, void *aux)
148 {
149 	struct iobus_attach_args *aa = aux;
150 
151 	if (strcmp(cf->cf_name, aa->aa_name) != 0)
152 		return 0;
153 	return 1;
154 }
155 
156 static void
157 octeon_twsi_attach(device_t parent, device_t self, void *aux)
158 {
159 	struct octeon_twsi_softc *sc = device_private(self);
160 	struct iobus_attach_args *aa = aux;
161 	int status;
162 
163 	sc->sc_dev = self;
164 	sc->sc_regt = aa->aa_bust;
165 
166 	status = bus_space_map(sc->sc_regt, MIO_TWS_BASE_0, MIO_TWS_SIZE, 0,
167 	    &sc->sc_regh);
168 	if (status != 0)
169 		panic(": can't map register");
170 
171 	aprint_normal("\n");
172 
173 #ifdef TWSITEST
174 	octeon_twsi_test(sc);
175 #endif
176 }
177 
178 /* -------------------------------------------------------------------------- */
179 
180 /*
181  * Initialization, basic operations
182  */
183 
184 #ifdef notyet
185 
186 static void
187 octeon_twsi_wait(struct octeon_twsi_softc *sc)
188 {
189 }
190 
191 static void
192 octeon_twsi_intr(struct octeon_twsi_softc *sc)
193 {
194 }
195 
196 static void
197 octeon_twsi_lock(struct octeon_twsi_softc *sc)
198 {
199 }
200 
201 static void
202 octeon_twsi_unlock(struct octeon_twsi_softc *sc)
203 {
204 }
205 
206 #endif
207 
208 /* -------------------------------------------------------------------------- */
209 
210 /*
211  * High-Level Controller as a Master
212  */
213 
214 #ifdef notyet
215 
216 #define	_BUFTOLE32(buf)						\
217 	((buf[0] << 24) | (buf[1] << 16) | (buf[2] <<  8) | (buf[3] <<  0))
218 #define	_LE32TOBUF(buf, x)					\
219 	do {							\
220 		buf[0] = (char)((x) >> 24);			\
221 		buf[1] = (char)((x) >> 16);			\
222 		buf[2] = (char)((x) >> 8);			\
223 		buf[3] = (char)((x) >> 0);			\
224 	} while (0)
225 
226 static void
227 octeon_twsi_hlcm_read(struct octeon_twsi_softc *sc, int addr, char *buf,
228     size_t len)
229 {
230 	uint64_t cmd;
231 	size_t resid;
232 
233 	octeon_twsi_lock(sc);
234 
235 #ifdef notyet
236 
237 	octeon_twsi_hlcm_setup(sc);
238 
239 	resid = len;
240 
241 	while (resid > 4) {
242 		cmd = MIO_TWS_SW_TWSI_OP_FOUR | MIO_TWS_SW_TWSI_R
243 		    | (addr << MIO_TWS_SW_TWSI_A_SHIFT);
244 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
245 		octeon_twsi_wait(sc);
246 		cmd = octeon_twsi_reg_rd(sc);
247 		_LE32TOBUF(&buf[len - 1 - resid], (uint32_t)cmd);
248 		resid -= 4;
249 	}
250 
251 	while (resid > 0) {
252 		cmd = MIO_TWS_SW_TWSI_OP_ONE | MIO_TWS_SW_TWSI_R
253 		    | (addr << MIO_TWS_SW_TWSI_A_SHIFT);
254 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
255 		octeon_twsi_wait(sc);
256 		cmd = octeon_twsi_reg_rd(sc);
257 		buf[len - 1 - resid] = (uint8_t)cmd;
258 		resid--;
259 	}
260 
261 #endif
262 
263 	octeon_twsi_unlock(sc);
264 }
265 
266 static void
267 octeon_twsi_hlcm_write(struct octeon_twsi_softc *sc, int addr, char *buf,
268     size_t len)
269 {
270 	uint64_t cmd;
271 	size_t resid;
272 
273 	octeon_twsi_lock(sc);
274 
275 #ifdef notyet
276 
277 	octeon_twsi_hlcm_setup(sc);
278 
279 	resid = len;
280 
281 	while (resid > 4) {
282 		cmd = MIO_TWS_SW_TWSI_OP_FOUR
283 		    | (addr << MIO_TWS_SW_TWSI_A_SHIFT)
284 		    | _BUFTOLE32(&buf[len - 1 - resid]);
285 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
286 		octeon_twsi_wait(sc);
287 		resid -= 4;
288 	}
289 
290 	while (resid > 0) {
291 		cmd = MIO_TWS_SW_TWSI_OP_ONE
292 		    | (addr << MIO_TWS_SW_TWSI_A_SHIFT)
293 		    | buf[len - 1 - resid];
294 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
295 		octeon_twsi_wait(sc);
296 		resid--;
297 	}
298 
299 	/* MIO_TWS_SW_TWSI:V must be zero */
300 
301 	/* check error */
302 	if (MIO_TWS_SW_TWSI:R == 0) {
303 		code = MIO_TWS_SW_TWSI:D;
304 	}
305 #endif
306 
307 	octeon_twsi_unlock(sc);
308 }
309 
310 static void
311 octeon_twsi_hlcm_setup(struct octeon_twsi_softc *sc, ...)
312 {
313 	/* XXX */
314 
315 	_CONTROL_WR(sc, TWSI_CTL, TWSI_CTL_CE | TWSI_CTL_ENAB | TWSI_AAK);
316 }
317 
318 static uint8_t
319 octeon_twsi_hlcm_read_1(struct octeon_twsi_softc *sc, ...)
320 {
321 	/* XXX */
322 	return 0;
323 }
324 
325 static uint64_t
326 octeon_twsi_hlcm_read_4(struct octeon_twsi_softc *sc, ...)
327 {
328 	/* XXX */
329 	return 0;
330 }
331 
332 static void
333 octeon_twsi_hlcm_write_1(struct octeon_twsi_softc *sc, ...)
334 {
335 	/* XXX */
336 }
337 
338 static void
339 octeon_twsi_hlcm_write_4(struct octeon_twsi_softc *sc, ...)
340 {
341 	/* XXX */
342 }
343 
344 #endif
345 
346 /* -------------------------------------------------------------------------- */
347 
348 /*
349  * High-Level Controller as a Slave
350  */
351 
352 #ifdef notyet
353 
354 static void
355 octeon_twsi_hlcs_setup(struct octeon_twsi_softc *sc, ...)
356 {
357 	/* XXX */
358 }
359 
360 #endif
361 
362 /* -------------------------------------------------------------------------- */
363 
364 /*
365  * TWSI Control Register operations
366  */
367 
368 #ifdef notyet
369 
370 static uint8_t
371 octeon_twsi_control_read(struct octeon_twsi_softc *sc, uint64_t eop_ia)
372 {
373 	uint64_t cmd;
374 
375 	cmd = MIO_TWS_SW_TWSI_OP_EXTEND
376 	    | (addr << MIO_TWS_SW_TWSI_A_SHIFT)
377 	    | eop_ia;
378 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
379 	octeon_twsi_wait(sc);
380 	return (uint8_t)octeon_twsi_reg_rd(sc, MIO_TWS_SW_TWSI_OFFSET);
381 }
382 
383 static void
384 octeon_twsi_control_write(struct octeon_twsi_softc *sc, uint64_t eop_ia,
385     char *buf, size_t len)
386 {
387 	uint64_t cmd;
388 
389 	cmd = MIO_TWS_SW_TWSI_OP_EXTEND
390 	    | (addr << MIO_TWS_SW_TWSI_A_SHIFT)
391 	    | eop_ia
392 	    | _BUFTOLE32(&buf[len - 1 - resid]);
393 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
394 	octeon_twsi_wait(sc);
395 }
396 
397 #endif
398 
399 /* -------------------------------------------------------------------------- */
400 
401 /*
402  * Send / receive operations
403  */
404 
405 /* Send (== software to TWSI) */
406 
407 #ifdef notyet
408 
409 static void
410 octeon_twsi_send(struct octeon_twsi_softc *sc, ...)
411 {
412 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
413 }
414 
415 /* Receive (== TWSI to software) */
416 
417 static void
418 octeon_twsi_recv(struct octeon_twsi_softc *sc, ...)
419 {
420 	/* XXX */
421 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
422 	octeon_twsi_wait(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
423 	octeon_twsi_reg_rd(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
424 }
425 
426 #endif
427 
428 /* -------------------------------------------------------------------------- */
429 
430 /*
431  * Register accessors
432  */
433 
434 static inline uint64_t
435 octeon_twsi_reg_rd(struct octeon_twsi_softc *sc, int offset)
436 {
437 	return bus_space_read_8(sc->sc_regt, sc->sc_regh, offset);
438 }
439 
440 static inline void
441 octeon_twsi_reg_wr(struct octeon_twsi_softc *sc, int offset, uint64_t value)
442 {
443 	bus_space_write_8(sc->sc_regt, sc->sc_regh, offset, value);
444 }
445 
446 #ifdef TWSIDEBUG
447 
448 void
449 octeon_twsi_reg_dump(struct octeon_twsi_softc *sc, int offset)
450 {
451 	octeon_twsi_debug_reg_dump(sc, offset);
452 }
453 
454 #endif
455 
456 /* -------------------------------------------------------------------------- */
457 
458 /*
459  * Test functions
460  */
461 
462 #ifdef TWSITEST
463 
464 void
465 octeon_twsi_test(struct octeon_twsi_softc *sc)
466 {
467 	octeon_twsi_debug_dumpregs(sc);
468 }
469 
470 #endif
471 
472 /* -------------------------------------------------------------------------- */
473 
474 #ifdef TWSIDEBUG
475 
476 /*
477  * Debug functions
478  *
479  *	octeon_twsi_debug_reg_dump
480  *	octeon_twsi_debug_dumpregs
481  *	octeon_twsi_debug_dumpreg
482  */
483 
484 struct octeon_twsi_reg {
485 	const char		*name;
486 	int			offset;
487 	const char		*format;
488 };
489 
490 static const struct octeon_twsi_reg octeon_twsi_regs[] = {
491 #define	_ENTRY(x)	{ #x, x##_OFFSET, x##_BITS }
492 	_ENTRY(MIO_TWS_SW_TWSI),
493 	_ENTRY(MIO_TWS_TWSI_SW),
494 	_ENTRY(MIO_TWS_INT),
495 	_ENTRY(MIO_TWS_SW_TWSI_EXT)
496 #undef	_ENTRY
497 };
498 
499 void
500 octeon_twsi_debug_reg_dump(struct octeon_twsi_softc *sc, int offset)
501 {
502 	int i;
503 	const struct octeon_twsi_reg *reg;
504 
505 	reg = NULL;
506 	for (i = 0; i < (int)__arraycount(octeon_twsi_regs); i++)
507 		if (octeon_twsi_regs[i].offset == offset) {
508 			reg = &octeon_twsi_regs[i];
509 			break;
510 		}
511 	KASSERT(reg != NULL);
512 
513 	octeon_twsi_debug_dumpreg(sc, reg);
514 }
515 
516 void
517 octeon_twsi_debug_dumpregs(struct octeon_twsi_softc *sc)
518 {
519 	int i;
520 
521 	for (i = 0; i < (int)__arraycount(octeon_twsi_regs); i++)
522 		octeon_twsi_debug_dumpreg(sc, &octeon_twsi_regs[i]);
523 }
524 
525 void
526 octeon_twsi_debug_dumpreg(struct octeon_twsi_softc *sc,
527     const struct octeon_twsi_reg *reg)
528 {
529 	uint64_t value;
530 	char buf[256];
531 
532 	value = octeon_twsi_reg_rd(sc, reg->offset);
533 	snprintb(buf, sizeof(buf), reg->format, value);
534 	printf("\t%-24s: %s\n", reg->name, buf);
535 }
536 
537 #endif
538