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