1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 2004, 2005 8 * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice unmodified, this list of conditions, and the following 15 * disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Intel Wireless PRO/2200 mini-PCI adapter driver 35 * ipw2200_hw.c is used t handle hardware operations and firmware operations. 36 */ 37 #include <sys/types.h> 38 #include <sys/byteorder.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/note.h> 42 #include <sys/stream.h> 43 #include <sys/strsun.h> 44 45 #include "ipw2200.h" 46 #include "ipw2200_impl.h" 47 48 /* 49 * Hardware related operations 50 */ 51 #define IPW2200_EEPROM_SHIFT_D (2) 52 #define IPW2200_EEPROM_SHIFT_Q (4) 53 54 #define IPW2200_EEPROM_C (1 << 0) 55 #define IPW2200_EEPROM_S (1 << 1) 56 #define IPW2200_EEPROM_D (1 << IPW2200_EEPROM_SHIFT_D) 57 #define IPW2200_EEPROM_Q (1 << IPW2200_EEPROM_SHIFT_Q) 58 59 uint8_t 60 ipw2200_csr_get8(struct ipw2200_softc *sc, uint32_t off) 61 { 62 return (ddi_get8(sc->sc_ioh, (uint8_t *)(sc->sc_regs + off))); 63 } 64 65 uint16_t 66 ipw2200_csr_get16(struct ipw2200_softc *sc, uint32_t off) 67 { 68 return (ddi_get16(sc->sc_ioh, 69 (uint16_t *)((uintptr_t)sc->sc_regs + off))); 70 } 71 72 uint32_t 73 ipw2200_csr_get32(struct ipw2200_softc *sc, uint32_t off) 74 { 75 return (ddi_get32(sc->sc_ioh, 76 (uint32_t *)((uintptr_t)sc->sc_regs + off))); 77 } 78 79 void 80 ipw2200_csr_getbuf32(struct ipw2200_softc *sc, uint32_t off, 81 uint32_t *buf, size_t cnt) 82 { 83 ddi_rep_get32(sc->sc_ioh, buf, 84 (uint32_t *)((uintptr_t)sc->sc_regs + off), 85 cnt, DDI_DEV_AUTOINCR); 86 } 87 88 void 89 ipw2200_csr_put8(struct ipw2200_softc *sc, uint32_t off, 90 uint8_t val) 91 { 92 ddi_put8(sc->sc_ioh, (uint8_t *)(sc->sc_regs + off), val); 93 } 94 95 void 96 ipw2200_csr_put16(struct ipw2200_softc *sc, uint32_t off, 97 uint16_t val) 98 { 99 ddi_put16(sc->sc_ioh, 100 (uint16_t *)((uintptr_t)sc->sc_regs + off), val); 101 } 102 103 void 104 ipw2200_csr_put32(struct ipw2200_softc *sc, uint32_t off, 105 uint32_t val) 106 { 107 ddi_put32(sc->sc_ioh, 108 (uint32_t *)((uintptr_t)sc->sc_regs + off), val); 109 } 110 111 uint8_t 112 ipw2200_imem_get8(struct ipw2200_softc *sc, uint32_t addr) 113 { 114 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 115 return (ipw2200_csr_get8(sc, IPW2200_CSR_INDIRECT_DATA)); 116 } 117 118 uint16_t 119 ipw2200_imem_get16(struct ipw2200_softc *sc, 120 uint32_t addr) 121 { 122 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 123 return (ipw2200_csr_get16(sc, IPW2200_CSR_INDIRECT_DATA)); 124 } 125 126 uint32_t 127 ipw2200_imem_get32(struct ipw2200_softc *sc, uint32_t addr) 128 { 129 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 130 return (ipw2200_csr_get32(sc, IPW2200_CSR_INDIRECT_DATA)); 131 } 132 133 void 134 ipw2200_imem_put8(struct ipw2200_softc *sc, uint32_t addr, uint8_t val) 135 { 136 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 137 ipw2200_csr_put8(sc, IPW2200_CSR_INDIRECT_DATA, val); 138 } 139 140 void 141 ipw2200_imem_put16(struct ipw2200_softc *sc, uint32_t addr, 142 uint16_t val) 143 { 144 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 145 ipw2200_csr_put16(sc, IPW2200_CSR_INDIRECT_DATA, val); 146 } 147 148 void 149 ipw2200_imem_put32(struct ipw2200_softc *sc, uint32_t addr, 150 uint32_t val) 151 { 152 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr); 153 ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_DATA, val); 154 } 155 156 void 157 ipw2200_rom_control(struct ipw2200_softc *sc, uint32_t val) 158 { 159 ipw2200_imem_put32(sc, IPW2200_IMEM_EEPROM_CTL, val); 160 drv_usecwait(IPW2200_EEPROM_DELAY); 161 } 162 163 uint16_t 164 ipw2200_rom_get16(struct ipw2200_softc *sc, uint8_t addr) 165 { 166 uint32_t tmp; 167 uint16_t val; 168 int n; 169 170 /* 171 * According to i2c bus protocol 172 */ 173 /* clock */ 174 ipw2200_rom_control(sc, 0); 175 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 176 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C); 177 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 178 /* start bit */ 179 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D); 180 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D | 181 IPW2200_EEPROM_C); 182 /* read opcode */ 183 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D); 184 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D | 185 IPW2200_EEPROM_C); 186 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 187 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C); 188 /* 189 * address, totally 8 bits, defined by hardware, push from MSB to LSB 190 */ 191 for (n = 7; n >= 0; n--) { 192 ipw2200_rom_control(sc, IPW2200_EEPROM_S | 193 (((addr >> n) & 1) << IPW2200_EEPROM_SHIFT_D)); 194 ipw2200_rom_control(sc, IPW2200_EEPROM_S | 195 (((addr >> n) & 1) << IPW2200_EEPROM_SHIFT_D) | 196 IPW2200_EEPROM_C); 197 } 198 199 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 200 201 /* 202 * data, totally 16 bits, defined by hardware, push from MSB to LSB 203 */ 204 val = 0; 205 for (n = 15; n >= 0; n--) { 206 ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C); 207 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 208 tmp = ipw2200_imem_get32(sc, IPW2200_IMEM_EEPROM_CTL); 209 val |= ((tmp & IPW2200_EEPROM_Q) >> IPW2200_EEPROM_SHIFT_Q) 210 << n; 211 } 212 213 ipw2200_rom_control(sc, 0); 214 215 /* clear chip select and clock */ 216 ipw2200_rom_control(sc, IPW2200_EEPROM_S); 217 ipw2200_rom_control(sc, 0); 218 ipw2200_rom_control(sc, IPW2200_EEPROM_C); 219 220 return (BE_16(val)); 221 } 222 223 /* 224 * Firmware related operations 225 */ 226 #define IPW2200_FW_MAJOR_VERSION (2) 227 #define IPW2200_FW_MINOR_VERSION (4) 228 229 #define IPW2200_FW_MAJOR(x)((x) & 0xff) 230 #define IPW2200_FW_MINOR(x)(((x) & 0xff) >> 8) 231 232 /* 233 * These firwares were issued by Intel as binaries which need to be 234 * loaded to hardware when card is initiated, or when fatal error 235 * happened, or when the chip need be reset. 236 */ 237 static uint8_t ipw2200_boot_bin [] = { 238 #include "fw-ipw2200/ipw-2.4-boot.hex" 239 }; 240 static uint8_t ipw2200_ucode_bin [] = { 241 #include "fw-ipw2200/ipw-2.4-bss_ucode.hex" 242 }; 243 static uint8_t ipw2200_fw_bin [] = { 244 #include "fw-ipw2200/ipw-2.4-bss.hex" 245 }; 246 247 #pragma pack(1) 248 struct header { 249 uint32_t version; 250 uint32_t mode; 251 }; 252 #pragma pack() 253 254 int 255 ipw2200_cache_firmware(struct ipw2200_softc *sc) 256 { 257 IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT, 258 "ipw2200_cache_firmware(): enter\n")); 259 260 /* boot code */ 261 sc->sc_fw.boot_base = ipw2200_boot_bin + sizeof (struct header); 262 sc->sc_fw.boot_size = 263 sizeof (ipw2200_boot_bin) - sizeof (struct header); 264 /* ucode */ 265 sc->sc_fw.uc_base = ipw2200_ucode_bin + sizeof (struct header); 266 sc->sc_fw.uc_size = sizeof (ipw2200_ucode_bin) - sizeof (struct header); 267 /* firmware */ 268 sc->sc_fw.fw_base = ipw2200_fw_bin + sizeof (struct header); 269 sc->sc_fw.fw_size = sizeof (ipw2200_fw_bin) - sizeof (struct header); 270 271 sc->sc_flags |= IPW2200_FLAG_FW_CACHED; 272 273 IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT, 274 "ipw2200_cache_firmware(): boot=%u,uc=%u,fw=%u\n", 275 sc->sc_fw.boot_size, sc->sc_fw.uc_size, sc->sc_fw.fw_size)); 276 IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT, 277 "ipw2200_cache_firmware(): exit\n")); 278 279 return (DDI_SUCCESS); 280 } 281 282 /* 283 * If user-land firmware loading is supported, this routine will 284 * free kernel memory, when sc->sc_fw.bin_base & sc->sc_fw.bin_size 285 * are not empty 286 */ 287 int 288 ipw2200_free_firmware(struct ipw2200_softc *sc) 289 { 290 sc->sc_flags &= ~IPW2200_FLAG_FW_CACHED; 291 292 return (DDI_SUCCESS); 293 } 294 295 /* 296 * the following routines load code onto ipw2200 hardware 297 */ 298 int 299 ipw2200_load_uc(struct ipw2200_softc *sc, uint8_t *buf, size_t size) 300 { 301 int ntries, i; 302 uint16_t *w; 303 304 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 305 IPW2200_RST_STOP_MASTER | ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 306 for (ntries = 0; ntries < 5; ntries++) { 307 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) & 308 IPW2200_RST_MASTER_DISABLED) 309 break; 310 drv_usecwait(10); 311 } 312 if (ntries == 5) { 313 IPW2200_WARN((sc->sc_dip, CE_CONT, 314 "ipw2200_load_uc(): timeout waiting for master")); 315 return (DDI_FAILURE); 316 } 317 318 ipw2200_imem_put32(sc, 0x3000e0, 0x80000000); 319 drv_usecwait(5000); 320 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 321 ~IPW2200_RST_PRINCETON_RESET & 322 ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 323 drv_usecwait(5000); 324 ipw2200_imem_put32(sc, 0x3000e0, 0); 325 drv_usecwait(1000); 326 ipw2200_imem_put32(sc, IPW2200_IMEM_EVENT_CTL, 1); 327 drv_usecwait(1000); 328 ipw2200_imem_put32(sc, IPW2200_IMEM_EVENT_CTL, 0); 329 drv_usecwait(1000); 330 ipw2200_imem_put8(sc, 0x200000, 0x00); 331 ipw2200_imem_put8(sc, 0x200000, 0x40); 332 drv_usecwait(1000); 333 334 for (w = (uint16_t *)(uintptr_t)buf; size > 0; w++, size -= 2) 335 ipw2200_imem_put16(sc, 0x200010, LE_16(*w)); 336 337 ipw2200_imem_put8(sc, 0x200000, 0x00); 338 ipw2200_imem_put8(sc, 0x200000, 0x80); 339 340 /* 341 * try many times to wait the upload is ready, 2000times 342 */ 343 for (ntries = 0; ntries < 2000; ntries++) { 344 uint8_t val; 345 346 val = ipw2200_imem_get8(sc, 0x200000); 347 if (val & 1) 348 break; 349 drv_usecwait(1000); /* wait for a while */ 350 } 351 if (ntries == 2000) { 352 IPW2200_WARN((sc->sc_dip, CE_WARN, 353 "ipw2200_load_uc(): timeout waiting for ucode init.\n")); 354 return (DDI_FAILURE); 355 } 356 357 for (i = 0; i < 7; i++) 358 (void) ipw2200_imem_get32(sc, 0x200004); 359 360 ipw2200_imem_put8(sc, 0x200000, 0x00); 361 362 return (DDI_SUCCESS); 363 } 364 365 #define MAX_DR_NUM (64) 366 #define MAX_DR_SIZE (4096) 367 368 int 369 ipw2200_load_fw(struct ipw2200_softc *sc, uint8_t *buf, size_t size) 370 { 371 struct dma_region dr[MAX_DR_NUM]; /* maximal, 64 * 4KB = 256KB */ 372 uint8_t *p, *end, *v; 373 uint32_t mlen; 374 uint32_t src, dst, ctl, len, sum, off; 375 uint32_t sentinel; 376 int ntries, err, cnt, i; 377 clock_t clk = drv_usectohz(5000000); /* 5 second */ 378 379 ipw2200_imem_put32(sc, 0x3000a0, 0x27000); 380 381 p = buf; 382 end = p + size; 383 384 cnt = 0; 385 err = ipw2200_dma_region_alloc(sc, &dr[cnt], MAX_DR_SIZE, DDI_DMA_READ, 386 DDI_DMA_STREAMING); 387 if (err != DDI_SUCCESS) 388 goto fail0; 389 off = 0; 390 src = dr[cnt].dr_pbase; 391 392 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0x27000); 393 394 while (p < end) { 395 dst = LE_32(*((uint32_t *)(uintptr_t)p)); p += 4; 396 len = LE_32(*((uint32_t *)(uintptr_t)p)); p += 4; 397 v = p; 398 p += len; 399 IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT, 400 "ipw2200_load_fw(): dst=0x%x,len=%u\n", dst, len)); 401 402 while (len > 0) { 403 /* 404 * if no DMA region is available, allocate a new one 405 */ 406 if (off == dr[cnt].dr_size) { 407 cnt++; 408 if (cnt >= MAX_DR_NUM) { 409 IPW2200_WARN((sc->sc_dip, CE_WARN, 410 "ipw2200_load_fw(): " 411 "maximum %d DRs is reached\n", 412 cnt)); 413 cnt--; /* only free alloced DMA */ 414 goto fail1; 415 } 416 err = ipw2200_dma_region_alloc(sc, &dr[cnt], 417 MAX_DR_SIZE, DDI_DMA_WRITE, 418 DDI_DMA_STREAMING); 419 if (err != DDI_SUCCESS) { 420 cnt--; /* only free alloced DMA */ 421 goto fail1; 422 } 423 off = 0; 424 src = dr[cnt].dr_pbase; 425 } 426 mlen = min(IPW2200_CB_MAXDATALEN, len); 427 mlen = min(mlen, dr[cnt].dr_size - off); 428 429 (void) memcpy(dr[cnt].dr_base + off, v, mlen); 430 (void) ddi_dma_sync(dr[cnt].dr_hnd, off, mlen, 431 DDI_DMA_SYNC_FORDEV); 432 433 ctl = IPW2200_CB_DEFAULT_CTL | mlen; 434 sum = ctl ^ src ^ dst; 435 /* 436 * write a command 437 */ 438 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, ctl); 439 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, src); 440 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, dst); 441 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, sum); 442 443 off += mlen; 444 src += mlen; 445 dst += mlen; 446 v += mlen; 447 len -= mlen; 448 } 449 } 450 451 sentinel = ipw2200_csr_get32(sc, IPW2200_CSR_AUTOINC_ADDR); 452 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0); 453 454 IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT, 455 "ipw2200_load_fw(): sentinel=%x\n", sentinel)); 456 457 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 458 ~(IPW2200_RST_MASTER_DISABLED | IPW2200_RST_STOP_MASTER) 459 & ipw2200_csr_get32(sc, IPW2200_CSR_RST)); 460 461 ipw2200_imem_put32(sc, 0x3000a4, 0x540100); 462 for (ntries = 0; ntries < 400; ntries++) { 463 uint32_t val; 464 val = ipw2200_imem_get32(sc, 0x3000d0); 465 if (val >= sentinel) 466 break; 467 drv_usecwait(100); 468 } 469 if (ntries == 400) { 470 IPW2200_WARN((sc->sc_dip, CE_WARN, 471 "ipw2200_load_fw(): timeout processing command blocks\n")); 472 goto fail1; 473 } 474 475 mutex_enter(&sc->sc_ilock); 476 477 ipw2200_imem_put32(sc, 0x3000a4, 0x540c00); 478 479 /* 480 * enable all interrupts 481 */ 482 ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL); 483 484 /* 485 * tell the adapter to initialize the firmware, 486 * just simply set it to 0 487 */ 488 ipw2200_csr_put32(sc, IPW2200_CSR_RST, 0); 489 ipw2200_csr_put32(sc, IPW2200_CSR_CTL, 490 ipw2200_csr_get32(sc, IPW2200_CSR_CTL) | 491 IPW2200_CTL_ALLOW_STANDBY); 492 493 /* 494 * wait for interrupt to notify fw initialization is done 495 */ 496 sc->sc_fw_ok = 0; 497 while (!sc->sc_fw_ok) { 498 /* 499 * There is an enhancement! we just change from 1s to 5s 500 */ 501 if (cv_reltimedwait(&sc->sc_fw_cond, &sc->sc_ilock, clk, 502 TR_CLOCK_TICK) < 0) 503 break; 504 } 505 mutex_exit(&sc->sc_ilock); 506 507 if (!sc->sc_fw_ok) { 508 IPW2200_WARN((sc->sc_dip, CE_WARN, 509 "ipw2200_load_fw(): firmware(%u) load failed!", size)); 510 goto fail1; 511 } 512 513 for (i = 0; i <= cnt; i++) 514 ipw2200_dma_region_free(&dr[i]); 515 516 return (DDI_SUCCESS); 517 518 fail1: 519 IPW2200_WARN((sc->sc_dip, CE_WARN, 520 "ipw2200_load_fw(): DMA allocation failed, cnt=%d\n", cnt)); 521 for (i = 0; i <= cnt; i++) 522 ipw2200_dma_region_free(&dr[i]); 523 fail0: 524 return (DDI_FAILURE); 525 } 526