| Inaky Perez-Gonzalez | 1ba47da | 2008-09-17 16:34:20 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * i1480 Device Firmware Upload | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2005-2006 Intel Corporation | 
 | 5 |  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 
 | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or | 
 | 8 |  * modify it under the terms of the GNU General Public License version | 
 | 9 |  * 2 as published by the Free Software Foundation. | 
 | 10 |  * | 
 | 11 |  * This program is distributed in the hope that it will be useful, | 
 | 12 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 13 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 14 |  * GNU General Public License for more details. | 
 | 15 |  * | 
 | 16 |  * You should have received a copy of the GNU General Public License | 
 | 17 |  * along with this program; if not, write to the Free Software | 
 | 18 |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 
 | 19 |  * 02110-1301, USA. | 
 | 20 |  * | 
 | 21 |  * | 
 | 22 |  * This driver is the firmware uploader for the Intel Wireless UWB | 
 | 23 |  * Link 1480 device (both in the USB and PCI incarnations). | 
 | 24 |  * | 
 | 25 |  * The process is quite simple: we stop the device, write the firmware | 
 | 26 |  * to its memory and then restart it. Wait for the device to let us | 
 | 27 |  * know it is done booting firmware. Ready. | 
 | 28 |  * | 
 | 29 |  * We might have to upload before or after a phy firmware (which might | 
 | 30 |  * be done in two methods, using a normal firmware image or through | 
 | 31 |  * the MPI port). | 
 | 32 |  * | 
 | 33 |  * Because USB and PCI use common methods, we just make ops out of the | 
 | 34 |  * common operations (read, write, wait_init_done and cmd) and | 
 | 35 |  * implement them in usb.c and pci.c. | 
 | 36 |  * | 
 | 37 |  * The flow is (some parts omitted): | 
 | 38 |  * | 
 | 39 |  * i1480_{usb,pci}_probe()	  On enumerate/discovery | 
 | 40 |  *   i1480_fw_upload() | 
 | 41 |  *     i1480_pre_fw_upload() | 
 | 42 |  *       __mac_fw_upload() | 
 | 43 |  *         fw_hdrs_load() | 
 | 44 |  *         mac_fw_hdrs_push() | 
 | 45 |  *           i1480->write()       [i1480_{usb,pci}_write()] | 
 | 46 |  *           i1480_fw_cmp() | 
 | 47 |  *             i1480->read()      [i1480_{usb,pci}_read()] | 
 | 48 |  *     i1480_mac_fw_upload() | 
 | 49 |  *       __mac_fw_upload() | 
 | 50 |  *       i1480->setup(() | 
 | 51 |  *       i1480->wait_init_done() | 
 | 52 |  *       i1480_cmd_reset() | 
 | 53 |  *         i1480->cmd()           [i1480_{usb,pci}_cmd()] | 
 | 54 |  *         ... | 
 | 55 |  *     i1480_phy_fw_upload() | 
 | 56 |  *       request_firmware() | 
 | 57 |  *       i1480_mpi_write() | 
 | 58 |  *         i1480->cmd()           [i1480_{usb,pci}_cmd()] | 
| Inaky Perez-Gonzalez | 1ba47da | 2008-09-17 16:34:20 +0100 | [diff] [blame] | 59 |  * | 
 | 60 |  * Once the probe function enumerates the device and uploads the | 
 | 61 |  * firmware, we just exit with -ENODEV, as we don't really want to | 
 | 62 |  * attach to the device. | 
 | 63 |  */ | 
 | 64 | #ifndef __i1480_DFU_H__ | 
 | 65 | #define __i1480_DFU_H__ | 
 | 66 |  | 
 | 67 | #include <linux/uwb/spec.h> | 
 | 68 | #include <linux/types.h> | 
 | 69 | #include <linux/completion.h> | 
 | 70 |  | 
 | 71 | #define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018)) | 
 | 72 |  | 
 | 73 | #if i1480_FW > 0x00000302 | 
 | 74 | #define i1480_RCEB_EXTENDED | 
 | 75 | #endif | 
 | 76 |  | 
 | 77 | struct uwb_rccb; | 
 | 78 | struct uwb_rceb; | 
 | 79 |  | 
 | 80 | /* | 
 | 81 |  * Common firmware upload handlers | 
 | 82 |  * | 
 | 83 |  * Normally you embed this struct in another one specific to your hw. | 
 | 84 |  * | 
 | 85 |  * @write	Write to device's memory from buffer. | 
 | 86 |  * @read	Read from device's memory to i1480->evt_buf. | 
 | 87 |  * @setup	Setup device after basic firmware is uploaded | 
 | 88 |  * @wait_init_done | 
 | 89 |  *              Wait for the device to send a notification saying init | 
 | 90 |  *              is done. | 
 | 91 |  * @cmd         FOP for issuing the command to the hardware. The | 
 | 92 |  *              command data is contained in i1480->cmd_buf and the size | 
 | 93 |  *              is supplied as an argument. The command replied is put | 
 | 94 |  *              in i1480->evt_buf and the size in i1480->evt_result (or if | 
 | 95 |  *              an error, a < 0 errno code). | 
 | 96 |  * | 
 | 97 |  * @cmd_buf	Memory buffer used to send commands to the device. | 
 | 98 |  *              Allocated by the upper layers i1480_fw_upload(). | 
 | 99 |  *              Size has to be @buf_size. | 
 | 100 |  * @evt_buf	Memory buffer used to place the async notifications | 
 | 101 |  *              received by the hw. Allocated by the upper layers | 
 | 102 |  *              i1480_fw_upload(). | 
 | 103 |  *              Size has to be @buf_size. | 
 | 104 |  * @cmd_complete | 
 | 105 |  *              Low level driver uses this to notify code waiting afor | 
 | 106 |  *              an event that the event has arrived and data is in | 
 | 107 |  *              i1480->evt_buf (and size/result in i1480->evt_result). | 
 | 108 |  * @hw_rev | 
 | 109 |  *              Use this value to activate dfu code to support new revisions | 
 | 110 |  *              of hardware.  i1480_init() sets this to a default value. | 
 | 111 |  *              It should be updated by the USB and PCI code. | 
 | 112 |  */ | 
 | 113 | struct i1480 { | 
 | 114 | 	struct device *dev; | 
 | 115 |  | 
 | 116 | 	int (*write)(struct i1480 *, u32 addr, const void *, size_t); | 
 | 117 | 	int (*read)(struct i1480 *, u32 addr, size_t); | 
 | 118 | 	int (*rc_setup)(struct i1480 *); | 
 | 119 | 	void (*rc_release)(struct i1480 *); | 
 | 120 | 	int (*wait_init_done)(struct i1480 *); | 
 | 121 | 	int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size); | 
 | 122 | 	const char *pre_fw_name; | 
 | 123 | 	const char *mac_fw_name; | 
 | 124 | 	const char *mac_fw_name_deprecate;	/* FIXME: Will go away */ | 
 | 125 | 	const char *phy_fw_name; | 
 | 126 | 	u8 hw_rev; | 
 | 127 |  | 
 | 128 | 	size_t buf_size;	/* size of both evt_buf and cmd_buf */ | 
 | 129 | 	void *evt_buf, *cmd_buf; | 
 | 130 | 	ssize_t evt_result; | 
 | 131 | 	struct completion evt_complete; | 
| Inaky Perez-Gonzalez | 1ba47da | 2008-09-17 16:34:20 +0100 | [diff] [blame] | 132 | }; | 
 | 133 |  | 
 | 134 | static inline | 
 | 135 | void i1480_init(struct i1480 *i1480) | 
 | 136 | { | 
 | 137 | 	i1480->hw_rev = 1; | 
 | 138 | 	init_completion(&i1480->evt_complete); | 
 | 139 | } | 
 | 140 |  | 
 | 141 | extern int i1480_fw_upload(struct i1480 *); | 
 | 142 | extern int i1480_pre_fw_upload(struct i1480 *); | 
 | 143 | extern int i1480_mac_fw_upload(struct i1480 *); | 
 | 144 | extern int i1480_phy_fw_upload(struct i1480 *); | 
 | 145 | extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t); | 
 | 146 | extern int i1480_rceb_check(const struct i1480 *, | 
 | 147 | 			    const struct uwb_rceb *, const char *, u8, | 
| Anderson Lizardo | b5784f1 | 2008-09-17 16:34:38 +0100 | [diff] [blame] | 148 | 			    u8, unsigned); | 
| Inaky Perez-Gonzalez | 1ba47da | 2008-09-17 16:34:20 +0100 | [diff] [blame] | 149 |  | 
 | 150 | enum { | 
 | 151 | 	/* Vendor specific command type */ | 
 | 152 | 	i1480_CET_VS1 = 		0xfd, | 
 | 153 | 	/* i1480 commands */ | 
 | 154 | 	i1480_CMD_SET_IP_MAS = 		0x000e, | 
 | 155 | 	i1480_CMD_GET_MAC_PHY_INFO = 	0x0003, | 
 | 156 | 	i1480_CMD_MPI_WRITE =		0x000f, | 
 | 157 | 	i1480_CMD_MPI_READ = 		0x0010, | 
 | 158 | 	/* i1480 events */ | 
 | 159 | #if i1480_FW > 0x00000302 | 
 | 160 | 	i1480_EVT_CONFIRM = 		0x0002, | 
 | 161 | 	i1480_EVT_RM_INIT_DONE = 	0x0101, | 
 | 162 | 	i1480_EVT_DEV_ADD = 		0x0103, | 
 | 163 | 	i1480_EVT_DEV_RM = 		0x0104, | 
 | 164 | 	i1480_EVT_DEV_ID_CHANGE = 	0x0105, | 
 | 165 | 	i1480_EVT_GET_MAC_PHY_INFO =	i1480_CMD_GET_MAC_PHY_INFO, | 
 | 166 | #else | 
 | 167 | 	i1480_EVT_CONFIRM = 		0x0002, | 
 | 168 | 	i1480_EVT_RM_INIT_DONE = 	0x0101, | 
 | 169 | 	i1480_EVT_DEV_ADD = 		0x0103, | 
 | 170 | 	i1480_EVT_DEV_RM = 		0x0104, | 
 | 171 | 	i1480_EVT_DEV_ID_CHANGE = 	0x0105, | 
 | 172 | 	i1480_EVT_GET_MAC_PHY_INFO =	i1480_EVT_CONFIRM, | 
 | 173 | #endif | 
 | 174 | }; | 
 | 175 |  | 
 | 176 |  | 
 | 177 | struct i1480_evt_confirm { | 
 | 178 | 	struct uwb_rceb rceb; | 
 | 179 | #ifdef i1480_RCEB_EXTENDED | 
 | 180 | 	__le16 wParamLength; | 
 | 181 | #endif | 
 | 182 | 	u8 bResultCode; | 
 | 183 | } __attribute__((packed)); | 
 | 184 |  | 
 | 185 |  | 
 | 186 | struct i1480_rceb { | 
 | 187 | 	struct uwb_rceb rceb; | 
 | 188 | #ifdef i1480_RCEB_EXTENDED | 
 | 189 | 	__le16 wParamLength; | 
 | 190 | #endif | 
 | 191 | } __attribute__((packed)); | 
 | 192 |  | 
 | 193 |  | 
 | 194 | /** | 
 | 195 |  * Get MAC & PHY Information confirm event structure | 
 | 196 |  * | 
 | 197 |  * Confirm event returned by the command. | 
 | 198 |  */ | 
 | 199 | struct i1480_evt_confirm_GMPI { | 
 | 200 | #if i1480_FW > 0x00000302 | 
 | 201 | 	struct uwb_rceb rceb; | 
 | 202 | 	__le16 wParamLength; | 
 | 203 | 	__le16 status; | 
 | 204 | 	u8 mac_addr[6];		/* EUI-64 bit IEEE address [still 8 bytes?] */ | 
 | 205 | 	u8 dev_addr[2]; | 
 | 206 | 	__le16 mac_fw_rev;	/* major = v >> 8; minor = v & 0xff */ | 
 | 207 | 	u8 hw_rev; | 
 | 208 | 	u8 phy_vendor; | 
 | 209 | 	u8 phy_rev;		/* major v = >> 8; minor = v & 0xff */ | 
 | 210 | 	__le16 mac_caps; | 
 | 211 | 	u8 phy_caps[3]; | 
 | 212 | 	u8 key_stores; | 
 | 213 | 	__le16 mcast_addr_stores; | 
 | 214 | 	u8 sec_mode_supported; | 
 | 215 | #else | 
 | 216 | 	struct uwb_rceb rceb; | 
 | 217 | 	u8 status; | 
 | 218 | 	u8 mac_addr[8];         /* EUI-64 bit IEEE address [still 8 bytes?] */ | 
 | 219 | 	u8 dev_addr[2]; | 
 | 220 | 	__le16 mac_fw_rev;      /* major = v >> 8; minor = v & 0xff */ | 
 | 221 | 	__le16 phy_fw_rev;      /* major v = >> 8; minor = v & 0xff */ | 
 | 222 | 	__le16 mac_caps; | 
 | 223 | 	u8 phy_caps; | 
 | 224 | 	u8 key_stores; | 
 | 225 | 	__le16 mcast_addr_stores; | 
 | 226 | 	u8 sec_mode_supported; | 
 | 227 | #endif | 
 | 228 | } __attribute__((packed)); | 
 | 229 |  | 
 | 230 |  | 
 | 231 | struct i1480_cmd_mpi_write { | 
 | 232 | 	struct uwb_rccb rccb; | 
 | 233 | 	__le16 size; | 
 | 234 | 	u8 data[]; | 
 | 235 | }; | 
 | 236 |  | 
 | 237 |  | 
 | 238 | struct i1480_cmd_mpi_read { | 
 | 239 | 	struct uwb_rccb rccb; | 
 | 240 | 	__le16 size; | 
 | 241 | 	struct { | 
 | 242 | 		u8 page, offset; | 
 | 243 | 	} __attribute__((packed)) data[]; | 
 | 244 | } __attribute__((packed)); | 
 | 245 |  | 
 | 246 |  | 
 | 247 | struct i1480_evt_mpi_read { | 
 | 248 | 	struct uwb_rceb rceb; | 
 | 249 | #ifdef i1480_RCEB_EXTENDED | 
 | 250 | 	__le16 wParamLength; | 
 | 251 | #endif | 
 | 252 | 	u8 bResultCode; | 
 | 253 | 	__le16 size; | 
 | 254 | 	struct { | 
 | 255 | 		u8 page, offset, value; | 
 | 256 | 	} __attribute__((packed)) data[]; | 
 | 257 | } __attribute__((packed)); | 
 | 258 |  | 
 | 259 |  | 
 | 260 | #endif /* #ifndef __i1480_DFU_H__ */ |