Inaky Perez-Gonzalez | 1ba47da | 2008-09-17 16:34:20 +0100 | [diff] [blame] | 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 | */ |
| 51 | static |
| 52 | int 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 | } |
| 74 | out: |
| 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 | */ |
| 99 | static |
| 100 | int 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; |
| 143 | out: |
| 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 | */ |
| 162 | int 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); |
| 194 | error_phy_status: |
| 195 | error_mpi_status: |
| 196 | error_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); |
| 201 | out: |
| 202 | return result; |
| 203 | } |