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