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