summaryrefslogtreecommitdiffstats
path: root/drivers/uwb/i1480/dfu/i1480-dfu.h
blob: 9dd567d174b3ff525349ff44e6e597f403856598 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * i1480 Device Firmware Upload
 *
 * Copyright (C) 2005-2006 Intel Corporation
 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 *
 * This driver is the firmware uploader for the Intel Wireless UWB
 * Link 1480 device (both in the USB and PCI incarnations).
 *
 * The process is quite simple: we stop the device, write the firmware
 * to its memory and then restart it. Wait for the device to let us
 * know it is done booting firmware. Ready.
 *
 * We might have to upload before or after a phy firmware (which might
 * be done in two methods, using a normal firmware image or through
 * the MPI port).
 *
 * Because USB and PCI use common methods, we just make ops out of the
 * common operations (read, write, wait_init_done and cmd) and
 * implement them in usb.c and pci.c.
 *
 * The flow is (some parts omitted):
 *
 * i1480_{usb,pci}_probe()	  On enumerate/discovery
 *   i1480_fw_upload()
 *     i1480_pre_fw_upload()
 *       __mac_fw_upload()
 *         fw_hdrs_load()
 *         mac_fw_hdrs_push()
 *           i1480->write()       [i1480_{usb,pci}_write()]
 *           i1480_fw_cmp()
 *             i1480->read()      [i1480_{usb,pci}_read()]
 *     i1480_mac_fw_upload()
 *       __mac_fw_upload()
 *       i1480->setup(()
 *       i1480->wait_init_done()
 *       i1480_cmd_reset()
 *         i1480->cmd()           [i1480_{usb,pci}_cmd()]
 *         ...
 *     i1480_phy_fw_upload()
 *       request_firmware()
 *       i1480_mpi_write()
 *         i1480->cmd()           [i1480_{usb,pci}_cmd()]
 *
 * Once the probe function enumerates the device and uploads the
 * firmware, we just exit with -ENODEV, as we don't really want to
 * attach to the device.
 */
#ifndef __i1480_DFU_H__
#define __i1480_DFU_H__

#include <linux/uwb/spec.h>
#include <linux/types.h>
#include <linux/completion.h>

#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018))

#if i1480_FW > 0x00000302
#define i1480_RCEB_EXTENDED
#endif

struct uwb_rccb;
struct uwb_rceb;

/*
 * Common firmware upload handlers
 *
 * Normally you embed this struct in another one specific to your hw.
 *
 * @write	Write to device's memory from buffer.
 * @read	Read from device's memory to i1480->evt_buf.
 * @setup	Setup device after basic firmware is uploaded
 * @wait_init_done
 *              Wait for the device to send a notification saying init
 *              is done.
 * @cmd         FOP for issuing the command to the hardware. The
 *              command data is contained in i1480->cmd_buf and the size
 *              is supplied as an argument. The command replied is put
 *              in i1480->evt_buf and the size in i1480->evt_result (or if
 *              an error, a < 0 errno code).
 *
 * @cmd_buf	Memory buffer used to send commands to the device.
 *              Allocated by the upper layers i1480_fw_upload().
 *              Size has to be @buf_size.
 * @evt_buf	Memory buffer used to place the async notifications
 *              received by the hw. Allocated by the upper layers
 *              i1480_fw_upload().
 *              Size has to be @buf_size.
 * @cmd_complete
 *              Low level driver uses this to notify code waiting afor
 *              an event that the event has arrived and data is in
 *              i1480->evt_buf (and size/result in i1480->evt_result).
 * @hw_rev
 *              Use this value to activate dfu code to support new revisions
 *              of hardware.  i1480_init() sets this to a default value.
 *              It should be updated by the USB and PCI code.
 */
struct i1480 {
	struct device *dev;

	int (*write)(struct i1480 *, u32 addr, const void *, size_t);
	int (*read)(struct i1480 *, u32 addr, size_t);
	int (*rc_setup)(struct i1480 *);
	void (*rc_release)(struct i1480 *);
	int (*wait_init_done)(struct i1480 *);
	int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size);
	const char *pre_fw_name;
	const char *mac_fw_name;
	const char *mac_fw_name_deprecate;	/* FIXME: Will go away */
	const char *phy_fw_name;
	u8 hw_rev;

	size_t buf_size;	/* size of both evt_buf and cmd_buf */
	void *evt_buf, *cmd_buf;
	ssize_t evt_result;
	struct completion evt_complete;
};

static inline
void i1480_init(struct i1480 *i1480)
{
	i1480->hw_rev = 1;
	init_completion(&i1480->evt_complete);
}

extern int i1480_fw_upload(struct i1480 *);
extern int i1480_pre_fw_upload(struct i1480 *);
extern int i1480_mac_fw_upload(struct i1480 *);
extern int i1480_phy_fw_upload(struct i1480 *);
extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t);
extern int i1480_rceb_check(const struct i1480 *,
			    const struct uwb_rceb *, const char *, u8,
			    u8, unsigned);

enum {
	/* Vendor specific command type */
	i1480_CET_VS1 = 		0xfd,
	/* i1480 commands */
	i1480_CMD_SET_IP_MAS = 		0x000e,
	i1480_CMD_GET_MAC_PHY_INFO = 	0x0003,
	i1480_CMD_MPI_WRITE =		0x000f,
	i1480_CMD_MPI_READ = 		0x0010,
	/* i1480 events */
#if i1480_FW > 0x00000302
	i1480_EVT_CONFIRM = 		0x0002,
	i1480_EVT_RM_INIT_DONE = 	0x0101,
	i1480_EVT_DEV_ADD = 		0x0103,
	i1480_EVT_DEV_RM = 		0x0104,
	i1480_EVT_DEV_ID_CHANGE = 	0x0105,
	i1480_EVT_GET_MAC_PHY_INFO =	i1480_CMD_GET_MAC_PHY_INFO,
#else
	i1480_EVT_CONFIRM = 		0x0002,
	i1480_EVT_RM_INIT_DONE = 	0x0101,
	i1480_EVT_DEV_ADD = 		0x0103,
	i1480_EVT_DEV_RM = 		0x0104,
	i1480_EVT_DEV_ID_CHANGE = 	0x0105,
	i1480_EVT_GET_MAC_PHY_INFO =	i1480_EVT_CONFIRM,
#endif
};


struct i1480_evt_confirm {
	struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
	__le16 wParamLength;
#endif
	u8 bResultCode;
} __attribute__((packed));


struct i1480_rceb {
	struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
	__le16 wParamLength;
#endif
} __attribute__((packed));


/**
 * Get MAC & PHY Information confirm event structure
 *
 * Confirm event returned by the command.
 */
struct i1480_evt_confirm_GMPI {
#if i1480_FW > 0x00000302
	struct uwb_rceb rceb;
	__le16 wParamLength;
	__le16 status;
	u8 mac_addr[6];		/* EUI-64 bit IEEE address [still 8 bytes?] */
	u8 dev_addr[2];
	__le16 mac_fw_rev;	/* major = v >> 8; minor = v & 0xff */
	u8 hw_rev;
	u8 phy_vendor;
	u8 phy_rev;		/* major v = >> 8; minor = v & 0xff */
	__le16 mac_caps;
	u8 phy_caps[3];
	u8 key_stores;
	__le16 mcast_addr_stores;
	u8 sec_mode_supported;
#else
	struct uwb_rceb rceb;
	u8 status;
	u8 mac_addr[8];         /* EUI-64 bit IEEE address [still 8 bytes?] */
	u8 dev_addr[2];
	__le16 mac_fw_rev;      /* major = v >> 8; minor = v & 0xff */
	__le16 phy_fw_rev;      /* major v = >> 8; minor = v & 0xff */
	__le16 mac_caps;
	u8 phy_caps;
	u8 key_stores;
	__le16 mcast_addr_stores;
	u8 sec_mode_supported;
#endif
} __attribute__((packed));


struct i1480_cmd_mpi_write {
	struct uwb_rccb rccb;
	__le16 size;
	u8 data[];
};


struct i1480_cmd_mpi_read {
	struct uwb_rccb rccb;
	__le16 size;
	struct {
		u8 page, offset;
	} __attribute__((packed)) data[];
} __attribute__((packed));


struct i1480_evt_mpi_read {
	struct uwb_rceb rceb;
#ifdef i1480_RCEB_EXTENDED
	__le16 wParamLength;
#endif
	u8 bResultCode;
	__le16 size;
	struct {
		u8 page, offset, value;
	} __attribute__((packed)) data[];
} __attribute__((packed));


#endif /* #ifndef __i1480_DFU_H__ */