1a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy/* 2a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Firmware I/O code for mac80211 ST-Ericsson CW1200 drivers 3a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * 4a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Copyright (c) 2010, ST-Ericsson 5a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> 6a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * 7a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Based on: 8a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * ST-Ericsson UMAC CW1200 driver which is 9a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Copyright (c) 2010, ST-Ericsson 10a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> 11a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * 12a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * This program is free software; you can redistribute it and/or modify 13a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * it under the terms of the GNU General Public License version 2 as 14a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * published by the Free Software Foundation. 15a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy */ 16a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 17a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include <linux/vmalloc.h> 18a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include <linux/sched.h> 19a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include <linux/firmware.h> 20a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 21a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include "cw1200.h" 22a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include "fwio.h" 23a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include "hwio.h" 24911373cca1b45571b62938f8f19cec24cb102471Solomon Peachy#include "hwbus.h" 25a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#include "bh.h" 26a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 27a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachystatic int cw1200_get_hw_type(u32 config_reg_val, int *major_revision) 28a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy{ 29a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int hw_type = -1; 30a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 silicon_type = (config_reg_val >> 24) & 0x7; 31a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 silicon_vers = (config_reg_val >> 31) & 0x1; 32a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 33a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (silicon_type) { 34a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 0x00: 35a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy *major_revision = 1; 36a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy hw_type = HIF_9000_SILICON_VERSATILE; 37a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 38a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 0x01: 39a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 0x02: /* CW1x00 */ 40a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 0x04: /* CW1x60 */ 41a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy *major_revision = silicon_type; 42a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (silicon_vers) 43a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy hw_type = HIF_8601_VERSATILE; 44a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy else 45a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy hw_type = HIF_8601_SILICON; 46a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 47a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 48a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 49a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 50a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 51a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return hw_type; 52a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy} 53a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 54a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachystatic int cw1200_load_firmware_cw1200(struct cw1200_common *priv) 55a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy{ 56a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int ret, block, num_blocks; 57a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy unsigned i; 58a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 val32; 59a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 put = 0, get = 0; 60a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u8 *buf = NULL; 61a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy const char *fw_path; 62a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy const struct firmware *firmware = NULL; 63a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 64a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Macroses are local. */ 65a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#define APB_WRITE(reg, val) \ 66a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy do { \ 67a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ 68a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) \ 69a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; \ 70a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } while (0) 71a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#define APB_READ(reg, val) \ 72a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy do { \ 73a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \ 74a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) \ 75a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; \ 76a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } while (0) 77a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#define REG_WRITE(reg, val) \ 78a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy do { \ 79a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_write_32(priv, (reg), (val)); \ 80a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) \ 81a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; \ 82a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } while (0) 83a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#define REG_READ(reg, val) \ 84a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy do { \ 85a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_read_32(priv, (reg), &(val)); \ 86a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) \ 87a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; \ 88a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } while (0) 89a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 90a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (priv->hw_revision) { 91a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1200_HW_REV_CUT10: 92a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy fw_path = FIRMWARE_CUT10; 93a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!priv->sdd_path) 94a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->sdd_path = SDD_FILE_10; 95a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 96a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1200_HW_REV_CUT11: 97a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy fw_path = FIRMWARE_CUT11; 98a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!priv->sdd_path) 99a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->sdd_path = SDD_FILE_11; 100a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 101a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1200_HW_REV_CUT20: 102a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy fw_path = FIRMWARE_CUT20; 103a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!priv->sdd_path) 104a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->sdd_path = SDD_FILE_20; 105a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 106a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1200_HW_REV_CUT22: 107a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy fw_path = FIRMWARE_CUT22; 108a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!priv->sdd_path) 109a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->sdd_path = SDD_FILE_22; 110a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 111a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1X60_HW_REV: 112a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy fw_path = FIRMWARE_CW1X60; 113a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!priv->sdd_path) 114a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->sdd_path = SDD_FILE_CW1X60; 115a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 116a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 117a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Invalid silicon revision %d.\n", priv->hw_revision); 118a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return -EINVAL; 119a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 120a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 121a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Initialize common registers */ 122a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); 123a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_PUT_REG, 0); 124a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_GET_REG, 0); 125a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); 126a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_FLAGS_REG, 0); 127a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 128a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Write the NOP Instruction */ 129a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy REG_WRITE(ST90TDS_SRAM_BASE_ADDR_REG_ID, 0xFFF20000); 130a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy REG_WRITE(ST90TDS_AHB_DPORT_REG_ID, 0xEAFFFFFE); 131a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 132a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Release CPU from RESET */ 133a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy REG_READ(ST90TDS_CONFIG_REG_ID, val32); 134a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy val32 &= ~ST90TDS_CONFIG_CPU_RESET_BIT; 135a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); 136a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 137a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Enable Clock */ 138a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT; 139a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); 140a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 141a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Load a firmware file */ 142a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = request_firmware(&firmware, fw_path, priv->pdev); 143a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret) { 144a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't load firmware file %s.\n", fw_path); 145a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 146a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 147a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 148a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); 149a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!buf) { 150a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't allocate firmware load buffer.\n"); 151a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ENOMEM; 152a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 153a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 154a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 155a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Check if the bootloader is ready */ 156a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy for (i = 0; i < 100; i += 1 + i / 2) { 157a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); 158a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 == DOWNLOAD_I_AM_HERE) 159a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 160a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy mdelay(i); 161a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } /* End of for loop */ 162a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 163a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 != DOWNLOAD_I_AM_HERE) { 164a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Bootloader is not ready.\n"); 165a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ETIMEDOUT; 166a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 167a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 168a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 169a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Calculcate number of download blocks */ 170a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; 171a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 172a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Updating the length in Download Ctrl Area */ 173a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy val32 = firmware->size; /* Explicit cast from size_t to u32 */ 174a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); 175a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 176a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Firmware downloading loop */ 177a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy for (block = 0; block < num_blocks; block++) { 178a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy size_t tx_size; 179a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy size_t block_size; 180a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 181a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* check the download status */ 182a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_READ(DOWNLOAD_STATUS_REG, val32); 183a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 != DOWNLOAD_PENDING) { 184a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Bootloader reported error %d.\n", val32); 185a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -EIO; 186a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 187a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 188a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 189a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* loop until put - get <= 24K */ 190a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy for (i = 0; i < 100; i++) { 191a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_READ(DOWNLOAD_GET_REG, get); 192a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if ((put - get) <= 193a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) 194a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 195a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy mdelay(i); 196a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 197a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 198a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { 199a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Timeout waiting for FIFO.\n"); 200a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ETIMEDOUT; 201a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 202a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 203a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 204a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* calculate the block size */ 205c8e4955653a470ece7bf580c84fc88eb58cc9850Silvan Jegen tx_size = block_size = min_t(size_t, firmware->size - put, 206c8e4955653a470ece7bf580c84fc88eb58cc9850Silvan Jegen DOWNLOAD_BLOCK_SIZE); 207a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 208a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy memcpy(buf, &firmware->data[put], block_size); 209a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (block_size < DOWNLOAD_BLOCK_SIZE) { 210a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy memset(&buf[block_size], 0, 211a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy DOWNLOAD_BLOCK_SIZE - block_size); 212a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy tx_size = DOWNLOAD_BLOCK_SIZE; 213a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 214a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 215a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* send the block to sram */ 216a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_apb_write(priv, 217a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy CW1200_APB(DOWNLOAD_FIFO_OFFSET + 218a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy (put & (DOWNLOAD_FIFO_SIZE - 1))), 219a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy buf, tx_size); 220a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 221a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't write firmware block @ %d!\n", 222a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy put & (DOWNLOAD_FIFO_SIZE - 1)); 223a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 224a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 225a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 226a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* update the put register */ 227a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy put += block_size; 228a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_WRITE(DOWNLOAD_PUT_REG, put); 229a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } /* End of firmware download loop */ 230a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 231a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Wait for the download completion */ 232a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy for (i = 0; i < 300; i += 1 + i / 2) { 233a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy APB_READ(DOWNLOAD_STATUS_REG, val32); 234a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 != DOWNLOAD_PENDING) 235a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 236a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy mdelay(i); 237a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 238a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 != DOWNLOAD_SUCCESS) { 239a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Wait for download completion failed: 0x%.8X\n", val32); 240a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ETIMEDOUT; 241a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto error; 242a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } else { 243a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("Firmware download completed.\n"); 244a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = 0; 245a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 246a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 247a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachyerror: 248a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy kfree(buf); 249a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (firmware) 250a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy release_firmware(firmware); 251a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return ret; 252a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 253a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#undef APB_WRITE 254a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#undef APB_READ 255a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#undef REG_WRITE 256a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy#undef REG_READ 257a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy} 258a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 259a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 260a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachystatic int config_reg_read(struct cw1200_common *priv, u32 *val) 261a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy{ 262a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (priv->hw_type) { 263a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_9000_SILICON_VERSATILE: { 264a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u16 val16; 265a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int ret = cw1200_reg_read_16(priv, 266a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ST90TDS_CONFIG_REG_ID, 267a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy &val16); 268a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) 269a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return ret; 270a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy *val = val16; 271a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return 0; 272a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 273a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_8601_VERSATILE: 274a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_8601_SILICON: 275a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 276a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, val); 277a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 278a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 279a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return 0; 280a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy} 281a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 282a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachystatic int config_reg_write(struct cw1200_common *priv, u32 val) 283a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy{ 284a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (priv->hw_type) { 285a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_9000_SILICON_VERSATILE: 286a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return cw1200_reg_write_16(priv, 287a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ST90TDS_CONFIG_REG_ID, 288a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy (u16)val); 289a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_8601_VERSATILE: 290a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_8601_SILICON: 291a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 292a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val); 293a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 294a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return 0; 295a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy} 296a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 297a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachyint cw1200_load_firmware(struct cw1200_common *priv) 298a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy{ 299a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int ret; 300a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int i; 301a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 val32; 302a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u16 val16; 303a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy int major_revision = -1; 304a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 305a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Read CONFIG Register */ 306a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); 307a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 308a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't read config register.\n"); 309a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 310a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 311a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 312a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 == 0 || val32 == 0xffffffff) { 313a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Bad config register value (0x%08x)\n", val32); 314a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -EIO; 315a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 316a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 317a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 318a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_type = cw1200_get_hw_type(val32, &major_revision); 319a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (priv->hw_type < 0) { 320a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't deduce hardware type.\n"); 321a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ENOTSUPP; 322a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 323a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 324a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 325a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Set DPLL Reg value, and read back to confirm writes work */ 326a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, 327a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy cw1200_dpll_from_clk(priv->hw_refclk)); 328a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 329a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't write DPLL register.\n"); 330a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 331a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 332a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 333a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy msleep(20); 334a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 335a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_read_32(priv, 336a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ST90TDS_TSET_GEN_R_W_REG_ID, &val32); 337a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 338a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't read DPLL register.\n"); 339a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 340a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 341a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 342a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val32 != cw1200_dpll_from_clk(priv->hw_refclk)) { 343a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Unable to initialise DPLL register. Wrote 0x%.8X, Read 0x%.8X.\n", 344a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy cw1200_dpll_from_clk(priv->hw_refclk), val32); 345a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -EIO; 346a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 347a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 348a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 349a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Set wakeup bit in device */ 350a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_read_16(priv, ST90TDS_CONTROL_REG_ID, &val16); 351a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 352a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("set_wakeup: can't read control register.\n"); 353a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 354a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 355a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 356a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 357a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy val16 | ST90TDS_CONT_WUP_BIT); 358a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 359a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("set_wakeup: can't write control register.\n"); 360a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 361a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 362a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 363a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Wait for wakeup */ 364a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy for (i = 0; i < 300; i += (1 + i / 2)) { 365a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_reg_read_16(priv, 366a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ST90TDS_CONTROL_REG_ID, &val16); 367a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 368a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("wait_for_wakeup: can't read control register.\n"); 369a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 370a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 371a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 372a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (val16 & ST90TDS_CONT_RDY_BIT) 373a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 374a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 375a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy msleep(i); 376a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 377a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 378a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if ((val16 & ST90TDS_CONT_RDY_BIT) == 0) { 379a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("wait_for_wakeup: device is not responding.\n"); 380a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ETIMEDOUT; 381a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 382a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 383a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 384a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (major_revision) { 385a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 1: 386a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* CW1200 Hardware detection logic : Check for CUT1.1 */ 387a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_ahb_read_32(priv, CW1200_CUT_ID_ADDR, &val32); 388a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret) { 389a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("HW detection: can't read CUT ID.\n"); 390a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 391a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 392a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 393a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (val32) { 394a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case CW1200_CUT_11_ID_STR: 395a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("CW1x00 Cut 1.1 silicon detected.\n"); 396a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_revision = CW1200_HW_REV_CUT11; 397a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 398a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 399a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("CW1x00 Cut 1.0 silicon detected.\n"); 400a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_revision = CW1200_HW_REV_CUT10; 401a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 402a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 403a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 404a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* According to ST-E, CUT<2.0 has busted BA TID0-3. 405a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy Just disable it entirely... 406a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy */ 407a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->ba_rx_tid_mask = 0; 408a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->ba_tx_tid_mask = 0; 409a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 410a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 2: { 411a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy u32 ar1, ar2, ar3; 412a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR, &ar1); 413a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret) { 414a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("(1) HW detection: can't read CUT ID\n"); 415a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 416a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 417a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 4, &ar2); 418a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret) { 419a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("(2) HW detection: can't read CUT ID.\n"); 420a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 421a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 422a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 423a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 8, &ar3); 424a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret) { 425a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("(3) HW detection: can't read CUT ID.\n"); 426a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 427a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 428a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 429a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ar1 == CW1200_CUT_22_ID_STR1 && 430a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ar2 == CW1200_CUT_22_ID_STR2 && 431a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ar3 == CW1200_CUT_22_ID_STR3) { 432a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("CW1x00 Cut 2.2 silicon detected.\n"); 433a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_revision = CW1200_HW_REV_CUT22; 434a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } else { 435a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("CW1x00 Cut 2.0 silicon detected.\n"); 436a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_revision = CW1200_HW_REV_CUT20; 437a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 438a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 439a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 440a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case 4: 441a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_info("CW1x60 silicon detected.\n"); 442a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_revision = CW1X60_HW_REV; 443a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 444a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 445a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Unsupported silicon major revision %d.\n", 446a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy major_revision); 447a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ENOTSUPP; 448a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 449a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 450a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 451a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Checking for access mode */ 452a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = config_reg_read(priv, &val32); 453a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 454a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't read config register.\n"); 455a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 456a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 457a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 458a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (!(val32 & ST90TDS_CONFIG_ACCESS_MODE_BIT)) { 459a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Device is already in QUEUE mode!\n"); 460a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -EINVAL; 461a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 462a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 463a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 464a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy switch (priv->hw_type) { 465a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy case HIF_8601_SILICON: 466a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (priv->hw_revision == CW1X60_HW_REV) { 467a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't handle CW1160/1260 firmware load yet.\n"); 468a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ENOTSUPP; 469a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 470a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 471a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = cw1200_load_firmware_cw1200(priv); 472a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy break; 473a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy default: 474a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't perform firmware load for hw type %d.\n", 475a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy priv->hw_type); 476a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = -ENOTSUPP; 477a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 478a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 479a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 480a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Firmware load error.\n"); 481a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto out; 482a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 483a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 484a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Enable interrupt signalling */ 485911373cca1b45571b62938f8f19cec24cb102471Solomon Peachy priv->hwbus_ops->lock(priv->hwbus_priv); 486c4fb19d21b003ec99ec490ba2cb60baffabc73f3Solomon Peachy ret = __cw1200_irq_enable(priv, 1); 487911373cca1b45571b62938f8f19cec24cb102471Solomon Peachy priv->hwbus_ops->unlock(priv->hwbus_priv); 488a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) 489a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto unsubscribe; 490a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 491a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Configure device for MESSSAGE MODE */ 492a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = config_reg_read(priv, &val32); 493a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 494a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't read config register.\n"); 495a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto unsubscribe; 496a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 497a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = config_reg_write(priv, val32 & ~ST90TDS_CONFIG_ACCESS_MODE_BIT); 498a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy if (ret < 0) { 499a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy pr_err("Can't write config register.\n"); 500a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy goto unsubscribe; 501a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy } 502a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 503a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Unless we read the CONFIG Register we are 504a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy * not able to get an interrupt 505a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy */ 506a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy mdelay(10); 507a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy config_reg_read(priv, &val32); 508a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 509a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachyout: 510a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return ret; 511a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy 512a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachyunsubscribe: 513a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy /* Disable interrupt signalling */ 514911373cca1b45571b62938f8f19cec24cb102471Solomon Peachy priv->hwbus_ops->lock(priv->hwbus_priv); 515a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy ret = __cw1200_irq_enable(priv, 0); 516911373cca1b45571b62938f8f19cec24cb102471Solomon Peachy priv->hwbus_ops->unlock(priv->hwbus_priv); 517a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy return ret; 518a910e4a94f6923c8c988565525f017f687bf7205Solomon Peachy} 519