|
|
|
|
@@ -54,8 +54,10 @@
|
|
|
|
|
#define TI_MODE_CONFIGURING 0 /* Device has not entered start device */
|
|
|
|
|
#define TI_MODE_BOOT 1 /* Staying in boot mode */
|
|
|
|
|
#define TI_MODE_DOWNLOAD 2 /* Made it to download mode */
|
|
|
|
|
#define TI_MODE_TRANSITIONING 3 /* Currently in boot mode but
|
|
|
|
|
transitioning to download mode */
|
|
|
|
|
#define TI_MODE_TRANSITIONING 3 /*
|
|
|
|
|
* Currently in boot mode but
|
|
|
|
|
* transitioning to download mode
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* read urb state */
|
|
|
|
|
#define EDGE_READ_URB_RUNNING 0
|
|
|
|
|
@@ -97,9 +99,11 @@ struct edgeport_port {
|
|
|
|
|
__u8 shadow_mcr;
|
|
|
|
|
__u8 shadow_lsr;
|
|
|
|
|
__u8 lsr_mask;
|
|
|
|
|
__u32 ump_read_timeout; /* Number of milliseconds the UMP will
|
|
|
|
|
wait without data before completing
|
|
|
|
|
a read short */
|
|
|
|
|
__u32 ump_read_timeout; /*
|
|
|
|
|
* Number of milliseconds the UMP will
|
|
|
|
|
* wait without data before completing
|
|
|
|
|
* a read short
|
|
|
|
|
*/
|
|
|
|
|
int baud_rate;
|
|
|
|
|
int close_pending;
|
|
|
|
|
int lsr_event;
|
|
|
|
|
@@ -115,8 +119,10 @@ struct edgeport_port {
|
|
|
|
|
struct edgeport_serial {
|
|
|
|
|
struct product_info product_info;
|
|
|
|
|
u8 TI_I2C_Type; /* Type of I2C in UMP */
|
|
|
|
|
u8 TiReadI2C; /* Set to TRUE if we have read the
|
|
|
|
|
I2c in Boot Mode */
|
|
|
|
|
u8 TiReadI2C; /*
|
|
|
|
|
* Set to TRUE if we have read the
|
|
|
|
|
* I2c in Boot Mode
|
|
|
|
|
*/
|
|
|
|
|
struct mutex es_lock;
|
|
|
|
|
int num_ports_open;
|
|
|
|
|
struct usb_serial *serial;
|
|
|
|
|
@@ -223,6 +229,11 @@ static void edge_set_termios(struct tty_struct *tty,
|
|
|
|
|
struct usb_serial_port *port, struct ktermios *old_termios);
|
|
|
|
|
static void edge_send(struct usb_serial_port *port, struct tty_struct *tty);
|
|
|
|
|
|
|
|
|
|
static int do_download_mode(struct edgeport_serial *serial,
|
|
|
|
|
const struct firmware *fw);
|
|
|
|
|
static int do_boot_mode(struct edgeport_serial *serial,
|
|
|
|
|
const struct firmware *fw);
|
|
|
|
|
|
|
|
|
|
/* sysfs attributes */
|
|
|
|
|
static int edge_create_sysfs_attrs(struct usb_serial_port *port);
|
|
|
|
|
static int edge_remove_sysfs_attrs(struct usb_serial_port *port);
|
|
|
|
|
@@ -324,7 +335,8 @@ static int read_download_mem(struct usb_device *dev, int start_address,
|
|
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
|
|
|
|
|
|
|
|
|
|
/* Read in blocks of 64 bytes
|
|
|
|
|
/*
|
|
|
|
|
* Read in blocks of 64 bytes
|
|
|
|
|
* (TI firmware can't handle more than 64 byte reads)
|
|
|
|
|
*/
|
|
|
|
|
while (length) {
|
|
|
|
|
@@ -430,7 +442,6 @@ static int write_boot_mem(struct edgeport_serial *serial,
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Write edgeport I2C memory to TI chip */
|
|
|
|
|
static int write_i2c_mem(struct edgeport_serial *serial,
|
|
|
|
|
int start_address, int length, __u8 address_type, __u8 *buffer)
|
|
|
|
|
@@ -472,8 +483,10 @@ static int write_i2c_mem(struct edgeport_serial *serial,
|
|
|
|
|
start_address += write_length;
|
|
|
|
|
buffer += write_length;
|
|
|
|
|
|
|
|
|
|
/* We should be aligned now -- can write
|
|
|
|
|
max page size bytes at a time */
|
|
|
|
|
/*
|
|
|
|
|
* We should be aligned now -- can write max page size bytes at a
|
|
|
|
|
* time.
|
|
|
|
|
*/
|
|
|
|
|
while (length) {
|
|
|
|
|
if (length > EPROM_PAGE_SIZE)
|
|
|
|
|
write_length = EPROM_PAGE_SIZE;
|
|
|
|
|
@@ -506,7 +519,8 @@ static int write_i2c_mem(struct edgeport_serial *serial,
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Examine the UMP DMA registers and LSR
|
|
|
|
|
/*
|
|
|
|
|
* Examine the UMP DMA registers and LSR
|
|
|
|
|
*
|
|
|
|
|
* Check the MSBit of the X and Y DMA byte count registers.
|
|
|
|
|
* A zero in this bit indicates that the TX DMA buffers are empty
|
|
|
|
|
@@ -523,9 +537,11 @@ static int tx_active(struct edgeport_port *port)
|
|
|
|
|
if (!oedb)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
lsr = kmalloc(1, GFP_KERNEL); /* Sigh, that's right, just one byte,
|
|
|
|
|
as not all platforms can do DMA
|
|
|
|
|
from stack */
|
|
|
|
|
/*
|
|
|
|
|
* Sigh, that's right, just one byte, as not all platforms can
|
|
|
|
|
* do DMA from stack
|
|
|
|
|
*/
|
|
|
|
|
lsr = kmalloc(1, GFP_KERNEL);
|
|
|
|
|
if (!lsr) {
|
|
|
|
|
kfree(oedb);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
@@ -615,8 +631,6 @@ static int write_rom(struct edgeport_serial *serial, int start_address,
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a descriptor header from I2C based on type */
|
|
|
|
|
static int get_descriptor_addr(struct edgeport_serial *serial,
|
|
|
|
|
int desc_type, struct ti_i2c_desc *rom_desc)
|
|
|
|
|
@@ -785,8 +799,7 @@ exit:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Build firmware header used for firmware update */
|
|
|
|
|
static int build_i2c_fw_hdr(u8 *header, struct device *dev,
|
|
|
|
|
const struct firmware *fw)
|
|
|
|
|
static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw)
|
|
|
|
|
{
|
|
|
|
|
__u8 *buffer;
|
|
|
|
|
int buffer_size;
|
|
|
|
|
@@ -797,7 +810,8 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev,
|
|
|
|
|
struct ti_i2c_firmware_rec *firmware_rec;
|
|
|
|
|
struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data;
|
|
|
|
|
|
|
|
|
|
/* In order to update the I2C firmware we must change the type 2 record
|
|
|
|
|
/*
|
|
|
|
|
* In order to update the I2C firmware we must change the type 2 record
|
|
|
|
|
* to type 0xF2. This will force the UMP to come up in Boot Mode.
|
|
|
|
|
* Then while in boot mode, the driver will download the latest
|
|
|
|
|
* firmware (padded to 15.5k) into the UMP ram. And finally when the
|
|
|
|
|
@@ -806,8 +820,10 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev,
|
|
|
|
|
* update the record type from 0xf2 to 0x02.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Allocate a 15.5k buffer + 2 bytes for version number
|
|
|
|
|
* (Firmware Record) */
|
|
|
|
|
/*
|
|
|
|
|
* Allocate a 15.5k buffer + 2 bytes for version number (Firmware
|
|
|
|
|
* Record)
|
|
|
|
|
*/
|
|
|
|
|
buffer_size = (((1024 * 16) - 512 ) +
|
|
|
|
|
sizeof(struct ti_i2c_firmware_rec));
|
|
|
|
|
|
|
|
|
|
@@ -815,7 +831,7 @@ static int build_i2c_fw_hdr(u8 *header, struct device *dev,
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
// Set entire image of 0xffs
|
|
|
|
|
/* Set entire image of 0xffs */
|
|
|
|
|
memset(buffer, 0xff, buffer_size);
|
|
|
|
|
|
|
|
|
|
/* Copy version number into firmware record */
|
|
|
|
|
@@ -981,32 +997,41 @@ static int check_fw_sanity(struct edgeport_serial *serial,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/*
|
|
|
|
|
* DownloadTIFirmware - Download run-time operating firmware to the TI5052
|
|
|
|
|
*
|
|
|
|
|
* This routine downloads the main operating code into the TI5052, using the
|
|
|
|
|
* boot code already burned into E2PROM or ROM.
|
|
|
|
|
*/
|
|
|
|
|
static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
const struct firmware *fw)
|
|
|
|
|
static int download_fw(struct edgeport_serial *serial)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = &serial->serial->dev->dev;
|
|
|
|
|
struct device *dev = &serial->serial->interface->dev;
|
|
|
|
|
int status = 0;
|
|
|
|
|
int start_address;
|
|
|
|
|
struct edge_ti_manuf_descriptor *ti_manuf_desc;
|
|
|
|
|
struct usb_interface_descriptor *interface;
|
|
|
|
|
int download_cur_ver;
|
|
|
|
|
int download_new_ver;
|
|
|
|
|
struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data;
|
|
|
|
|
const struct firmware *fw;
|
|
|
|
|
const char *fw_name = "edgeport/down3.bin";
|
|
|
|
|
struct edgeport_fw_hdr *fw_hdr;
|
|
|
|
|
|
|
|
|
|
if (check_fw_sanity(serial, fw))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
status = request_firmware(&fw, fw_name, dev);
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_err(dev, "Failed to load image \"%s\" err %d\n",
|
|
|
|
|
fw_name, status);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If on-board version is newer, "fw_version" will be updated below. */
|
|
|
|
|
if (check_fw_sanity(serial, fw)) {
|
|
|
|
|
status = -EINVAL;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fw_hdr = (struct edgeport_fw_hdr *)fw->data;
|
|
|
|
|
|
|
|
|
|
/* If on-board version is newer, "fw_version" will be updated later. */
|
|
|
|
|
serial->fw_version = (fw_hdr->major_version << 8) +
|
|
|
|
|
fw_hdr->minor_version;
|
|
|
|
|
|
|
|
|
|
/* This routine is entered by both the BOOT mode and the Download mode
|
|
|
|
|
/*
|
|
|
|
|
* This routine is entered by both the BOOT mode and the Download mode
|
|
|
|
|
* We can determine which code is running by the reading the config
|
|
|
|
|
* descriptor and if we have only one bulk pipe it is in boot mode
|
|
|
|
|
*/
|
|
|
|
|
@@ -1017,12 +1042,13 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
|
|
|
|
|
status = choose_config(serial->serial->dev);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
interface = &serial->serial->interface->cur_altsetting->desc;
|
|
|
|
|
if (!interface) {
|
|
|
|
|
dev_err(dev, "%s - no interface set, error!\n", __func__);
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
status = -ENODEV;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -1030,190 +1056,219 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
* if we have more than one endpoint we are definitely in download
|
|
|
|
|
* mode
|
|
|
|
|
*/
|
|
|
|
|
if (interface->bNumEndpoints > 1)
|
|
|
|
|
if (interface->bNumEndpoints > 1) {
|
|
|
|
|
serial->product_info.TiMode = TI_MODE_DOWNLOAD;
|
|
|
|
|
else
|
|
|
|
|
status = do_download_mode(serial, fw);
|
|
|
|
|
} else {
|
|
|
|
|
/* Otherwise we will remain in configuring mode */
|
|
|
|
|
serial->product_info.TiMode = TI_MODE_CONFIGURING;
|
|
|
|
|
status = do_boot_mode(serial, fw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
/* Download Mode */
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
|
|
|
|
|
struct ti_i2c_desc *rom_desc;
|
|
|
|
|
out:
|
|
|
|
|
release_firmware(fw);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__);
|
|
|
|
|
static int do_download_mode(struct edgeport_serial *serial,
|
|
|
|
|
const struct firmware *fw)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = &serial->serial->interface->dev;
|
|
|
|
|
int status = 0;
|
|
|
|
|
int start_address;
|
|
|
|
|
struct edge_ti_manuf_descriptor *ti_manuf_desc;
|
|
|
|
|
int download_cur_ver;
|
|
|
|
|
int download_new_ver;
|
|
|
|
|
struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data;
|
|
|
|
|
struct ti_i2c_desc *rom_desc;
|
|
|
|
|
|
|
|
|
|
status = check_i2c_image(serial);
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__);
|
|
|
|
|
return status;
|
|
|
|
|
dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__);
|
|
|
|
|
|
|
|
|
|
status = check_i2c_image(serial);
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Validate Hardware version number
|
|
|
|
|
* Read Manufacturing Descriptor from TI Based Edgeport
|
|
|
|
|
*/
|
|
|
|
|
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL);
|
|
|
|
|
if (!ti_manuf_desc)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check version number of ION descriptor */
|
|
|
|
|
if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
|
|
|
|
|
dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
|
|
|
|
|
__func__, ti_cpu_rev(ti_manuf_desc));
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
|
|
|
|
|
if (!rom_desc) {
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search for type 2 record (firmware record) */
|
|
|
|
|
start_address = get_descriptor_addr(serial,
|
|
|
|
|
I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc);
|
|
|
|
|
if (start_address != 0) {
|
|
|
|
|
struct ti_i2c_firmware_rec *firmware_version;
|
|
|
|
|
u8 *record;
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n",
|
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
|
|
firmware_version = kmalloc(sizeof(*firmware_version),
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!firmware_version) {
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate Hardware version number
|
|
|
|
|
* Read Manufacturing Descriptor from TI Based Edgeport
|
|
|
|
|
/*
|
|
|
|
|
* Validate version number
|
|
|
|
|
* Read the descriptor data
|
|
|
|
|
*/
|
|
|
|
|
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL);
|
|
|
|
|
if (!ti_manuf_desc)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
|
|
|
|
|
status = read_rom(serial, start_address +
|
|
|
|
|
sizeof(struct ti_i2c_desc),
|
|
|
|
|
sizeof(struct ti_i2c_firmware_rec),
|
|
|
|
|
(__u8 *)firmware_version);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check version number of ION descriptor */
|
|
|
|
|
if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
|
|
|
|
|
dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
|
|
|
|
|
__func__, ti_cpu_rev(ti_manuf_desc));
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Check version number of download with current
|
|
|
|
|
* version in I2c
|
|
|
|
|
*/
|
|
|
|
|
download_cur_ver = (firmware_version->Ver_Major << 8) +
|
|
|
|
|
(firmware_version->Ver_Minor);
|
|
|
|
|
download_new_ver = (fw_hdr->major_version << 8) +
|
|
|
|
|
(fw_hdr->minor_version);
|
|
|
|
|
|
|
|
|
|
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
|
|
|
|
|
if (!rom_desc) {
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n",
|
|
|
|
|
__func__, firmware_version->Ver_Major,
|
|
|
|
|
firmware_version->Ver_Minor,
|
|
|
|
|
fw_hdr->major_version, fw_hdr->minor_version);
|
|
|
|
|
|
|
|
|
|
/* Search for type 2 record (firmware record) */
|
|
|
|
|
start_address = get_descriptor_addr(serial,
|
|
|
|
|
I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc);
|
|
|
|
|
if (start_address != 0) {
|
|
|
|
|
struct ti_i2c_firmware_rec *firmware_version;
|
|
|
|
|
u8 *record;
|
|
|
|
|
/*
|
|
|
|
|
* Check if we have an old version in the I2C and
|
|
|
|
|
* update if necessary
|
|
|
|
|
*/
|
|
|
|
|
if (download_cur_ver < download_new_ver) {
|
|
|
|
|
dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n",
|
|
|
|
|
__func__,
|
|
|
|
|
firmware_version->Ver_Major,
|
|
|
|
|
firmware_version->Ver_Minor,
|
|
|
|
|
fw_hdr->major_version,
|
|
|
|
|
fw_hdr->minor_version);
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - Found Type FIRMWARE (Type 2) record\n", __func__);
|
|
|
|
|
|
|
|
|
|
firmware_version = kmalloc(sizeof(*firmware_version),
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!firmware_version) {
|
|
|
|
|
record = kmalloc(1, GFP_KERNEL);
|
|
|
|
|
if (!record) {
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate version number
|
|
|
|
|
* Read the descriptor data
|
|
|
|
|
/*
|
|
|
|
|
* In order to update the I2C firmware we must
|
|
|
|
|
* change the type 2 record to type 0xF2. This
|
|
|
|
|
* will force the UMP to come up in Boot Mode.
|
|
|
|
|
* Then while in boot mode, the driver will
|
|
|
|
|
* download the latest firmware (padded to
|
|
|
|
|
* 15.5k) into the UMP ram. Finally when the
|
|
|
|
|
* device comes back up in download mode the
|
|
|
|
|
* driver will cause the new firmware to be
|
|
|
|
|
* copied from the UMP Ram to I2C and the
|
|
|
|
|
* firmware will update the record type from
|
|
|
|
|
* 0xf2 to 0x02.
|
|
|
|
|
*/
|
|
|
|
|
status = read_rom(serial, start_address +
|
|
|
|
|
sizeof(struct ti_i2c_desc),
|
|
|
|
|
sizeof(struct ti_i2c_firmware_rec),
|
|
|
|
|
(__u8 *)firmware_version);
|
|
|
|
|
*record = I2C_DESC_TYPE_FIRMWARE_BLANK;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Change the I2C Firmware record type to
|
|
|
|
|
* 0xf2 to trigger an update
|
|
|
|
|
*/
|
|
|
|
|
status = write_rom(serial, start_address,
|
|
|
|
|
sizeof(*record), record);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check version number of download with current
|
|
|
|
|
version in I2c */
|
|
|
|
|
download_cur_ver = (firmware_version->Ver_Major << 8) +
|
|
|
|
|
(firmware_version->Ver_Minor);
|
|
|
|
|
download_new_ver = (fw_hdr->major_version << 8) +
|
|
|
|
|
(fw_hdr->minor_version);
|
|
|
|
|
/*
|
|
|
|
|
* verify the write -- must do this in order
|
|
|
|
|
* for write to complete before we do the
|
|
|
|
|
* hardware reset
|
|
|
|
|
*/
|
|
|
|
|
status = read_rom(serial,
|
|
|
|
|
start_address,
|
|
|
|
|
sizeof(*record),
|
|
|
|
|
record);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n",
|
|
|
|
|
__func__, firmware_version->Ver_Major,
|
|
|
|
|
firmware_version->Ver_Minor,
|
|
|
|
|
fw_hdr->major_version, fw_hdr->minor_version);
|
|
|
|
|
|
|
|
|
|
/* Check if we have an old version in the I2C and
|
|
|
|
|
update if necessary */
|
|
|
|
|
if (download_cur_ver < download_new_ver) {
|
|
|
|
|
dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n",
|
|
|
|
|
__func__,
|
|
|
|
|
firmware_version->Ver_Major,
|
|
|
|
|
firmware_version->Ver_Minor,
|
|
|
|
|
fw_hdr->major_version,
|
|
|
|
|
fw_hdr->minor_version);
|
|
|
|
|
|
|
|
|
|
record = kmalloc(1, GFP_KERNEL);
|
|
|
|
|
if (!record) {
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
/* In order to update the I2C firmware we must
|
|
|
|
|
* change the type 2 record to type 0xF2. This
|
|
|
|
|
* will force the UMP to come up in Boot Mode.
|
|
|
|
|
* Then while in boot mode, the driver will
|
|
|
|
|
* download the latest firmware (padded to
|
|
|
|
|
* 15.5k) into the UMP ram. Finally when the
|
|
|
|
|
* device comes back up in download mode the
|
|
|
|
|
* driver will cause the new firmware to be
|
|
|
|
|
* copied from the UMP Ram to I2C and the
|
|
|
|
|
* firmware will update the record type from
|
|
|
|
|
* 0xf2 to 0x02.
|
|
|
|
|
*/
|
|
|
|
|
*record = I2C_DESC_TYPE_FIRMWARE_BLANK;
|
|
|
|
|
|
|
|
|
|
/* Change the I2C Firmware record type to
|
|
|
|
|
0xf2 to trigger an update */
|
|
|
|
|
status = write_rom(serial, start_address,
|
|
|
|
|
sizeof(*record), record);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* verify the write -- must do this in order
|
|
|
|
|
* for write to complete before we do the
|
|
|
|
|
* hardware reset
|
|
|
|
|
*/
|
|
|
|
|
status = read_rom(serial,
|
|
|
|
|
start_address,
|
|
|
|
|
sizeof(*record),
|
|
|
|
|
record);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
|
|
|
|
|
dev_err(dev, "%s - error resetting device\n", __func__);
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - HARDWARE RESET\n", __func__);
|
|
|
|
|
|
|
|
|
|
/* Reset UMP -- Back to BOOT MODE */
|
|
|
|
|
status = ti_vsend_sync(serial->serial->dev,
|
|
|
|
|
UMPC_HARDWARE_RESET,
|
|
|
|
|
0, 0, NULL, 0,
|
|
|
|
|
TI_VSEND_TIMEOUT_DEFAULT);
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status);
|
|
|
|
|
|
|
|
|
|
/* return an error on purpose. */
|
|
|
|
|
if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
|
|
|
|
|
dev_err(dev, "%s - error resetting device\n",
|
|
|
|
|
__func__);
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
} else {
|
|
|
|
|
/* Same or newer fw version is already loaded */
|
|
|
|
|
serial->fw_version = download_cur_ver;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - HARDWARE RESET\n", __func__);
|
|
|
|
|
|
|
|
|
|
/* Reset UMP -- Back to BOOT MODE */
|
|
|
|
|
status = ti_vsend_sync(serial->serial->dev,
|
|
|
|
|
UMPC_HARDWARE_RESET,
|
|
|
|
|
0, 0, NULL, 0,
|
|
|
|
|
TI_VSEND_TIMEOUT_DEFAULT);
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - HARDWARE RESET return %d\n",
|
|
|
|
|
__func__, status);
|
|
|
|
|
|
|
|
|
|
/* return an error on purpose. */
|
|
|
|
|
kfree(record);
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
/* Search for type 0xF2 record (firmware blank record) */
|
|
|
|
|
else if ((start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) {
|
|
|
|
|
/* Same or newer fw version is already loaded */
|
|
|
|
|
serial->fw_version = download_cur_ver;
|
|
|
|
|
kfree(firmware_version);
|
|
|
|
|
}
|
|
|
|
|
/* Search for type 0xF2 record (firmware blank record) */
|
|
|
|
|
else {
|
|
|
|
|
start_address = get_descriptor_addr(serial,
|
|
|
|
|
I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc);
|
|
|
|
|
if (start_address != 0) {
|
|
|
|
|
#define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \
|
|
|
|
|
sizeof(struct ti_i2c_firmware_rec))
|
|
|
|
|
sizeof(struct ti_i2c_firmware_rec))
|
|
|
|
|
__u8 *header;
|
|
|
|
|
__u8 *vheader;
|
|
|
|
|
|
|
|
|
|
@@ -1232,7 +1287,8 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n", __func__);
|
|
|
|
|
dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n",
|
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In order to update the I2C firmware we must change
|
|
|
|
|
@@ -1245,7 +1301,7 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
* UMP Ram to I2C and the firmware will update the
|
|
|
|
|
* record type from 0xf2 to 0x02.
|
|
|
|
|
*/
|
|
|
|
|
status = build_i2c_fw_hdr(header, dev, fw);
|
|
|
|
|
status = build_i2c_fw_hdr(header, fw);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(vheader);
|
|
|
|
|
kfree(header);
|
|
|
|
|
@@ -1254,8 +1310,10 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update I2C with type 0xf2 record with correct
|
|
|
|
|
size and checksum */
|
|
|
|
|
/*
|
|
|
|
|
* Update I2C with type 0xf2 record with correct
|
|
|
|
|
* size and checksum
|
|
|
|
|
*/
|
|
|
|
|
status = write_rom(serial,
|
|
|
|
|
start_address,
|
|
|
|
|
HEADER_SIZE,
|
|
|
|
|
@@ -1268,13 +1326,16 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* verify the write -- must do this in order for
|
|
|
|
|
write to complete before we do the hardware reset */
|
|
|
|
|
/*
|
|
|
|
|
* verify the write -- must do this in order for
|
|
|
|
|
* write to complete before we do the hardware reset
|
|
|
|
|
*/
|
|
|
|
|
status = read_rom(serial, start_address,
|
|
|
|
|
HEADER_SIZE, vheader);
|
|
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_dbg(dev, "%s - can't read header back\n", __func__);
|
|
|
|
|
dev_dbg(dev, "%s - can't read header back\n",
|
|
|
|
|
__func__);
|
|
|
|
|
kfree(vheader);
|
|
|
|
|
kfree(header);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
@@ -1282,7 +1343,8 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
if (memcmp(vheader, header, HEADER_SIZE)) {
|
|
|
|
|
dev_dbg(dev, "%s - write download record failed\n", __func__);
|
|
|
|
|
dev_dbg(dev, "%s - write download record failed\n",
|
|
|
|
|
__func__);
|
|
|
|
|
kfree(vheader);
|
|
|
|
|
kfree(header);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
@@ -1301,26 +1363,33 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
0, 0, NULL, 0,
|
|
|
|
|
TI_VSEND_TIMEOUT_FW_DOWNLOAD);
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status);
|
|
|
|
|
dev_dbg(dev, "%s - Update complete 0x%x\n", __func__,
|
|
|
|
|
status);
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_err(dev,
|
|
|
|
|
"%s - UMPC_COPY_DNLD_TO_I2C failed\n",
|
|
|
|
|
__func__);
|
|
|
|
|
__func__);
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The device is running the download code
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
/* Boot Mode */
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
/* The device is running the download code */
|
|
|
|
|
kfree(rom_desc);
|
|
|
|
|
kfree(ti_manuf_desc);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int do_boot_mode(struct edgeport_serial *serial,
|
|
|
|
|
const struct firmware *fw)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = &serial->serial->interface->dev;
|
|
|
|
|
int status = 0;
|
|
|
|
|
struct edge_ti_manuf_descriptor *ti_manuf_desc;
|
|
|
|
|
struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data;
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__);
|
|
|
|
|
|
|
|
|
|
/* Configure the TI device so we can use the BULK pipes for download */
|
|
|
|
|
@@ -1336,8 +1405,10 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
goto stayinbootmode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We have an ION device (I2c Must be programmed)
|
|
|
|
|
Determine I2C image type */
|
|
|
|
|
/*
|
|
|
|
|
* We have an ION device (I2c Must be programmed)
|
|
|
|
|
* Determine I2C image type
|
|
|
|
|
*/
|
|
|
|
|
if (i2c_type_bootmode(serial))
|
|
|
|
|
goto stayinbootmode;
|
|
|
|
|
|
|
|
|
|
@@ -1349,7 +1420,8 @@ static int download_fw(struct edgeport_serial *serial,
|
|
|
|
|
__u8 *buffer;
|
|
|
|
|
int buffer_size;
|
|
|
|
|
|
|
|
|
|
/* Validate Hardware version number
|
|
|
|
|
/*
|
|
|
|
|
* Validate Hardware version number
|
|
|
|
|
* Read Manufacturing Descriptor from TI Based Edgeport
|
|
|
|
|
*/
|
|
|
|
|
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL);
|
|
|
|
|
@@ -1439,7 +1511,6 @@ stayinbootmode:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int ti_do_config(struct edgeport_port *port, int feature, int on)
|
|
|
|
|
{
|
|
|
|
|
int port_number = port->port->port_number;
|
|
|
|
|
@@ -1450,7 +1521,6 @@ static int ti_do_config(struct edgeport_port *port, int feature, int on)
|
|
|
|
|
on, NULL, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int restore_mcr(struct edgeport_port *port, __u8 mcr)
|
|
|
|
|
{
|
|
|
|
|
int status = 0;
|
|
|
|
|
@@ -1556,7 +1626,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
|
|
|
|
|
icount->frame++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void edge_interrupt_callback(struct urb *urb)
|
|
|
|
|
{
|
|
|
|
|
struct edgeport_serial *edge_serial = urb->context;
|
|
|
|
|
@@ -1616,8 +1685,9 @@ static void edge_interrupt_callback(struct urb *urb)
|
|
|
|
|
case TIUMP_INTERRUPT_CODE_LSR:
|
|
|
|
|
lsr = map_line_status(data[1]);
|
|
|
|
|
if (lsr & UMP_UART_LSR_DATA_MASK) {
|
|
|
|
|
/* Save the LSR event for bulk read
|
|
|
|
|
completion routine */
|
|
|
|
|
/*
|
|
|
|
|
* Save the LSR event for bulk read completion routine
|
|
|
|
|
*/
|
|
|
|
|
dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n",
|
|
|
|
|
__func__, port_number, lsr);
|
|
|
|
|
edge_port->lsr_event = 1;
|
|
|
|
|
@@ -1925,8 +1995,10 @@ static void edge_close(struct usb_serial_port *port)
|
|
|
|
|
if (edge_serial == NULL || edge_port == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* The bulkreadcompletion routine will check
|
|
|
|
|
* this flag and dump add read data */
|
|
|
|
|
/*
|
|
|
|
|
* The bulkreadcompletion routine will check
|
|
|
|
|
* this flag and dump add read data
|
|
|
|
|
*/
|
|
|
|
|
edge_port->close_pending = 1;
|
|
|
|
|
|
|
|
|
|
usb_kill_urb(port->read_urb);
|
|
|
|
|
@@ -2016,8 +2088,10 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
|
|
|
|
|
} else
|
|
|
|
|
edge_port->port->icount.tx += count;
|
|
|
|
|
|
|
|
|
|
/* wakeup any process waiting for writes to complete */
|
|
|
|
|
/* there is now more room in the buffer for new writes */
|
|
|
|
|
/*
|
|
|
|
|
* wakeup any process waiting for writes to complete
|
|
|
|
|
* there is now more room in the buffer for new writes
|
|
|
|
|
*/
|
|
|
|
|
if (tty)
|
|
|
|
|
tty_wakeup(tty);
|
|
|
|
|
}
|
|
|
|
|
@@ -2089,8 +2163,10 @@ static void edge_throttle(struct tty_struct *tty)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if we are implementing RTS/CTS, stop reads */
|
|
|
|
|
/* and the Edgeport will clear the RTS line */
|
|
|
|
|
/*
|
|
|
|
|
* if we are implementing RTS/CTS, stop reads
|
|
|
|
|
* and the Edgeport will clear the RTS line
|
|
|
|
|
*/
|
|
|
|
|
if (C_CRTSCTS(tty))
|
|
|
|
|
stop_read(edge_port);
|
|
|
|
|
|
|
|
|
|
@@ -2113,8 +2189,10 @@ static void edge_unthrottle(struct tty_struct *tty)
|
|
|
|
|
dev_err(&port->dev, "%s - failed to write start character, %d\n", __func__, status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* if we are implementing RTS/CTS, restart reads */
|
|
|
|
|
/* are the Edgeport will assert the RTS line */
|
|
|
|
|
/*
|
|
|
|
|
* if we are implementing RTS/CTS, restart reads
|
|
|
|
|
* are the Edgeport will assert the RTS line
|
|
|
|
|
*/
|
|
|
|
|
if (C_CRTSCTS(tty)) {
|
|
|
|
|
status = restart_read(edge_port);
|
|
|
|
|
if (status)
|
|
|
|
|
@@ -2236,8 +2314,10 @@ static void change_port_settings(struct tty_struct *tty,
|
|
|
|
|
restart_read(edge_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if we are implementing XON/XOFF, set the start and stop
|
|
|
|
|
character in the device */
|
|
|
|
|
/*
|
|
|
|
|
* if we are implementing XON/XOFF, set the start and stop
|
|
|
|
|
* character in the device
|
|
|
|
|
*/
|
|
|
|
|
config->cXon = START_CHAR(tty);
|
|
|
|
|
config->cXoff = STOP_CHAR(tty);
|
|
|
|
|
|
|
|
|
|
@@ -2467,9 +2547,6 @@ static int edge_startup(struct usb_serial *serial)
|
|
|
|
|
{
|
|
|
|
|
struct edgeport_serial *edge_serial;
|
|
|
|
|
int status;
|
|
|
|
|
const struct firmware *fw;
|
|
|
|
|
const char *fw_name = "edgeport/down3.bin";
|
|
|
|
|
struct device *dev = &serial->interface->dev;
|
|
|
|
|
u16 product_id;
|
|
|
|
|
|
|
|
|
|
/* create our private serial structure */
|
|
|
|
|
@@ -2481,16 +2558,7 @@ static int edge_startup(struct usb_serial *serial)
|
|
|
|
|
edge_serial->serial = serial;
|
|
|
|
|
usb_set_serial_data(serial, edge_serial);
|
|
|
|
|
|
|
|
|
|
status = request_firmware(&fw, fw_name, dev);
|
|
|
|
|
if (status) {
|
|
|
|
|
dev_err(dev, "Failed to load image \"%s\" err %d\n",
|
|
|
|
|
fw_name, status);
|
|
|
|
|
kfree(edge_serial);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = download_fw(edge_serial, fw);
|
|
|
|
|
release_firmware(fw);
|
|
|
|
|
status = download_fw(edge_serial);
|
|
|
|
|
if (status) {
|
|
|
|
|
kfree(edge_serial);
|
|
|
|
|
return status;
|
|
|
|
|
|