Home | History | Annotate | Line # | Download | only in dev
octeon_twsi.c revision 1.1
      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