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