1 /*- 2 * Copyright (c) 2004 Hidetoshi Shimokawa <simokawa@FreeBSD.ORG> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* 31 * FireWire disk device handling. 32 * 33 */ 34 35 #include <stand.h> 36 37 #include <machine/bootinfo.h> 38 39 #include <stdarg.h> 40 41 #include <bootstrap.h> 42 #include <btxv86.h> 43 #include <libi386.h> 44 #include "fwohci.h" 45 #include <dev/dcons/dcons.h> 46 47 /* XXX */ 48 #define BIT4x2(x,y) uint8_t y:4, x:4 49 #define BIT16x2(x,y) uint32_t y:16, x:16 50 #define _KERNEL 51 #include <dev/firewire/iec13213.h> 52 53 extern uint32_t dcons_paddr; 54 extern struct console dconsole; 55 56 struct crom_src_buf { 57 struct crom_src src; 58 struct crom_chunk root; 59 struct crom_chunk vendor; 60 struct crom_chunk hw; 61 /* for dcons */ 62 struct crom_chunk unit; 63 struct crom_chunk spec; 64 struct crom_chunk ver; 65 }; 66 67 static int fw_init(void); 68 static int fw_strategy(void *devdata, int flag, daddr_t dblk, 69 size_t size, char *buf, size_t *rsize); 70 static int fw_open(struct open_file *f, ...); 71 static int fw_close(struct open_file *f); 72 static int fw_print(int verbose); 73 static void fw_cleanup(void); 74 75 void fw_enable(void); 76 77 struct devsw fwohci = { 78 "FW1394", /* 7 chars at most */ 79 DEVT_NET, 80 fw_init, 81 fw_strategy, 82 fw_open, 83 fw_close, 84 noioctl, 85 fw_print, 86 fw_cleanup 87 }; 88 89 static struct fwohci_softc fwinfo[MAX_OHCI]; 90 static int fw_initialized = 0; 91 92 static void 93 fw_probe(int index, struct fwohci_softc *sc) 94 { 95 int err; 96 97 sc->state = FWOHCI_STATE_INIT; 98 err = biospci_find_devclass( 99 0x0c0010 /* Serial:FireWire:OHCI */, 100 index /* index */, 101 &sc->locator); 102 103 if (err != 0) { 104 sc->state = FWOHCI_STATE_DEAD; 105 return; 106 } 107 108 biospci_write_config(sc->locator, 109 0x4 /* command */, 110 0x6 /* enable bus master and memory mapped I/O */, 111 1 /* word */); 112 113 biospci_read_config(sc->locator, 0x00 /*devid*/, 2 /*dword*/, 114 &sc->devid); 115 biospci_read_config(sc->locator, 0x10 /*base_addr*/, 2 /*dword*/, 116 &sc->base_addr); 117 118 sc->handle = (uint32_t)PTOV(sc->base_addr); 119 sc->bus_id = OREAD(sc, OHCI_BUS_ID); 120 121 return; 122 } 123 124 static int 125 fw_init(void) 126 { 127 int i, avail; 128 struct fwohci_softc *sc; 129 130 if (fw_initialized) 131 return (0); 132 133 avail = 0; 134 for (i = 0; i < MAX_OHCI; i ++) { 135 sc = &fwinfo[i]; 136 fw_probe(i, sc); 137 if (sc->state == FWOHCI_STATE_DEAD) 138 break; 139 avail ++; 140 break; 141 } 142 fw_initialized = 1; 143 144 return (0); 145 } 146 147 148 /* 149 * Print information about OHCI chips 150 */ 151 static int 152 fw_print(int verbose) 153 { 154 int i, ret; 155 struct fwohci_softc *sc; 156 157 printf("%s devices:", fwohci.dv_name); 158 if ((ret = pager_output("\n")) != 0) 159 return (ret); 160 161 for (i = 0; i < MAX_OHCI; i ++) { 162 sc = &fwinfo[i]; 163 if (sc->state == FWOHCI_STATE_DEAD) 164 break; 165 printf("%d: locator=0x%04x devid=0x%08x" 166 " base_addr=0x%08x handle=0x%08x bus_id=0x%08x", 167 i, sc->locator, sc->devid, 168 sc->base_addr, sc->handle, sc->bus_id); 169 if ((ret = pager_output("\n")) != 0) 170 break; 171 } 172 return (ret); 173 } 174 175 static int 176 fw_open(struct open_file *f, ...) 177 { 178 #if 0 179 va_list ap; 180 struct i386_devdesc *dev; 181 struct open_disk *od; 182 int error; 183 184 va_start(ap, f); 185 dev = va_arg(ap, struct i386_devdesc *); 186 va_end(ap); 187 #endif 188 189 return (ENXIO); 190 } 191 192 static int 193 fw_close(struct open_file *f) 194 { 195 return (0); 196 } 197 198 static void 199 fw_cleanup() 200 { 201 struct dcons_buf *db; 202 203 /* invalidate dcons buffer */ 204 if (dcons_paddr) { 205 db = (struct dcons_buf *)PTOV(dcons_paddr); 206 db->magic = 0; 207 } 208 } 209 210 static int 211 fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 212 { 213 return (EIO); 214 } 215 216 static void 217 fw_init_crom(struct fwohci_softc *sc) 218 { 219 struct crom_src *src; 220 221 printf("fw_init_crom\n"); 222 sc->crom_src_buf = (struct crom_src_buf *) 223 malloc(sizeof(struct crom_src_buf)); 224 if (sc->crom_src_buf == NULL) 225 return; 226 227 src = &sc->crom_src_buf->src; 228 bzero(src, sizeof(struct crom_src)); 229 230 /* BUS info sample */ 231 src->hdr.info_len = 4; 232 233 src->businfo.bus_name = CSR_BUS_NAME_IEEE1394; 234 235 src->businfo.irmc = 1; 236 src->businfo.cmc = 1; 237 src->businfo.isc = 1; 238 src->businfo.bmc = 1; 239 src->businfo.pmc = 0; 240 src->businfo.cyc_clk_acc = 100; 241 src->businfo.max_rec = sc->maxrec; 242 src->businfo.max_rom = MAXROM_4; 243 #define FW_GENERATION_CHANGEABLE 2 244 src->businfo.generation = FW_GENERATION_CHANGEABLE; 245 src->businfo.link_spd = sc->speed; 246 247 src->businfo.eui64.hi = sc->eui.hi; 248 src->businfo.eui64.lo = sc->eui.lo; 249 250 STAILQ_INIT(&src->chunk_list); 251 252 sc->crom_src = src; 253 sc->crom_root = &sc->crom_src_buf->root; 254 } 255 256 static void 257 fw_reset_crom(struct fwohci_softc *sc) 258 { 259 struct crom_src_buf *buf; 260 struct crom_src *src; 261 struct crom_chunk *root; 262 263 printf("fw_reset\n"); 264 if (sc->crom_src_buf == NULL) 265 fw_init_crom(sc); 266 267 buf = sc->crom_src_buf; 268 src = sc->crom_src; 269 root = sc->crom_root; 270 271 STAILQ_INIT(&src->chunk_list); 272 273 bzero(root, sizeof(struct crom_chunk)); 274 crom_add_chunk(src, NULL, root, 0); 275 crom_add_entry(root, CSRKEY_NCAP, 0x0083c0); /* XXX */ 276 /* private company_id */ 277 crom_add_entry(root, CSRKEY_VENDOR, CSRVAL_VENDOR_PRIVATE); 278 #ifdef __DragonFly__ 279 crom_add_simple_text(src, root, &buf->vendor, "DragonFly Project"); 280 #else 281 crom_add_simple_text(src, root, &buf->vendor, "FreeBSD Project"); 282 #endif 283 } 284 285 286 #define ADDR_HI(x) (((x) >> 24) & 0xffffff) 287 #define ADDR_LO(x) ((x) & 0xffffff) 288 289 static void 290 dcons_crom(struct fwohci_softc *sc) 291 { 292 struct crom_src_buf *buf; 293 struct crom_src *src; 294 struct crom_chunk *root; 295 296 buf = sc->crom_src_buf; 297 src = sc->crom_src; 298 root = sc->crom_root; 299 300 bzero(&buf->unit, sizeof(struct crom_chunk)); 301 302 crom_add_chunk(src, root, &buf->unit, CROM_UDIR); 303 crom_add_entry(&buf->unit, CSRKEY_SPEC, CSRVAL_VENDOR_PRIVATE); 304 crom_add_simple_text(src, &buf->unit, &buf->spec, "FreeBSD"); 305 crom_add_entry(&buf->unit, CSRKEY_VER, DCONS_CSR_VAL_VER); 306 crom_add_simple_text(src, &buf->unit, &buf->ver, "dcons"); 307 crom_add_entry(&buf->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr)); 308 crom_add_entry(&buf->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr)); 309 } 310 311 void 312 fw_crom(struct fwohci_softc *sc) 313 { 314 struct crom_src *src; 315 void *newrom; 316 317 fw_reset_crom(sc); 318 dcons_crom(sc); 319 320 newrom = malloc(CROMSIZE); 321 src = &sc->crom_src_buf->src; 322 crom_load(src, (uint32_t *)newrom, CROMSIZE); 323 if (bcmp(newrom, sc->config_rom, CROMSIZE) != 0) { 324 /* Bump generation and reload. */ 325 src->businfo.generation++; 326 327 /* Handle generation count wraps. */ 328 if (src->businfo.generation < 2) 329 src->businfo.generation = 2; 330 331 /* Recalculate CRC to account for generation change. */ 332 crom_load(src, (uint32_t *)newrom, CROMSIZE); 333 bcopy(newrom, (void *)sc->config_rom, CROMSIZE); 334 } 335 free(newrom); 336 } 337 338 static int 339 fw_busreset(struct fwohci_softc *sc) 340 { 341 int count; 342 343 if (sc->state < FWOHCI_STATE_ENABLED) { 344 printf("fwohci not enabled\n"); 345 return(CMD_OK); 346 } 347 fw_crom(sc); 348 fwohci_ibr(sc); 349 count = 0; 350 while (sc->state< FWOHCI_STATE_NORMAL) { 351 fwohci_poll(sc); 352 count ++; 353 if (count > 1000) { 354 printf("give up to wait bus initialize\n"); 355 return (-1); 356 } 357 } 358 printf("poll count = %d\n", count); 359 return (0); 360 } 361 362 void 363 fw_enable(void) 364 { 365 struct fwohci_softc *sc; 366 int i; 367 368 if (fw_initialized == 0) 369 fw_init(); 370 371 for (i = 0; i < MAX_OHCI; i ++) { 372 sc = &fwinfo[i]; 373 if (sc->state != FWOHCI_STATE_INIT) 374 break; 375 376 sc->config_rom = (uint32_t *) 377 (((uint32_t)sc->config_rom_buf 378 + (CROMSIZE - 1)) & ~(CROMSIZE - 1)); 379 #if 0 380 printf("configrom: %08p %08p\n", 381 sc->config_rom_buf, sc->config_rom); 382 #endif 383 if (fwohci_init(sc, 0) == 0) { 384 sc->state = FWOHCI_STATE_ENABLED; 385 fw_busreset(sc); 386 } else 387 sc->state = FWOHCI_STATE_DEAD; 388 } 389 } 390 391 void 392 fw_poll(void) 393 { 394 struct fwohci_softc *sc; 395 int i; 396 397 if (fw_initialized == 0) 398 return; 399 400 for (i = 0; i < MAX_OHCI; i ++) { 401 sc = &fwinfo[i]; 402 if (sc->state < FWOHCI_STATE_ENABLED) 403 break; 404 fwohci_poll(sc); 405 } 406 } 407 408 #if 0 /* for debug */ 409 static int 410 fw_busreset_cmd(int argc, char *argv[]) 411 { 412 struct fwohci_softc *sc; 413 int i; 414 415 for (i = 0; i < MAX_OHCI; i ++) { 416 sc = &fwinfo[i]; 417 if (sc->state < FWOHCI_STATE_INIT) 418 break; 419 fw_busreset(sc); 420 } 421 return(CMD_OK); 422 } 423 424 static int 425 fw_poll_cmd(int argc, char *argv[]) 426 { 427 fw_poll(); 428 return(CMD_OK); 429 } 430 431 static int 432 fw_enable_cmd(int argc, char *argv[]) 433 { 434 fw_print(0); 435 fw_enable(); 436 return(CMD_OK); 437 } 438 439 440 static int 441 dcons_enable(int argc, char *argv[]) 442 { 443 dconsole.c_init(0); 444 fw_enable(); 445 dconsole.c_flags |= C_ACTIVEIN | C_ACTIVEOUT; 446 return(CMD_OK); 447 } 448 449 static int 450 dcons_read(int argc, char *argv[]) 451 { 452 char c; 453 while (dconsole.c_ready()) { 454 c = dconsole.c_in(); 455 printf("%c", c); 456 } 457 printf("\r\n"); 458 return(CMD_OK); 459 } 460 461 static int 462 dcons_write(int argc, char *argv[]) 463 { 464 int len, i; 465 if (argc < 2) 466 return(CMD_OK); 467 468 len = strlen(argv[1]); 469 for (i = 0; i < len; i ++) 470 dconsole.c_out(argv[1][i]); 471 dconsole.c_out('\r'); 472 dconsole.c_out('\n'); 473 return(CMD_OK); 474 } 475 COMMAND_SET(firewire, "firewire", "enable firewire", fw_enable_cmd); 476 COMMAND_SET(fwbusreset, "fwbusreset", "firewire busreset", fw_busreset_cmd); 477 COMMAND_SET(fwpoll, "fwpoll", "firewire poll", fw_poll_cmd); 478 COMMAND_SET(dcons, "dcons", "enable dcons", dcons_enable); 479 COMMAND_SET(dread, "dread", "read from dcons", dcons_read); 480 COMMAND_SET(dwrite, "dwrite", "write to dcons", dcons_write); 481 #endif 482