static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) { u32 cpu_ctrl; int ret; /* 10.5.0 run the firmware (I) */ ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl); if (ret < 0) goto out; /* 10.5.1 run the firmware (II) */ cpu_ctrl |= flag; ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); out: return ret; }
int wlcore_boot_run_firmware(struct wl1271 *wl) { int loop, ret; u32 chip_id, intr; /* Make sure we have the boot partition */ ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); if (ret < 0) return ret; ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); if (ret < 0) return ret; ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id); if (ret < 0) return ret; wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); if (chip_id != wl->chip.id) { wl1271_error("chip id doesn't match after firmware boot"); return -EIO; } /* wait for init to complete */ loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; if (intr == 0xffffffff) { wl1271_error("error reading hardware complete " "init indication"); return -EIO; } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_INIT_COMPLETE); if (ret < 0) return ret; break; } } if (loop > INIT_LOOP) { wl1271_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; } /* get hardware config command mail box */ ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr); if (ret < 0) return ret; wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr); /* get hardware config event mail box */ ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]); if (ret < 0) return ret; wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", wl->mbox_ptr[0], wl->mbox_ptr[1]); ret = wlcore_boot_static_data(wl); if (ret < 0) { wl1271_error("error getting static data"); return ret; } /* * in case of full asynchronous mode the firmware event must be * ready to receive event from the command mailbox */ /* unmask required mbox events */ wl->event_mask = BSS_LOSS_EVENT_ID | SCAN_COMPLETE_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PERIODIC_SCAN_COMPLETE_EVENT_ID | DUMMY_PACKET_EVENT_ID | PEER_REMOVE_COMPLETE_EVENT_ID | BA_SESSION_RX_CONSTRAINT_EVENT_ID | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | INACTIVE_STA_EVENT_ID | MAX_TX_FAILURE_EVENT_ID | CHANNEL_SWITCH_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { wl1271_error("EVENT mask setting failed"); return ret; } /* set the working partition to its "running" mode offset */ ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); /* firmware startup completed */ return ret; }
/* * send command to firmware * * @wl: wl struct * @id: command id * @buf: buffer containing the command, must work with dma * @len: length of the buffer * return the cmd status code on success. */ static int __wlcore_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; u32 intr; int ret; u16 status; u16 poll_count = 0; if (unlikely(wl->state == WLCORE_STATE_RESTARTING && id != CMD_STOP_FWLOGGER)) return -EIO; if (WARN_ON_ONCE(len < sizeof(*cmd))) return -EIO; cmd = buf; cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); if (ret < 0) return ret; /* * TODO: we just need this because one bit is in a different * place. Is there any better way? */ ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); if (ret < 0) return ret; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); return -ETIMEDOUT; } poll_count++; if (poll_count < WL1271_CMD_FAST_POLL_COUNT) udelay(10); else msleep(1); ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); if (ret < 0) return ret; } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); if (ret < 0) return ret; status = le16_to_cpu(cmd->status); ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); if (ret < 0) return ret; return status; }