| // Copyright 2024 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #pragma once |
| |
| #include "firmware_updater_interface.hpp" |
| #include "host_command.hpp" |
| |
| #include <boost/endian/arithmetic.hpp> |
| |
| #include <array> |
| #include <cstdint> |
| |
| namespace google |
| { |
| namespace hoth |
| { |
| namespace internal |
| { |
| using boost::endian::little_uint16_t; |
| using boost::endian::little_uint32_t; |
| |
| /** @brief Equivalent of `hoth_update_region_response` in |
| * google3/host_commands.h |
| */ |
| struct HothUpdateRegionResponse |
| { |
| little_uint32_t offset; |
| little_uint32_t len; |
| uint8_t flags; |
| }; |
| |
| /** @brief Equivalent of `ec_response_sps_passthrough_status` in |
| * google3/host_commands.h |
| */ |
| struct SpsPassthroughStatusResponse |
| { |
| uint8_t enabled; |
| std::array<uint8_t, 3> padding; |
| }; |
| |
| /** @brief Equivalent of `ec_spi_operation_request` in |
| * google3/host_commands.h |
| */ |
| struct EcSpiOperationHeader |
| { |
| little_uint16_t mosiLen; |
| little_uint16_t misoLen; |
| }; |
| |
| enum class ResetMode : uint8_t |
| { |
| needed, |
| never, |
| ignore, |
| needed_active, |
| }; |
| |
| /** @class FirmwareSpiUpdater class |
| * @brief Hoth firmware updater using Hoth SPI command |
| */ |
| class FirmwareSpiUpdater : public FirmwareUpdater |
| { |
| public: |
| using Base = FirmwareUpdater; |
| |
| /** @brief A RAII object to prepare and cleanup the spiWrite op(s). |
| */ |
| class SpiWritePreparer |
| { |
| public: |
| SpiWritePreparer(FirmwareSpiUpdater* updater, ResetMode mode); |
| SpiWritePreparer(SpiWritePreparer&& preparer) noexcept; |
| ~SpiWritePreparer(); |
| |
| SpiWritePreparer(const SpiWritePreparer&) = delete; |
| SpiWritePreparer& operator=(const SpiWritePreparer&) = delete; |
| SpiWritePreparer& operator=(SpiWritePreparer&&) = delete; |
| |
| private: |
| FirmwareSpiUpdater* fwUpdater{nullptr}; |
| bool setSpsPassThoughDisabled{false}; |
| bool didResetTarget{false}; |
| ResetMode resetMode{ResetMode::needed}; |
| }; |
| |
| /** @brief Constructor |
| * |
| * @param[in] hostCmd - Reference to the host command interface |
| * @param[in] addressSize - SPI operation address size |
| * @param[in] targetReset - Whether to reset target |
| * @param[in] ignoreAddressMode - Ignore address mode change failure |
| */ |
| explicit FirmwareSpiUpdater(HostCommand* hostCmd, uint8_t addressSize = 4, |
| ResetMode targetReset = ResetMode::never, |
| bool ignoreAddressMode = false); |
| |
| [[nodiscard]] SpiWritePreparer prepareSpiWrite(); |
| |
| /** @brief Updates firmware. |
| * |
| * @param[in] firmwareData - Hoth firmware image. |
| */ |
| void update(std::vector<uint8_t> firmwareData) override; |
| |
| /** @brief SPI write to arbitrary address |
| * |
| * @param[in] address - SPI offset to start writing from |
| * @param[in] data - Data to write to the SPI EEPROM |
| */ |
| void spiWrite(uint32_t address, std::vector<uint8_t> data) override; |
| |
| private: |
| /** @brief Check if update firmware with Hoth is supported |
| * Check firmware update mode supported using Hoth |
| * EC_PRV_CMD_HOTH_GET_REGION_FROM_IMG_DESC command. |
| * |
| * @param[in] firmwareSize - Hoth firmware image length. |
| * |
| * @return absolute address from which new firmware data can be written |
| */ |
| uint32_t supportUpdateWithHothSpi(uint32_t firmwareSize); |
| |
| /** @brief Set/release target from reset |
| * Calls EC_PRV_CMD_HOTH_RESET_TARGET command to reset target |
| * |
| * We only need to call this funciton when the build option is enabled. |
| * |
| * @param[in] option - one of ec_target_reset_option enums |
| */ |
| void resetTarget(uint8_t option); |
| |
| /** @brief Static helper function for RAII target release |
| */ |
| static void releaseTarget(FirmwareSpiUpdater*&& updater) noexcept; |
| |
| /** @brief Check whether SPS passthrough is enabled |
| * |
| * If SPS passthrough is disabled, then we can send SPI commands without |
| * having to reset the target. |
| * |
| * @return true if passthrough is enabled, false if it's disabled |
| */ |
| bool getSpsPassthrough(); |
| |
| /** @brief Set SPS passthrough mode |
| * |
| * If SPS passthrough is disabled, then we can send SPI commands without |
| * having to reset the target. |
| * |
| * @param[in] enable - The desired SPS passthough mode. |
| * @return indicates if the passthrough mode is successfully set. |
| */ |
| bool setSpsPassthrough(bool enable); |
| |
| /** @brief SPI requires erase enough space before write |
| * |
| * @param[in] firmwareSize - Hoth firmware image length. |
| * @param[in] address - address to erase |
| */ |
| void erase(size_t firmwareSize, uint32_t address); |
| |
| /** @brief Writes firmwara data |
| * |
| * @param[in] firmwareData - Hoth firmware image. |
| * @param[in] address - address to write |
| */ |
| void writeData(const std::vector<uint8_t>& firmwareData, uint32_t address); |
| |
| /** @brief Reads back data and verifies it matches input firmware |
| * |
| * @param[in] firmwareData - Hoth firmware image. |
| * @param[in] address - address to read |
| */ |
| void verifyData(const std::vector<uint8_t>& firmwareData, uint32_t address); |
| |
| /** @brief Appends 3 or 4 byte address to `array` depending on `addressSize` |
| * |
| * @param[in] array - byte array |
| * @param[in] address - address |
| */ |
| void appendAddress(std::vector<uint8_t> &array, uint32_t address) const; |
| |
| /** @brief The actual firmware update operation. |
| * |
| * @param[in] firmwareData - data |
| * @param[in] address - address |
| */ |
| void doUpdate(const std::vector<uint8_t>& data, uint32_t address); |
| |
| /** @brief Connection to Hoth for sending and receiving host commands */ |
| HostCommand* hostCmd; |
| |
| /** @brief SPI operation address size, it can be 3 or 4 bytes */ |
| uint8_t addressSize; |
| |
| /** @brief Whether set target to reset before SPI */ |
| ResetMode targetReset; |
| |
| /** @brief Whether to ignore address mode change failure */ |
| bool ignoreAddressMode; |
| }; |
| } // namespace internal |
| } // namespace hoth |
| } // namespace google |