2 * Copyright (c) 2010-2011 Qlogic Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
29 * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
40 #include "qla_inline.h"
45 * structure encapsulating the value to read/write to offchip memory
47 typedef struct _offchip_mem_val {
54 #define Q8_ADDR_UNDEFINED 0xFFFFFFFF
57 * The index to this table is Bits 20-27 of the indirect register address
59 static uint32_t indirect_to_base_map[] =
61 Q8_ADDR_UNDEFINED, /* 0x00 */
62 0x77300000, /* 0x01 */
63 0x29500000, /* 0x02 */
64 0x2A500000, /* 0x03 */
65 Q8_ADDR_UNDEFINED, /* 0x04 */
66 0x0D000000, /* 0x05 */
67 0x1B100000, /* 0x06 */
68 0x0E600000, /* 0x07 */
69 0x0E000000, /* 0x08 */
70 0x0E100000, /* 0x09 */
71 0x0E200000, /* 0x0A */
72 0x0E300000, /* 0x0B */
73 0x42000000, /* 0x0C */
74 0x41700000, /* 0x0D */
75 0x42100000, /* 0x0E */
76 0x34B00000, /* 0x0F */
77 0x40500000, /* 0x10 */
78 0x34000000, /* 0x11 */
79 0x34100000, /* 0x12 */
80 0x34200000, /* 0x13 */
81 0x34300000, /* 0x14 */
82 0x34500000, /* 0x15 */
83 0x34400000, /* 0x16 */
84 0x3C000000, /* 0x17 */
85 0x3C100000, /* 0x18 */
86 0x3C200000, /* 0x19 */
87 0x3C300000, /* 0x1A */
88 Q8_ADDR_UNDEFINED, /* 0x1B */
89 0x3C400000, /* 0x1C */
90 0x41000000, /* 0x1D */
91 Q8_ADDR_UNDEFINED, /* 0x1E */
92 0x0D100000, /* 0x1F */
93 Q8_ADDR_UNDEFINED, /* 0x20 */
94 0x77300000, /* 0x21 */
95 0x41600000, /* 0x22 */
96 Q8_ADDR_UNDEFINED, /* 0x23 */
97 Q8_ADDR_UNDEFINED, /* 0x24 */
98 Q8_ADDR_UNDEFINED, /* 0x25 */
99 Q8_ADDR_UNDEFINED, /* 0x26 */
100 Q8_ADDR_UNDEFINED, /* 0x27 */
101 0x41700000, /* 0x28 */
102 Q8_ADDR_UNDEFINED, /* 0x29 */
103 0x08900000, /* 0x2A */
104 0x70A00000, /* 0x2B */
105 0x70B00000, /* 0x2C */
106 0x70C00000, /* 0x2D */
107 0x08D00000, /* 0x2E */
108 0x08E00000, /* 0x2F */
109 0x70F00000, /* 0x30 */
110 0x40500000, /* 0x31 */
111 0x42000000, /* 0x32 */
112 0x42100000, /* 0x33 */
113 Q8_ADDR_UNDEFINED, /* 0x34 */
114 0x08800000, /* 0x35 */
115 0x09100000, /* 0x36 */
116 0x71200000, /* 0x37 */
117 0x40600000, /* 0x38 */
118 Q8_ADDR_UNDEFINED, /* 0x39 */
119 0x71800000, /* 0x3A */
120 0x19900000, /* 0x3B */
121 0x1A900000, /* 0x3C */
122 Q8_ADDR_UNDEFINED, /* 0x3D */
123 0x34600000, /* 0x3E */
124 Q8_ADDR_UNDEFINED, /* 0x3F */
128 * Address Translation Table for CRB to offsets from PCI BAR0
130 typedef struct _crb_to_pci {
135 static crb_to_pci_t crbinit_to_pciaddr[] = {
136 {(0x088 << 20), (0x035 << 20)},
137 {(0x089 << 20), (0x02A << 20)},
138 {(0x08D << 20), (0x02E << 20)},
139 {(0x08E << 20), (0x02F << 20)},
140 {(0x0C6 << 20), (0x023 << 20)},
141 {(0x0C7 << 20), (0x024 << 20)},
142 {(0x0C8 << 20), (0x025 << 20)},
143 {(0x0D0 << 20), (0x005 << 20)},
144 {(0x0D1 << 20), (0x01F << 20)},
145 {(0x0E0 << 20), (0x008 << 20)},
146 {(0x0E1 << 20), (0x009 << 20)},
147 {(0x0E2 << 20), (0x00A << 20)},
148 {(0x0E3 << 20), (0x00B << 20)},
149 {(0x0E6 << 20), (0x007 << 20)},
150 {(0x199 << 20), (0x03B << 20)},
151 {(0x1B1 << 20), (0x006 << 20)},
152 {(0x295 << 20), (0x002 << 20)},
153 {(0x29A << 20), (0x000 << 20)},
154 {(0x2A5 << 20), (0x003 << 20)},
155 {(0x340 << 20), (0x011 << 20)},
156 {(0x341 << 20), (0x012 << 20)},
157 {(0x342 << 20), (0x013 << 20)},
158 {(0x343 << 20), (0x014 << 20)},
159 {(0x344 << 20), (0x016 << 20)},
160 {(0x345 << 20), (0x015 << 20)},
161 {(0x3C0 << 20), (0x017 << 20)},
162 {(0x3C1 << 20), (0x018 << 20)},
163 {(0x3C2 << 20), (0x019 << 20)},
164 {(0x3C3 << 20), (0x01A << 20)},
165 {(0x3C4 << 20), (0x01C << 20)},
166 {(0x3C5 << 20), (0x01B << 20)},
167 {(0x405 << 20), (0x031 << 20)},
168 {(0x406 << 20), (0x038 << 20)},
169 {(0x410 << 20), (0x01D << 20)},
170 {(0x416 << 20), (0x022 << 20)},
171 {(0x417 << 20), (0x028 << 20)},
172 {(0x420 << 20), (0x032 << 20)},
173 {(0x421 << 20), (0x033 << 20)},
174 {(0x700 << 20), (0x00C << 20)},
175 {(0x701 << 20), (0x00D << 20)},
176 {(0x702 << 20), (0x00E << 20)},
177 {(0x703 << 20), (0x00F << 20)},
178 {(0x704 << 20), (0x010 << 20)},
179 {(0x70A << 20), (0x02B << 20)},
180 {(0x70B << 20), (0x02C << 20)},
181 {(0x70C << 20), (0x02D << 20)},
182 {(0x70F << 20), (0x030 << 20)},
183 {(0x718 << 20), (0x03A << 20)},
184 {(0x758 << 20), (0x026 << 20)},
185 {(0x759 << 20), (0x027 << 20)},
186 {(0x773 << 20), (0x001 << 20)}
189 #define Q8_INVALID_ADDRESS (-1)
190 #define Q8_ADDR_MASK (0xFFF << 20)
192 typedef struct _addr_val {
200 * Name: qla_rdwr_indreg32
201 * Function: Read/Write an Indirect Register
204 qla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val, uint32_t rd)
209 offset = (addr & 0xFFF00000) >> 20;
212 device_printf(ha->pci_dev, "%s: invalid addr 0x%08x\n",
217 offset = indirect_to_base_map[offset];
218 if (offset == Q8_ADDR_UNDEFINED) {
219 device_printf(ha->pci_dev, "%s: undefined map 0x%08x\n",
224 offset = offset | (addr & 0x000F0000);
226 if (qla_sem_lock(ha, Q8_SEM7_LOCK, 0, 0)) {
227 device_printf(ha->pci_dev, "%s: SEM7_LOCK failed\n", __func__);
231 WRITE_OFFSET32(ha, Q8_CRB_WINDOW_2M, offset);
233 while (offset != (READ_OFFSET32(ha, Q8_CRB_WINDOW_2M))) {
236 qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
240 qla_mdelay(__func__, 1);
244 *val = READ_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000));
246 WRITE_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000), *val);
249 qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
254 * Name: qla_rdwr_offchip_mem
255 * Function: Read/Write OffChip Memory
258 qla_rdwr_offchip_mem(qla_host_t *ha, uint64_t addr, offchip_mem_val_t *val,
261 uint32_t count = 100;
264 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_LO, (uint32_t)addr);
265 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_HI, (uint32_t)(addr >> 32));
268 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_LO, val->data_lo);
269 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_HI, val->data_hi);
270 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_ULO, val->data_ulo);
271 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_UHI, val->data_uhi);
272 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x07); /* Write */
274 WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x03); /* Read */
278 data = READ_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL);
279 if (!(data & BIT_3)) {
281 val->data_lo = READ_OFFSET32(ha, \
282 Q8_MIU_TEST_AGT_RDDATA_LO);
283 val->data_hi = READ_OFFSET32(ha, \
284 Q8_MIU_TEST_AGT_RDDATA_HI);
285 val->data_ulo = READ_OFFSET32(ha, \
286 Q8_MIU_TEST_AGT_RDDATA_ULO);
287 val->data_uhi = READ_OFFSET32(ha, \
288 Q8_MIU_TEST_AGT_RDDATA_UHI);
292 qla_mdelay(__func__, 1);
295 device_printf(ha->pci_dev, "%s: failed[0x%08x]\n", __func__, data);
300 * Name: qla_rd_flash32
301 * Function: Read Flash Memory
304 qla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
307 uint32_t count = 100;
309 if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
310 device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
313 WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
316 qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
318 qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
320 qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
324 val = ROM_OPCODE_FAST_RD;
325 qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
327 while (!((val = READ_OFFSET32(ha, Q8_ROM_STATUS)) & BIT_1)) {
330 qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
336 qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
337 qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
341 qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, data, 1);
343 qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
348 * Name: qla_int_to_pci_addr_map
349 * Function: Convert's Internal(CRB) Address to Indirect Address
352 qla_int_to_pci_addr_map(qla_host_t *ha, uint32_t int_addr)
354 uint32_t crb_to_pci_table_size, i;
357 crb_to_pci_table_size = sizeof(crbinit_to_pciaddr)/sizeof(crb_to_pci_t);
358 addr = int_addr & Q8_ADDR_MASK;
360 for (i = 0; i < crb_to_pci_table_size; i++) {
361 if (crbinit_to_pciaddr[i].crb_addr == addr) {
362 addr = (int_addr & ~Q8_ADDR_MASK) |
363 crbinit_to_pciaddr[i].pci_addr;
367 return (Q8_INVALID_ADDRESS);
371 * Name: qla_filter_pci_addr
372 * Function: Filter's out Indirect Addresses which are not writeable
375 qla_filter_pci_addr(qla_host_t *ha, uint32_t addr)
377 if ((addr == Q8_INVALID_ADDRESS) ||
378 (addr == 0x00112040) ||
379 (addr == 0x00112048) ||
380 ((addr & 0xFFFF0FFF) == 0x001100C4) ||
381 ((addr & 0xFFFF0FFF) == 0x001100C8) ||
382 ((addr & 0x0FF00000) == 0x00200000) ||
383 (addr == 0x022021FC) ||
384 (addr == 0x0330001C) ||
385 (addr == 0x03300024) ||
386 (addr == 0x033000A8) ||
387 (addr == 0x033000C8) ||
388 (addr == 0x033000BC) ||
389 ((addr & 0x0FF00000) == 0x03A00000) ||
390 (addr == 0x03B0001C))
391 return (Q8_INVALID_ADDRESS);
398 * Function: CRB Initialization - first step in the initialization after reset
399 * Essentially reads the address/value pairs from address = 0x00 and
400 * writes the value into address in the addr/value pair.
403 qla_crb_init(qla_host_t *ha)
406 uint32_t offset, count, i;
407 addr_val_t *addr_val_map, *avmap;
409 qla_rd_flash32(ha, 0, &sig);
410 QL_DPRINT2((ha->pci_dev, "%s: val[0] = 0x%08x\n", __func__, sig));
412 qla_rd_flash32(ha, 4, &val);
413 QL_DPRINT2((ha->pci_dev, "%s: val[4] = 0x%08x\n", __func__, val));
416 offset = val & 0xFFFF;
417 offset = offset << 2;
419 QL_DPRINT2((ha->pci_dev, "%s: [sig,val]=[0x%08x, 0x%08x] %d pairs\n",
420 __func__, sig, val, count));
422 addr_val_map = avmap = malloc((sizeof(addr_val_t) * count),
423 M_QLA8XXXBUF, M_NOWAIT);
425 if (addr_val_map == NULL) {
426 device_printf(ha->pci_dev, "%s: malloc failed\n", __func__);
429 memset(avmap, 0, (sizeof(addr_val_t) * count));
432 for (i = 0; i < count; ) {
433 qla_rd_flash32(ha, (offset + (i * 4)), &avmap->value);
435 qla_rd_flash32(ha, (offset + (i * 4)), &avmap->addr);
438 avmap->pci_addr = qla_int_to_pci_addr_map(ha, avmap->addr);
439 avmap->ind_addr = qla_filter_pci_addr(ha, avmap->pci_addr);
441 QL_DPRINT2((ha->pci_dev,
442 "%s: [0x%02x][0x%08x:0x%08x:0x%08x] 0x%08x\n",
443 __func__, (i >> 1), avmap->addr, avmap->pci_addr,
444 avmap->ind_addr, avmap->value));
446 if (avmap->ind_addr != Q8_INVALID_ADDRESS) {
447 qla_rdwr_indreg32(ha, avmap->ind_addr, &avmap->value,0);
448 qla_mdelay(__func__, 1);
453 free (addr_val_map, M_QLA8XXXBUF);
458 * Name: qla_init_peg_regs
459 * Function: Protocol Engine Register Initialization
462 qla_init_peg_regs(qla_host_t *ha)
464 WRITE_OFFSET32(ha, Q8_PEG_D_RESET1, 0x001E);
465 WRITE_OFFSET32(ha, Q8_PEG_D_RESET2, 0x0008);
466 WRITE_OFFSET32(ha, Q8_PEG_I_RESET, 0x0008);
467 WRITE_OFFSET32(ha, Q8_PEG_0_CLR1, 0x0000);
468 WRITE_OFFSET32(ha, Q8_PEG_0_CLR2, 0x0000);
469 WRITE_OFFSET32(ha, Q8_PEG_1_CLR1, 0x0000);
470 WRITE_OFFSET32(ha, Q8_PEG_1_CLR2, 0x0000);
471 WRITE_OFFSET32(ha, Q8_PEG_2_CLR1, 0x0000);
472 WRITE_OFFSET32(ha, Q8_PEG_2_CLR2, 0x0000);
473 WRITE_OFFSET32(ha, Q8_PEG_3_CLR1, 0x0000);
474 WRITE_OFFSET32(ha, Q8_PEG_3_CLR2, 0x0000);
475 WRITE_OFFSET32(ha, Q8_PEG_4_CLR1, 0x0000);
476 WRITE_OFFSET32(ha, Q8_PEG_4_CLR2, 0x0000);
480 * Name: qla_load_fw_from_flash
481 * Function: Reads the Bootloader from Flash and Loads into Offchip Memory
484 qla_load_fw_from_flash(qla_host_t *ha)
486 uint64_t mem_off = 0x10000;
487 uint32_t flash_off = 0x10000;
489 offchip_mem_val_t val;
492 /* only bootloader needs to be loaded into memory */
493 for (count = 0; count < 0x20000 ; ) {
494 qla_rd_flash32(ha, flash_off, &val.data_lo);
496 flash_off = flash_off + 4;
498 qla_rd_flash32(ha, flash_off, &val.data_hi);
500 flash_off = flash_off + 4;
502 qla_rd_flash32(ha, flash_off, &val.data_ulo);
504 flash_off = flash_off + 4;
506 qla_rd_flash32(ha, flash_off, &val.data_uhi);
508 flash_off = flash_off + 4;
510 qla_rdwr_offchip_mem(ha, mem_off, &val, 0);
512 mem_off = mem_off + 16;
518 * Name: qla_init_from_flash
519 * Function: Performs Initialization which consists of the following sequence
523 * - Read the Bootloader from Flash and Load into Offchip Memory
524 * - Kick start the bootloader which loads the rest of the firmware
525 * and performs the remaining steps in the initialization process.
528 qla_init_from_flash(qla_host_t *ha)
530 uint32_t delay = 300;
534 qla_mdelay(__func__, 100);
537 qla_mdelay(__func__, 10);
539 qla_init_peg_regs(ha);
540 qla_mdelay(__func__, 10);
542 qla_load_fw_from_flash(ha);
544 WRITE_OFFSET32(ha, Q8_CMDPEG_STATE, 0x00000000);
545 WRITE_OFFSET32(ha, Q8_PEG_0_RESET, 0x00001020);
546 WRITE_OFFSET32(ha, Q8_ASIC_RESET, 0x0080001E);
547 qla_mdelay(__func__, 100);
550 data = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
552 QL_DPRINT2((ha->pci_dev, "%s: func[%d] cmdpegstate 0x%08x\n",
553 __func__, ha->pci_func, data));
554 if (data == CMDPEG_PHAN_INIT_COMPLETE) {
555 QL_DPRINT2((ha->pci_dev,
556 "%s: func[%d] init complete\n",
557 __func__, ha->pci_func));
560 qla_mdelay(__func__, 100);
563 device_printf(ha->pci_dev,
564 "%s: func[%d] Q8_PEG_HALT_STATUS1[0x%08x] STATUS2[0x%08x]"
565 " HEARTBEAT[0x%08x] RCVPEG_STATE[0x%08x]"
566 " CMDPEG_STATE[0x%08x]\n",
567 __func__, ha->pci_func,
568 (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS1)),
569 (READ_OFFSET32(ha, Q8_PEG_HALT_STATUS2)),
570 (READ_OFFSET32(ha, Q8_FIRMWARE_HEARTBEAT)),
571 (READ_OFFSET32(ha, Q8_RCVPEG_STATE)), data);
578 * Function: Initializes P3+ hardware.
581 qla_init_hw(qla_host_t *ha)
585 uint32_t val, delay = 300;
589 QL_DPRINT1((dev, "%s: enter\n", __func__));
591 qla_mdelay(__func__, 100);
593 if (ha->pci_func & 0x1) {
594 while ((ha->pci_func & 0x1) && delay--) {
595 val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
597 if (val == CMDPEG_PHAN_INIT_COMPLETE) {
599 "%s: func = %d init complete\n",
600 __func__, ha->pci_func));
601 qla_mdelay(__func__, 100);
604 qla_mdelay(__func__, 100);
609 val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
611 if (val != CMDPEG_PHAN_INIT_COMPLETE) {
612 ret = qla_init_from_flash(ha);
613 qla_mdelay(__func__, 100);
617 ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
618 ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
619 ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
620 ha->fw_ver_build = READ_OFFSET32(ha, Q8_FW_VER_BUILD);