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