blob: 2648d7d2285c1164b87c12007f000eb57c697aa3 [file]
/* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "include/platform.h"
#include "rts5453.h"
// #define DO_FLASH_PROTECT
int rts5453_do_firmware_update(struct ucsi_pd_driver* pd, const char* filepath,
int dry_run) {
struct rts5453_device* dev = (struct rts5453_device*)pd->dev;
int fd;
int flash_bank = 0;
char fbuf[FW_BLOCK_CHUNK_SIZE];
ssize_t bytes_read = 0;
int offset = 0;
struct rts5453_ic_status status;
if (!filepath) {
ELOG("Filepath was empty.");
return -1;
}
DLOG("Fwupdate: File path is %s", filepath);
// Open the file descriptor
fd = open(filepath, O_RDONLY);
if (fd < 0) {
ELOG("Could not open file at %s", filepath);
return -1;
}
// Do fwupdate commands:
// - VENDOR_CMD_ENABLE (smbus)
// - GET_IC_STATUS to figure out which bank to write to
// - VENDOR_CMD_ENABLE (smbus|flash)
// - SET_FLASH_PROTECTION (unlock)
// - Loop
// - Write to bank 0/1 (32-3 = 27 bytes per loop)
// - VENDOR_CMD_ENABLE (smbus) (disable flash access)
// - ISP_VALIDATION
// - SET_FLASH_PROTECTION (lock)
// - (!dry_run) RESET_TO_FLASH
if (rts5453_vendor_cmd_enable_smbus(dev, RTS_DEFAULT_PORT) == -1) {
ELOG("Failed to enable vendor commands");
return -1;
}
if (rts5453_get_ic_status(dev, &status) == -1) {
ELOG("Failed to GET_IC_STATUS");
goto cleanup;
}
// Set the flash bank as the opposite of the one currently in-use
flash_bank = status.flash_bank == 1 ? 0 : 1;
printf("Writing to flash_bank %d\n", flash_bank);
if (rts5453_vendor_cmd_enable_smbus_flash_access(dev, RTS_DEFAULT_PORT) == -1) {
ELOG("Failed to enable flash access");
goto cleanup;
}
#ifdef DO_FLASH_PROTECT
if (rts5453_set_flash_protection(dev, RTS5453_FLASH_PROTECT_DISABLE) == -1) {
ELOG("Failed to disable flash protection");
goto cleanup;
}
#endif
// Keep writing while there's data in the firmware image.
while ((bytes_read = read(fd, fbuf, FW_BLOCK_CHUNK_SIZE)) > 0) {
if (rts5453_write_to_flash(dev, flash_bank, fbuf, bytes_read, offset) ==
-1) {
ELOG("Failed to write to flash at bank %d (bytes = %d, offset = %d)",
flash_bank, (int)bytes_read, offset);
goto cleanup;
}
offset += bytes_read;
}
if (rts5453_vendor_cmd_enable_smbus(dev, RTS_DEFAULT_PORT) == -1) {
ELOG("Failed to disable smbus flash access.");
goto cleanup;
}
if (rts5453_isp_validation(dev) == -1) {
ELOG("Failed ISP validation.");
goto cleanup;
}
#ifdef DO_FLASH_PROTECT
if (rts5453_set_flash_protection(dev, RTS5453_FLASH_PROTECT_ENABLE) == -1) {
ELOG("Failed to enable flash protection");
goto cleanup;
}
#endif
// Only commit changes if not dry run
if (!dry_run) {
if (rts5453_reset_to_flash(dev) == -1) {
ELOG("Reset to flash failed.");
goto cleanup;
}
}
return 0;
cleanup:
// Protect flash and disable smbus
if (rts5453_vendor_cmd_disable(dev, RTS_DEFAULT_PORT) == -1) {
ELOG("Failed to disable vendor commands and flash access");
return -1;
}
return -1;
}
int rts5453_get_info(struct ucsi_pd_driver* pd) {
struct rts5453_device* dev = (struct rts5453_device*)pd->dev;
struct rts5453_ic_status status;
if (rts5453_vendor_cmd_enable_smbus(dev, RTS_DEFAULT_PORT) == -1) {
ELOG("Failed to enable vendor commands");
return -1;
}
if (rts5453_get_ic_status(dev, &status) == -1) {
ELOG("Failed to get ic status");
return -1;
}
printf("Code location (%s), Bank (%d)\n",
status.code_location ? "Flash" : "ROM", status.flash_bank);
printf("Fw version: %d.%d.%d\n", status.major_version, status.minor_version,
status.patch_version);
printf("VID:PID: %02x%02x:%02x%02x\n", status.vid_pid[1], status.vid_pid[0],
status.vid_pid[3], status.vid_pid[2]);
return 0;
}