/* * This file is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This file 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, see . * * Code by * Andy Piper * Siddharth Bharat Purohit, Cubepilot Pty. Ltd. */ /* Implements Common Flash Interface Driver based on Open Standard Published by JEDEC */ #include "AP_FlashIface_Abstract.h" class AP_FlashIface_JEDEC : public AP_FlashIface { public: bool init() override; /** * @details Read data from flash chip. * * @param[in] offset address offset from where to start the read * @param[out] data data to be read from the device * @param[in] size size of the data to be read * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool read(uint32_t offset, uint8_t *data, uint32_t size) override; /** * @details Gets number bytes that can be written in one go (page size). * * @return page size in bytes. * */ uint32_t get_page_size() const override { return _desc.page_size; } /** * @details Gets number pages, each page can written in one go * * @return Number of pages. * */ uint32_t get_page_count() const override { return _desc.page_count; } /** * @details Sends command to start programming a page of the chip. * * @param[in] page Page number to be written to * @param[in] data data to be written * @param[out] delay_us Time to wait until next is_device_busy call * @param[out] timeout_us Time after which the erase should be timedout, * should be reset at every call. * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool start_program_page(uint32_t page, const uint8_t *data, uint32_t &delay_us, uint32_t &timeout_us) override; /** * @details Tries to program as much as possible starting from the offset * until size. User needs to call this as many times as needed * taking already programmed bytes into account. * * @param[in] offset address offset for program * @param[in] data data to be programmed * @param[in] size size desired to be programmed * @param[out] programming number of bytes programming, taking care of the limits * @param[out] delay_us Time to wait until program typically finishes * @param[out] timeout_us Time by which current program should have timedout. * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool start_program_offset(uint32_t offset, const uint8_t* data, uint32_t size, uint32_t &programming, uint32_t &delay_us, uint32_t &timeout_us) override; // Erase Methods /** * @details Sends command to erase the entire chip. * * @param[out] delay_ms Time to wait until next is_device_busy call * @param[out] timeout_ms Time by which the erase should have timedout * * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool start_mass_erase(uint32_t &delay_ms, uint32_t &timeout_ms) override; /** * @details Gets number bytes that can erased in one go(sector size) * * @return Sector size in bytes. * */ uint32_t get_sector_size() const override { return _desc.sector_size; } /** * @details Gets number of sectors, each sector can be erased in one go * * @return Number of sectors. * */ uint32_t get_sector_count() const override { return _desc.sector_count; } /** * @details minimum number of bytes that can be erased * * @return Number of bytes. * */ uint32_t min_erase_size() const override { return _desc.min_erase_size; } /** * @details Sends command to erase a sector of the chip. * * @param[in] sector Sector number to be erased * @param[out] delay_ms Time to wait until next is_device_busy call * @param[out] timeout_ms Time by which the erase should have timedout * * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool start_sector_erase(uint32_t sector, uint32_t &delay_ms, uint32_t &timeout_ms) override; /** * @details Tries to erase as much as possible starting from the offset * until size. User needs to call this as many times as needed * taking already erased bytes into account, until desired erase * has taken place * * @param[in] offset address offset for erase * @param[in] size size desired to be erased * @param[out] erasing number of bytes erasing * @param[out] delay_ms Time to wait until next is_device_busy call * @param[out] timeout_ms Time by which the erase should have timedout * * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool start_erase_offset(uint32_t offset, uint32_t size, uint32_t &erasing, uint32_t &delay_ms, uint32_t &timeout_ms) override; /** * @details Check if selected sector is erased. * * @param[in] sector sector for which to check erase * @return The operation status. * @retval false if the operation failed. * @retval true if the operation succeeded. * */ bool verify_sector_erase(uint32_t sector) override; /** * @details Check if the device is busy. * * @return device busy with last op. * * @retval false if the device is ready. * @retval true if the device is busy. * */ bool is_device_busy() override; /** * @details Starts execution in place mode * * @return if successfully entered XIP mode. * * @retval false the device failed to enter XIP mode. * @retval true the device has entered XIP mode. * */ bool start_xip_mode(void** addr) override; bool stop_xip_mode() override; protected: void reset_device(); // Does initial configuration to bring up and setup chip bool detect_device(); // Configures device to normal working state, currently 4-4-4 QSPI bool configure_device(); // Enables commands that modify flash data or settings bool write_enable(); // Disables commands that modify flash data or settings bool write_disable(); // wait for the chip to be ready for the next instruction void wait_ready(); // Read modify write register bool modify_reg(uint8_t read_ins, uint8_t write_ins, uint8_t mask, uint8_t va_list); // reads a register value of chip using instruction bool read_reg(uint8_t read_ins, uint8_t &read_val); // sends instruction to write a register value in the chip bool write_reg(uint8_t read_ins, uint8_t write_val); // Sends QSPI command without data bool send_cmd(uint8_t ins); // Is device in quad spi mode bool _quad_spi_mode; AP_HAL::OwnPtr _dev; enum xip_entry_methods { XIP_ENTRY_METHOD_1, XIP_ENTRY_METHOD_2, XIP_ENTRY_METHOD_3 }; // Device description extracted from SFDP struct device_desc { uint16_t param_rev; //parameter revision uint8_t param_table_len; // size of parameter table uint32_t param_table_pointer; // location of parameter table uint32_t flash_size; // size of flash in bytes uint32_t page_size; // maximum size that can be written in one transaction uint32_t page_count; // number of pages each of page size uint32_t sector_size; // maximum number of bytes that can be erased outside of mass erase uint32_t sector_count; // number of sectors uint32_t min_erase_size; // minimum amount of bytes that can be erased struct { uint8_t ins; // instruction for the erase uint32_t size; // number of bytes that will be erased uint32_t delay_ms; // typical time this command will finish uint32_t timeout_ms; // time after which the erase cmd caller should time } erase_type[4]; uint32_t mass_erase_delay_ms; // typical time taken while mass erase uint32_t mass_erase_timeout_ms; // time after which mass erase cmd caller should timeout uint8_t write_enable_ins; // instruction to allow enabling modification of register and data uint32_t page_prog_delay_us; // time taken to write a page worth of data to flash uint32_t page_prog_timeout_us; // time after which the page program caller should timeout uint8_t fast_read_ins; // instruction to do fast read, i.e. read any number of bytes in single trx uint8_t fast_read_dummy_cycles; // number of dummy cycles after which the chip will respond with data uint8_t quad_mode_ins; // instruction to enter 4-4-4 mode uint8_t quad_mode_enable; bool quad_mode_rmw_seq; // use Read modify write sequence to enter 4-4-4 mode supported or not uint8_t status_read_ins; // read status of the chip, gets us if busy writing/erasing bool legacy_status_polling; // check if legacy status polling supported or not bool is_xip_supported; // is execution in place or 0-4-4 mode supported uint8_t fast_read_mode_clocks; xip_entry_methods entry_method; } _desc; uint8_t _dev_list_idx; bool initialised; bool write_enable_called; };