Esempio n. 1
0
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len)
{
	struct wl1271_cmd_header *cmd;
	unsigned long timeout;
	u32 intr;
	int ret = 0;

	cmd = buf;
	cmd->id = id;
	cmd->status = 0;

	WARN_ON(len % 4 != 0);

	wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len);

	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);

	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);

	intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
		if (time_after(jiffies, timeout)) {
			wl1271_error("command complete timeout");
			ret = -ETIMEDOUT;
			goto out;
		}

		msleep(1);

		intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
	}

	wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
			   WL1271_ACX_INTR_CMD_COMPLETE);

out:
	return ret;
}
Esempio n. 2
0
static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf,
        size_t fw_data_len, u32 dest)
{
    int addr, chunk_num, partition_limit;
    u8 *p;

    /* whal_FwCtrl_LoadFwImageSm() */

    wl1271_debug(DEBUG_BOOT, "starting firmware upload");

    wl1271_debug(DEBUG_BOOT, "fw_data_len %d chunk_size %d", fw_data_len,
                 CHUNK_SIZE);


    if ((fw_data_len % 4) != 0) {
        wl1271_error("firmware length not multiple of four");
        return -EIO;
    }

    wl1271_set_partition(wl, dest,
                         part_table[PART_DOWN].mem.size,
                         part_table[PART_DOWN].reg.start,
                         part_table[PART_DOWN].reg.size);

    /* 10.1 set partition limit and chunk num */
    chunk_num = 0;
    partition_limit = part_table[PART_DOWN].mem.size;

    while (chunk_num < fw_data_len / CHUNK_SIZE) {
        /* 10.2 update partition, if needed */
        addr = dest + (chunk_num + 2) * CHUNK_SIZE;
        if (addr > partition_limit) {
            addr = dest + chunk_num * CHUNK_SIZE;
            partition_limit = chunk_num * CHUNK_SIZE +
                              part_table[PART_DOWN].mem.size;

            /* FIXME: Over 80 chars! */
            wl1271_set_partition(wl,
                                 addr,
                                 part_table[PART_DOWN].mem.size,
                                 part_table[PART_DOWN].reg.start,
                                 part_table[PART_DOWN].reg.size);
        }

        /* 10.3 upload the chunk */
        addr = dest + chunk_num * CHUNK_SIZE;
        p = buf + chunk_num * CHUNK_SIZE;
        wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
                     p, addr);
        wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE);

        chunk_num++;
    }

    /* 10.4 upload the last chunk */
    addr = dest + chunk_num * CHUNK_SIZE;
    p = buf + chunk_num * CHUNK_SIZE;
    wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%d B) 0x%p to 0x%x",
                 fw_data_len % CHUNK_SIZE, p, addr);
    wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);

    return 0;
}
Esempio n. 3
0
static int wl1271_boot_upload_nvs(struct wl1271 *wl)
{
    size_t nvs_len, burst_len;
    int i;
    u32 dest_addr, val;
    u8 *nvs_ptr, *nvs, *nvs_aligned;

    nvs = wl->nvs;
    if (nvs == NULL)
        return -ENODEV;

    nvs_ptr = nvs;

    nvs_len = wl->nvs_len;

    /* Update the device MAC address into the nvs */
    nvs[11] = wl->mac_addr[0];
    nvs[10] = wl->mac_addr[1];
    nvs[6] = wl->mac_addr[2];
    nvs[5] = wl->mac_addr[3];
    nvs[4] = wl->mac_addr[4];
    nvs[3] = wl->mac_addr[5];

    /*
     * Layout before the actual NVS tables:
     * 1 byte : burst length.
     * 2 bytes: destination address.
     * n bytes: data to burst copy.
     *
     * This is ended by a 0 length, then the NVS tables.
     */

    /* FIXME: Do we need to check here whether the LSB is 1? */
    while (nvs_ptr[0]) {
        burst_len = nvs_ptr[0];
        dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8));

        /* FIXME: Due to our new wl1271_translate_reg_addr function,
           we need to add the REGISTER_BASE to the destination */
        dest_addr += REGISTERS_BASE;

        /* We move our pointer to the data */
        nvs_ptr += 3;

        for (i = 0; i < burst_len; i++) {
            val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
                   | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));

            wl1271_debug(DEBUG_BOOT,
                         "nvs burst write 0x%x: 0x%x",
                         dest_addr, val);
            wl1271_reg_write32(wl, dest_addr, val);

            nvs_ptr += 4;
            dest_addr += 4;
        }
    }

    /*
     * We've reached the first zero length, the first NVS table
     * is 7 bytes further.
     */
    nvs_ptr += 7;
    nvs_len -= nvs_ptr - nvs;
    nvs_len = ALIGN(nvs_len, 4);

    /* FIXME: The driver sets the partition here, but this is not needed,
       since it sets to the same one as currently in use */
    /* Now we must set the partition correctly */
    wl1271_set_partition(wl,
                         part_table[PART_WORK].mem.start,
                         part_table[PART_WORK].mem.size,
                         part_table[PART_WORK].reg.start,
                         part_table[PART_WORK].reg.size);

    /* Copy the NVS tables to a new block to ensure alignment */
    nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL);

    /* And finally we upload the NVS tables */
    /* FIXME: In wl1271, we upload everything at once.
       No endianness handling needed here?! The ref driver doesn't do
       anything about it at this point */
    wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len);

    kfree(nvs_aligned);
    return 0;
}