1/* 2 * Intel Wireless UWB Link 1480 3 * PHY parameters upload 4 * 5 * Copyright (C) 2005-2006 Intel Corporation 6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License version 10 * 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 * 02110-1301, USA. 21 * 22 * 23 * Code for uploading the PHY parameters to the PHY through the UWB 24 * Radio Control interface. 25 * 26 * We just send the data through the MPI interface using HWA-like 27 * commands and then reset the PHY to make sure it is ok. 28 */ 29#include <linux/delay.h> 30#include <linux/device.h> 31#include <linux/firmware.h> 32#include <linux/usb/wusb.h> 33#include "i1480-dfu.h" 34 35 36/** 37 * Write a value array to an address of the MPI interface 38 * 39 * @i1480: Device descriptor 40 * @data: Data array to write 41 * @size: Size of the data array 42 * @returns: 0 if ok, < 0 errno code on error. 43 * 44 * The data array is organized into pairs: 45 * 46 * ADDRESS VALUE 47 * 48 * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has 49 * to be a multiple of three. 50 */ 51static 52int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size) 53{ 54 int result; 55 struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf; 56 struct i1480_evt_confirm *reply = i1480->evt_buf; 57 58 BUG_ON(size > 480); 59 result = -ENOMEM; 60 cmd->rccb.bCommandType = i1480_CET_VS1; 61 cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE); 62 cmd->size = cpu_to_le16(size); 63 memcpy(cmd->data, data, size); 64 reply->rceb.bEventType = i1480_CET_VS1; 65 reply->rceb.wEvent = i1480_CMD_MPI_WRITE; 66 result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply)); 67 if (result < 0) 68 goto out; 69 if (reply->bResultCode != UWB_RC_RES_SUCCESS) { 70 dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n", 71 reply->bResultCode); 72 result = -EIO; 73 } 74out: 75 return result; 76} 77 78 79/** 80 * Read a value array to from an address of the MPI interface 81 * 82 * @i1480: Device descriptor 83 * @data: where to place the read array 84 * @srcaddr: Where to read from 85 * @size: Size of the data read array 86 * @returns: 0 if ok, < 0 errno code on error. 87 * 88 * The command data array is organized into pairs ADDR0 ADDR1..., and 89 * the returned data in ADDR0 VALUE0 ADDR1 VALUE1... 90 * 91 * We generate the command array to be a sequential read and then 92 * rearrange the result. 93 * 94 * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply. 95 * 96 * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount 97 * of values we can read is (512 - sizeof(*reply)) / 3 98 */ 99static 100int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size) 101{ 102 int result; 103 struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf; 104 struct i1480_evt_mpi_read *reply = i1480->evt_buf; 105 unsigned cnt; 106 107 memset(i1480->cmd_buf, 0x69, 512); 108 memset(i1480->evt_buf, 0x69, 512); 109 110 BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3); 111 result = -ENOMEM; 112 cmd->rccb.bCommandType = i1480_CET_VS1; 113 cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ); 114 cmd->size = cpu_to_le16(3*size); 115 for (cnt = 0; cnt < size; cnt++) { 116 cmd->data[cnt].page = (srcaddr + cnt) >> 8; 117 cmd->data[cnt].offset = (srcaddr + cnt) & 0xff; 118 } 119 reply->rceb.bEventType = i1480_CET_VS1; 120 reply->rceb.wEvent = i1480_CMD_MPI_READ; 121 result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size, 122 sizeof(*reply) + 3*size); 123 if (result < 0) 124 goto out; 125 if (reply->bResultCode != UWB_RC_RES_SUCCESS) { 126 dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n", 127 reply->bResultCode); 128 result = -EIO; 129 } 130 for (cnt = 0; cnt < size; cnt++) { 131 if (reply->data[cnt].page != (srcaddr + cnt) >> 8) 132 dev_err(i1480->dev, "MPI-READ: page inconsistency at " 133 "index %u: expected 0x%02x, got 0x%02x\n", cnt, 134 (srcaddr + cnt) >> 8, reply->data[cnt].page); 135 if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff)) 136 dev_err(i1480->dev, "MPI-READ: offset inconsistency at " 137 "index %u: expected 0x%02x, got 0x%02x\n", cnt, 138 (srcaddr + cnt) & 0x00ff, 139 reply->data[cnt].offset); 140 data[cnt] = reply->data[cnt].value; 141 } 142 result = 0; 143out: 144 return result; 145} 146 147 148/** 149 * Upload a PHY firmware, wait for it to start 150 * 151 * @i1480: Device instance 152 * @fw_name: Name of the file that contains the firmware 153 * 154 * We assume the MAC fw is up and running. This means we can use the 155 * MPI interface to write the PHY firmware. Once done, we issue an 156 * MBOA Reset, which will force the MAC to reset and reinitialize the 157 * PHY. If that works, we are ready to go. 158 * 159 * Max packet size for the MPI write is 512, so the max buffer is 480 160 * (which gives us 160 byte triads of MSB, LSB and VAL for the data). 161 */ 162int i1480_phy_fw_upload(struct i1480 *i1480) 163{ 164 int result; 165 const struct firmware *fw; 166 const char *data_itr, *data_top; 167 const size_t MAX_BLK_SIZE = 480; /* 160 triads */ 168 size_t data_size; 169 u8 phy_stat; 170 171 result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev); 172 if (result < 0) 173 goto out; 174 /* Loop writing data in chunks as big as possible until done. */ 175 for (data_itr = fw->data, data_top = data_itr + fw->size; 176 data_itr < data_top; data_itr += MAX_BLK_SIZE) { 177 data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr)); 178 result = i1480_mpi_write(i1480, data_itr, data_size); 179 if (result < 0) 180 goto error_mpi_write; 181 } 182 /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */ 183 result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1); 184 if (result < 0) { 185 dev_err(i1480->dev, "PHY: can't get status: %d\n", result); 186 goto error_mpi_status; 187 } 188 if (phy_stat != 0) { 189 result = -ENODEV; 190 dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat); 191 goto error_phy_status; 192 } 193 dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name); 194error_phy_status: 195error_mpi_status: 196error_mpi_write: 197 release_firmware(fw); 198 if (result < 0) 199 dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), " 200 "power cycle device\n", i1480->phy_fw_name, result); 201out: 202 return result; 203} 204