| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <ddk/binding.h> |
| #include <ddk/debug.h> |
| #include <ddk/io-buffer.h> |
| #include <ddk/mmio-buffer.h> |
| #include <ddk/platform-defs.h> |
| #include <lib/device-protocol/platform-device.h> |
| #include <ddk/protocol/platform/device.h> |
| #include <ddktl/device.h> |
| #include <lib/device-protocol/pdev.h> |
| #include <ddktl/protocol/rawnand.h> |
| #include <fbl/unique_ptr.h> |
| #include <hw/reg.h> |
| #include <lib/mmio/mmio.h> |
| #include <lib/sync/completion.h> |
| #include <memory> |
| #include <soc/aml-common/aml-rawnand.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <utility> |
| #include <zircon/threads.h> |
| #include <zircon/types.h> |
| |
| #include "onfi.h" |
| |
| namespace amlrawnand { |
| |
| struct AmlController { |
| int ecc_strength; |
| int user_mode; |
| int rand_mode; |
| int options; |
| int bch_mode; |
| }; |
| |
| class AmlRawNand; |
| using DeviceType = ddk::Device<AmlRawNand, ddk::Unbindable>; |
| |
| class AmlRawNand : public DeviceType, public ddk::RawNandProtocol<AmlRawNand, ddk::base_protocol> { |
| public: |
| explicit AmlRawNand(zx_device_t* parent, ddk::MmioBuffer mmio_nandreg, |
| ddk::MmioBuffer mmio_clockreg, zx::bti bti, zx::interrupt irq) |
| : DeviceType(parent), |
| mmio_nandreg_(std::move(mmio_nandreg)), |
| mmio_clockreg_(std::move(mmio_clockreg)), |
| bti_(std::move(bti)), |
| irq_(std::move(irq)) {} |
| |
| static zx_status_t Create(void* ctx, zx_device_t* parent); |
| |
| ~AmlRawNand() = default; |
| |
| void DdkRelease(); |
| void DdkUnbind(); |
| |
| zx_status_t Bind(); |
| zx_status_t Init(); |
| zx_status_t RawNandReadPageHwecc(uint32_t nand_page, void* data, size_t data_size, |
| size_t* data_actual, void* oob, size_t oob_size, |
| size_t* oob_actual, uint32_t* ecc_correct); |
| zx_status_t RawNandWritePageHwecc(const void* data, size_t data_size, const void* oob, |
| size_t oob_size, uint32_t nand_page); |
| zx_status_t RawNandEraseBlock(uint32_t nand_page); |
| zx_status_t RawNandGetNandInfo(fuchsia_hardware_nand_Info* nand_info); |
| |
| private: |
| Onfi onfi_; |
| void *info_buf_, *data_buf_; |
| zx_paddr_t info_buf_paddr_, data_buf_paddr_; |
| |
| ddk::MmioBuffer mmio_nandreg_; |
| ddk::MmioBuffer mmio_clockreg_; |
| |
| zx::bti bti_; |
| zx::interrupt irq_; |
| |
| thrd_t irq_thread_; |
| ddk::IoBuffer data_buffer_; |
| ddk::IoBuffer info_buffer_; |
| sync_completion_t req_completion_; |
| |
| AmlController controller_params_; |
| uint32_t chip_select_; |
| int chip_delay_; |
| uint32_t writesize_; /* NAND pagesize - bytes */ |
| uint32_t erasesize_; /* size of erase block - bytes */ |
| uint32_t erasesize_pages_; |
| uint32_t oobsize_; /* oob bytes per NAND page - bytes */ |
| uint32_t bus_width_; /* 16bit or 8bit ? */ |
| uint64_t chipsize_; /* MiB */ |
| uint32_t page_shift_; /* NAND page shift */ |
| struct { |
| uint64_t ecc_corrected; |
| uint64_t failed; |
| } stats; |
| |
| void AmlCmdCtrl(int32_t cmd, uint32_t ctrl); |
| // Reads status byte. |
| uint8_t AmlReadByte(); |
| void NandctrlSetCfg(uint32_t val); |
| void NandctrlSetTimingAsync(int bus_tim, int bus_cyc); |
| void NandctrlSendCmd(uint32_t cmd); |
| void AmlCmdIdle(uint32_t time); |
| zx_status_t AmlWaitCmdFinish(unsigned int timeout_ms); |
| void AmlCmdSeed(uint32_t seed); |
| void AmlCmdN2M(uint32_t ecc_pages, uint32_t ecc_pagesize); |
| void AmlCmdM2N(uint32_t ecc_pages, uint32_t ecc_pagesize); |
| void AmlCmdM2NPage0(); |
| void AmlCmdN2MPage0(); |
| zx_status_t AmlWaitDmaFinish(); |
| // Returns the AmlInfoFormat struct corresponding to the i'th |
| // ECC page. THIS ASSUMES user_mode == 2 (2 OOB bytes per ECC page). |
| void* AmlInfoPtr(int i); |
| zx_status_t AmlGetOOBByte(uint8_t* oob_buf); |
| zx_status_t AmlSetOOBByte(const uint8_t* oob_buf, uint32_t ecc_pages); |
| // Returns the maximum bitflips corrected on this NAND page |
| // (the maximum bitflips across all of the ECC pages in this page). |
| zx_status_t AmlGetECCCorrections(int ecc_pages, uint32_t nand_page, uint32_t* ecc_corrected); |
| zx_status_t AmlCheckECCPages(int ecc_pages); |
| zx_status_t AmlQueueRB(); |
| void AmlSetClockRate(uint32_t clk_freq); |
| void AmlClockInit(); |
| void AmlAdjustTimings(uint32_t tRC_min, uint32_t tREA_max, uint32_t RHOH_min); |
| zx_status_t AmlGetFlashType(); |
| int IrqThread(); |
| void AmlSetEncryption(); |
| zx_status_t AmlReadPage0(void* data, size_t data_size, void* oob, size_t oob_size, |
| uint32_t nand_page, uint32_t* ecc_correct, int retries); |
| // Reads one of the page0 pages, and use the result to init |
| // ECC algorithm and rand-mode. |
| zx_status_t AmlNandInitFromPage0(); |
| zx_status_t AmlRawNandAllocBufs(); |
| zx_status_t AmlNandInit(); |
| void CleanUpIrq(); |
| }; |
| |
| } // namespace amlrawnand |