261 lines
7.6 KiB
C
261 lines
7.6 KiB
C
/*
|
|
* i1480 Device Firmware Upload
|
|
*
|
|
* Copyright (C) 2005-2006 Intel Corporation
|
|
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version
|
|
* 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*
|
|
*
|
|
* 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__ */
|