/* The maximum number of CPorts supported by Greybus Host Device */ #define GB_MAX_CPORTS 32
/** * struct gb_beagleplay - BeaglePlay Greybus driver * * @sd: underlying serdev device * * @gb_hd: greybus host device * * @tx_work: hdlc transmit work * @tx_producer_lock: hdlc transmit data producer lock. acquired when appending data to buffer. * @tx_consumer_lock: hdlc transmit data consumer lock. acquired when sending data over uart. * @tx_circ_buf: hdlc transmit circular buffer. * @tx_crc: hdlc transmit crc-ccitt fcs * * @rx_buffer_len: length of receive buffer filled. * @rx_buffer: hdlc frame receive buffer * @rx_in_esc: hdlc rx flag to indicate ESC frame * * @fwl: underlying firmware upload device * @bootloader_backdoor_gpio: cc1352p7 boot gpio * @rst_gpio: cc1352p7 reset gpio * @flashing_mode: flag to indicate that flashing is currently in progress * @fwl_ack_com: completion to signal an Ack/Nack * @fwl_ack: Ack/Nack byte received * @fwl_cmd_response_com: completion to signal a bootloader command response * @fwl_cmd_response: bootloader command response data * @fwl_crc32: crc32 of firmware to flash * @fwl_reset_addr: flag to indicate if we need to send COMMAND_DOWNLOAD again
*/ struct gb_beagleplay { struct serdev_device *sd;
/** * struct hdlc_payload - Structure to represent part of HDCL frame payload data. * * @len: buffer length in bytes * @buf: payload buffer
*/ struct hdlc_payload {
u16 len; void *buf;
};
/** * struct hdlc_greybus_frame - Structure to represent greybus HDLC frame payload * * @cport: cport id * @hdr: greybus operation header * @payload: greybus message payload * * The HDLC payload sent over UART for greybus address has cport preappended to greybus message
*/ struct hdlc_greybus_frame {
__le16 cport; struct gb_operation_msg_hdr hdr;
u8 payload[];
} __packed;
/** * enum cc1352_bootloader_cmd: CC1352 Bootloader Commands * * @COMMAND_DOWNLOAD: Prepares flash programming * @COMMAND_GET_STATUS: Returns the status of the last command that was issued * @COMMAND_SEND_DATA: Transfers data and programs flash * @COMMAND_RESET: Performs a system reset * @COMMAND_CRC32: Calculates CRC32 over a specified memory area * @COMMAND_BANK_ERASE: Performs an erase of all of the customer-accessible * flash sectors not protected by FCFG1 and CCFG * writeprotect bits. * * CC1352 Bootloader serial bus commands
*/ enum cc1352_bootloader_cmd {
COMMAND_DOWNLOAD = 0x21,
COMMAND_GET_STATUS = 0x23,
COMMAND_SEND_DATA = 0x24,
COMMAND_RESET = 0x25,
COMMAND_CRC32 = 0x27,
COMMAND_BANK_ERASE = 0x2c,
};
/** * enum cc1352_bootloader_status: CC1352 Bootloader COMMAND_GET_STATUS response * * @COMMAND_RET_SUCCESS: Status for successful command * @COMMAND_RET_UNKNOWN_CMD: Status for unknown command * @COMMAND_RET_INVALID_CMD: Status for invalid command (in other words, * incorrect packet size) * @COMMAND_RET_INVALID_ADR: Status for invalid input address * @COMMAND_RET_FLASH_FAIL: Status for failing flash erase or program operation
*/ enum cc1352_bootloader_status {
COMMAND_RET_SUCCESS = 0x40,
COMMAND_RET_UNKNOWN_CMD = 0x41,
COMMAND_RET_INVALID_CMD = 0x42,
COMMAND_RET_INVALID_ADR = 0x43,
COMMAND_RET_FLASH_FAIL = 0x44,
};
/** * struct cc1352_bootloader_download_cmd_data: CC1352 Bootloader COMMAND_DOWNLOAD request data * * @addr: address to start programming data into * @size: size of data that will be sent
*/ struct cc1352_bootloader_download_cmd_data {
__be32 addr;
__be32 size;
} __packed;
/** * struct cc1352_bootloader_crc32_cmd_data: CC1352 Bootloader COMMAND_CRC32 request data * * @addr: address where crc32 calculation starts * @size: number of bytes comprised by crc32 calculation * @read_repeat: number of read repeats for each data location
*/ struct cc1352_bootloader_crc32_cmd_data {
__be32 addr;
__be32 size;
__be32 read_repeat;
} __packed;
/** * csum8: Calculate 8-bit checksum on data * * @data: bytes to calculate 8-bit checksum of * @size: number of bytes * @base: starting value for checksum
*/ static u8 csum8(const u8 *data, size_t size, u8 base)
{
size_t i;
u8 sum = base;
/** * cc1352_bootloader_pkt_rx: Process a CC1352 Bootloader Packet * * @bg: beagleplay greybus driver * @data: packet buffer * @count: packet buffer size * * @return: number of bytes processed * * Here are the steps to successfully receive a packet from cc1352 bootloader * according to the docs: * 1. Wait for nonzero data to be returned from the device. This is important * as the device may send zero bytes between a sent and a received data * packet. The first nonzero byte received is the size of the packet that is * being received. * 2. Read the next byte, which is the checksum for the packet. * 3. Read the data bytes from the device. During the data phase, packet size * minus 2 bytes is sent. * 4. Calculate the checksum of the data bytes and verify it matches the * checksum received in the packet. * 5. Send an acknowledge byte or a not-acknowledge byte to the device to * indicate the successful or unsuccessful reception of the packet.
*/ staticint cc1352_bootloader_pkt_rx(struct gb_beagleplay *bg, const u8 *data,
size_t count)
{ bool is_valid = false;
switch (data[0]) { /* Skip 0x00 bytes. */ case 0x00: return 1; case CC1352_BOOTLOADER_ACK: case CC1352_BOOTLOADER_NACK:
WRITE_ONCE(bg->fwl_ack, data[0]);
complete(&bg->fwl_ack_com); return 1; case 3: if (count < 3) return 0;
is_valid = data[1] == data[2];
WRITE_ONCE(bg->fwl_cmd_response, (u32)data[2]); break; case 6: if (count < 6) return 0;
is_valid = csum8(&data[2], sizeof(__be32), 0) == data[1];
WRITE_ONCE(bg->fwl_cmd_response, get_unaligned_be32(&data[2])); break; default: return -EINVAL;
}
if (is_valid) {
cc1352_bootloader_send_ack(bg);
complete(&bg->fwl_cmd_response_com);
} else {
dev_warn(&bg->sd->dev, "Dropping bootloader packet with invalid checksum");
cc1352_bootloader_send_nack(bg);
}
return data[0];
}
static size_t cc1352_bootloader_rx(struct gb_beagleplay *bg, const u8 *data,
size_t count)
{ int ret;
size_t off = 0;
serdev_device_write_buf(bg->sd, (const u8 *)&pkt, sizeof(pkt));
ret = cc1352_bootloader_wait_for_ack(bg); if (ret < 0) return ret;
ret = wait_for_completion_timeout(
&bg->fwl_cmd_response_com,
msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT)); if (ret < 0) return dev_err_probe(&bg->sd->dev, ret, "Failed to acquire last status semaphore");
/** * cc1352_bootloader_empty_pkt: Calculate the number of empty bytes in the current packet * * @data: packet bytes array to check * @size: number of bytes in array
*/ static size_t cc1352_bootloader_empty_pkt(const u8 *data, size_t size)
{
size_t i;
for (i = 0; i < size && data[i] == 0xff; ++i) continue;
ret = cc1352_bootloader_wait_for_ack(bg); if (ret < 0) return ret;
ret = wait_for_completion_timeout(
&bg->fwl_cmd_response_com,
msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT)); if (ret < 0) return dev_err_probe(&bg->sd->dev, ret, "Failed to acquire last status semaphore");
if (bg->fwl_reset_addr) {
ret = cc1352_bootloader_download(bg, size, offset); if (ret < 0) return dev_err_probe(&bg->sd->dev,
FW_UPLOAD_ERR_HW_ERROR, "Failed to send download cmd");
bg->fwl_reset_addr = false;
}
ret = cc1352_bootloader_send_data(bg, data + offset, size); if (ret < 0) return dev_err_probe(&bg->sd->dev, FW_UPLOAD_ERR_HW_ERROR, "Failed to flash firmware");
*written = ret;
staticint gb_serdev_init(struct gb_beagleplay *bg)
{ int ret;
serdev_device_set_drvdata(bg->sd, bg);
serdev_device_set_client_ops(bg->sd, &gb_beagleplay_ops);
ret = serdev_device_open(bg->sd); if (ret) return dev_err_probe(&bg->sd->dev, ret, "Unable to open serial device");
/* * Must only be called from probe() as the devres resources allocated here * will only be released on driver detach.
*/ staticint gb_fw_init(struct gb_beagleplay *bg)
{ struct fw_upload *fwl; struct gpio_desc *desc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.