Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: octeon_twsi.c,v 1.2 2020/06/18 13:52:08 simonb 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.2 2020/06/18 13:52:08 simonb 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 =
    243 		    __SHIFTIN(MIO_TWS_SW_TWSI_OP_FOUR, MIO_TWS_SW_TWSI_OP) |
    244 		    MIO_TWS_SW_TWSI_R |
    245 		    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A);
    246 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    247 		octeon_twsi_wait(sc);
    248 		cmd = octeon_twsi_reg_rd(sc);
    249 		_LE32TOBUF(&buf[len - 1 - resid], (uint32_t)cmd);
    250 		resid -= 4;
    251 	}
    252 
    253 	while (resid > 0) {
    254 		cmd =
    255 		    __SHIFTIN(MIO_TWS_SW_TWSI_OP_ONE, MIO_TWS_SW_TWSI_OP) |
    256 		    MIO_TWS_SW_TWSI_R |
    257 		    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A);
    258 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    259 		octeon_twsi_wait(sc);
    260 		cmd = octeon_twsi_reg_rd(sc);
    261 		buf[len - 1 - resid] = (uint8_t)cmd;
    262 		resid--;
    263 	}
    264 
    265 #endif
    266 
    267 	octeon_twsi_unlock(sc);
    268 }
    269 
    270 static void
    271 octeon_twsi_hlcm_write(struct octeon_twsi_softc *sc, int addr, char *buf,
    272     size_t len)
    273 {
    274 	uint64_t cmd;
    275 	size_t resid;
    276 
    277 	octeon_twsi_lock(sc);
    278 
    279 #ifdef notyet
    280 
    281 	octeon_twsi_hlcm_setup(sc);
    282 
    283 	resid = len;
    284 
    285 	while (resid > 4) {
    286 		cmd =
    287 		    __SHIFTIN(MIO_TWS_SW_TWSI_OP_FOUR, MIO_TWS_SW_TWSI_OP) |
    288 		    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A) |
    289 		    __SHIFTIN(_BUFTOLE32(&buf[len - 1 - resid]), MIO_TWS_SW_TWSI_D);
    290 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    291 		octeon_twsi_wait(sc);
    292 		resid -= 4;
    293 	}
    294 
    295 	while (resid > 0) {
    296 		cmd =
    297 		    __SHIFTIN(MIO_TWS_SW_TWSI_OP_ONE, MIO_TWS_SW_TWSI_OP) |
    298 		    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A) |
    299 		    __SHIFTIN(buf[len - 1 - resid], MIO_TWS_SW_TWSI_D);
    300 		octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    301 		octeon_twsi_wait(sc);
    302 		resid--;
    303 	}
    304 
    305 	/* MIO_TWS_SW_TWSI:V must be zero */
    306 
    307 	/* check error */
    308 	if (MIO_TWS_SW_TWSI:R == 0) {
    309 		code = MIO_TWS_SW_TWSI:D;
    310 	}
    311 #endif
    312 
    313 	octeon_twsi_unlock(sc);
    314 }
    315 
    316 static void
    317 octeon_twsi_hlcm_setup(struct octeon_twsi_softc *sc, ...)
    318 {
    319 	/* XXX */
    320 
    321 	_CONTROL_WR(sc, TWSI_CTL, TWSI_CTL_CE | TWSI_CTL_ENAB | TWSI_AAK);
    322 }
    323 
    324 static uint8_t
    325 octeon_twsi_hlcm_read_1(struct octeon_twsi_softc *sc, ...)
    326 {
    327 	/* XXX */
    328 	return 0;
    329 }
    330 
    331 static uint64_t
    332 octeon_twsi_hlcm_read_4(struct octeon_twsi_softc *sc, ...)
    333 {
    334 	/* XXX */
    335 	return 0;
    336 }
    337 
    338 static void
    339 octeon_twsi_hlcm_write_1(struct octeon_twsi_softc *sc, ...)
    340 {
    341 	/* XXX */
    342 }
    343 
    344 static void
    345 octeon_twsi_hlcm_write_4(struct octeon_twsi_softc *sc, ...)
    346 {
    347 	/* XXX */
    348 }
    349 
    350 #endif
    351 
    352 /* -------------------------------------------------------------------------- */
    353 
    354 /*
    355  * High-Level Controller as a Slave
    356  */
    357 
    358 #ifdef notyet
    359 
    360 static void
    361 octeon_twsi_hlcs_setup(struct octeon_twsi_softc *sc, ...)
    362 {
    363 	/* XXX */
    364 }
    365 
    366 #endif
    367 
    368 /* -------------------------------------------------------------------------- */
    369 
    370 /*
    371  * TWSI Control Register operations
    372  */
    373 
    374 #ifdef notyet
    375 
    376 static uint8_t
    377 octeon_twsi_control_read(struct octeon_twsi_softc *sc, uint64_t eop_ia)
    378 {
    379 	uint64_t cmd;
    380 
    381 	cmd =
    382 	    __SHIFTIN(MIO_TWS_SW_TWSI_OP_EXTEND, MIO_TWS_SW_TWSI_OP) |
    383 	    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A) |
    384 	    __SHIFTIN(eop_ia, MIO_TWS_SW_TWSI_EOP_IA);
    385 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    386 	octeon_twsi_wait(sc);
    387 	return (uint8_t)octeon_twsi_reg_rd(sc, MIO_TWS_SW_TWSI_OFFSET);
    388 }
    389 
    390 static void
    391 octeon_twsi_control_write(struct octeon_twsi_softc *sc, uint64_t eop_ia,
    392     char *buf, size_t len)
    393 {
    394 	uint64_t cmd;
    395 
    396 	cmd =
    397 	    __SHIFTIN(MIO_TWS_SW_TWSI_OP_EXTEND, MIO_TWS_SW_TWSI_OP) |
    398 	    __SHIFTIN(addr, MIO_TWS_SW_TWSI_A_SHIFT) |
    399 	    __SHIFTIN(eop_ia, MIO_TWS_SW_TWSI_EOP_IA) |
    400 	    __SHIFTIN(_BUFTOLE32(&buf[len - 1 - resid]), MIO_TWS_SW_TWSI_D);
    401 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, cmd);
    402 	octeon_twsi_wait(sc);
    403 }
    404 
    405 #endif
    406 
    407 /* -------------------------------------------------------------------------- */
    408 
    409 /*
    410  * Send / receive operations
    411  */
    412 
    413 /* Send (== software to TWSI) */
    414 
    415 #ifdef notyet
    416 
    417 static void
    418 octeon_twsi_send(struct octeon_twsi_softc *sc, ...)
    419 {
    420 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
    421 }
    422 
    423 /* Receive (== TWSI to software) */
    424 
    425 static void
    426 octeon_twsi_recv(struct octeon_twsi_softc *sc, ...)
    427 {
    428 	/* XXX */
    429 	octeon_twsi_reg_wr(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
    430 	octeon_twsi_wait(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
    431 	octeon_twsi_reg_rd(sc, MIO_TWS_SW_TWSI_OFFSET, ...);
    432 }
    433 
    434 #endif
    435 
    436 /* -------------------------------------------------------------------------- */
    437 
    438 /*
    439  * Register accessors
    440  */
    441 
    442 static inline uint64_t
    443 octeon_twsi_reg_rd(struct octeon_twsi_softc *sc, int offset)
    444 {
    445 	return bus_space_read_8(sc->sc_regt, sc->sc_regh, offset);
    446 }
    447 
    448 static inline void
    449 octeon_twsi_reg_wr(struct octeon_twsi_softc *sc, int offset, uint64_t value)
    450 {
    451 	bus_space_write_8(sc->sc_regt, sc->sc_regh, offset, value);
    452 }
    453 
    454 #ifdef TWSIDEBUG
    455 
    456 void
    457 octeon_twsi_reg_dump(struct octeon_twsi_softc *sc, int offset)
    458 {
    459 	octeon_twsi_debug_reg_dump(sc, offset);
    460 }
    461 
    462 #endif
    463 
    464 /* -------------------------------------------------------------------------- */
    465 
    466 /*
    467  * Test functions
    468  */
    469 
    470 #ifdef TWSITEST
    471 
    472 void
    473 octeon_twsi_test(struct octeon_twsi_softc *sc)
    474 {
    475 	octeon_twsi_debug_dumpregs(sc);
    476 }
    477 
    478 #endif
    479 
    480 /* -------------------------------------------------------------------------- */
    481 
    482 #ifdef TWSIDEBUG
    483 
    484 /*
    485  * Debug functions
    486  *
    487  *	octeon_twsi_debug_reg_dump
    488  *	octeon_twsi_debug_dumpregs
    489  *	octeon_twsi_debug_dumpreg
    490  */
    491 
    492 struct octeon_twsi_reg {
    493 	const char		*name;
    494 	int			offset;
    495 	const char		*format;
    496 };
    497 
    498 static const struct octeon_twsi_reg octeon_twsi_regs[] = {
    499 #define	_ENTRY(x)	{ #x, x##_OFFSET, x##_BITS }
    500 	_ENTRY(MIO_TWS_SW_TWSI),
    501 	_ENTRY(MIO_TWS_TWSI_SW),
    502 	_ENTRY(MIO_TWS_INT),
    503 	_ENTRY(MIO_TWS_SW_TWSI_EXT)
    504 #undef	_ENTRY
    505 };
    506 
    507 void
    508 octeon_twsi_debug_reg_dump(struct octeon_twsi_softc *sc, int offset)
    509 {
    510 	int i;
    511 	const struct octeon_twsi_reg *reg;
    512 
    513 	reg = NULL;
    514 	for (i = 0; i < (int)__arraycount(octeon_twsi_regs); i++)
    515 		if (octeon_twsi_regs[i].offset == offset) {
    516 			reg = &octeon_twsi_regs[i];
    517 			break;
    518 		}
    519 	KASSERT(reg != NULL);
    520 
    521 	octeon_twsi_debug_dumpreg(sc, reg);
    522 }
    523 
    524 void
    525 octeon_twsi_debug_dumpregs(struct octeon_twsi_softc *sc)
    526 {
    527 	int i;
    528 
    529 	for (i = 0; i < (int)__arraycount(octeon_twsi_regs); i++)
    530 		octeon_twsi_debug_dumpreg(sc, &octeon_twsi_regs[i]);
    531 }
    532 
    533 void
    534 octeon_twsi_debug_dumpreg(struct octeon_twsi_softc *sc,
    535     const struct octeon_twsi_reg *reg)
    536 {
    537 	uint64_t value;
    538 	char buf[256];
    539 
    540 	value = octeon_twsi_reg_rd(sc, reg->offset);
    541 	snprintb(buf, sizeof(buf), reg->format, value);
    542 	printf("\t%-24s: %s\n", reg->name, buf);
    543 }
    544 
    545 #endif
    546