1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <stddef.h> 8 9#include <ddk/metadata/bad-block.h> 10 11#include <fbl/array.h> 12#include <fbl/ref_ptr.h> 13#include <lib/zx/vmar.h> 14#include <lib/zx/vmo.h> 15#include <zircon/thread_annotations.h> 16#include <zircon/types.h> 17 18#include "bad-block.h" 19 20namespace nand { 21 22// Bad block implementation for NAND using Amlogic u-boot style bad block tables. 23class AmlBadBlock : public BadBlock { 24public: 25 struct OobMetadata { 26 // Identifer value. 27 uint32_t magic; 28 // Number of times the block has been programmed and erased. 29 int16_t program_erase_cycles; 30 // Iteration of the bad block table. Each time a new one is programmed, this 31 // should be incremented. Used to identify the newest copy. 32 uint16_t generation; 33 }; 34 35 static zx_status_t Create(Config config, fbl::RefPtr<BadBlock>* out); 36 37 zx_status_t GetBadBlockList(uint32_t first_block, uint32_t last_block, 38 fbl::Array<uint32_t>* bad_blocks) override; 39 zx_status_t MarkBlockBad(uint32_t block) override; 40 41private: 42 friend class fbl::RefPtr<AmlBadBlock>; 43 friend class fbl::internal::MakeRefCountedHelper<AmlBadBlock>; 44 45 typedef uint8_t BlockStatus; 46 constexpr static BlockStatus kNandBlockGood = 0; 47 constexpr static BlockStatus kNandBlockBad = 1; 48 constexpr static BlockStatus kNandBlockFactoryBad = 2; 49 50 constexpr static size_t kBlockListMax = 8; 51 52 struct BlockListEntry { 53 uint32_t block; 54 int16_t program_erase_cycles; 55 bool valid; 56 }; 57 58 AmlBadBlock(zx::vmo data_vmo, zx::vmo oob_vmo, fbl::Array<uint8_t> nand_op, 59 Config config, nand_info_t nand_info, BlockStatus* table, uint32_t table_len, 60 OobMetadata* oob) 61 : BadBlock(fbl::move(data_vmo), fbl::move(oob_vmo), fbl::move(nand_op)), 62 config_(config.bad_block_config), nand_proto_(config.nand_proto), nand_(&nand_proto_), 63 nand_info_(nand_info), block_entry_(nullptr), page_(0), 64 generation_(0), table_valid_(false), oob_(oob), bad_block_table_(table), 65 bad_block_table_len_(table_len) {} 66 67 ~AmlBadBlock() override { 68 zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(oob_), sizeof(OobMetadata)); 69 zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(bad_block_table_), 70 bad_block_table_len_); 71 } 72 73 // Synchronously erase a block. 74 zx_status_t EraseBlock(uint32_t block) TA_REQ(lock_); 75 76 // Synchronously write |num_pages| into NAND. 77 zx_status_t WritePages(uint32_t nand_page, uint32_t num_pages) TA_REQ(lock_); 78 79 // Synchronously read |num_pages| from NAND. 80 zx_status_t ReadPages(uint32_t nand_page, uint32_t num_pages) TA_REQ(lock_); 81 82 // Looks for a valid block to write BBT to. 83 zx_status_t GetNewBlock(void) TA_REQ(lock_); 84 85 // Writes in memory copy of BBT to the device. 86 zx_status_t WriteBadBlockTable(bool use_new_block) TA_REQ(lock_); 87 88 // Finds BBT and reads it into memory from NAND. 89 zx_status_t FindBadBlockTable(void) TA_REQ(lock_); 90 91 // Top level config. 92 const bad_block_config_t config_; 93 // Parent nand protocol implementation. 94 nand_protocol_t nand_proto_; 95 ddk::NandProtocolProxy nand_; 96 const nand_info_t nand_info_; 97 // Information about blocks which store BBT entries. 98 BlockListEntry block_list_[kBlockListMax]; 99 // Block with most recent valid BBT entry. 100 BlockListEntry* block_entry_; 101 // The first page for the last valid BBT entry in above block. 102 uint32_t page_; 103 // Generation ID of newest BBT entry. 104 uint16_t generation_; 105 // Whether the table is valid. 106 bool table_valid_; 107 // OOB metadata appended to end of table. Backed by oob_vmo. 108 OobMetadata* oob_; 109 // Copy of latest BBT. Each byte 1:1 maps to a block. Backed by data_vmo. 110 BlockStatus* bad_block_table_; 111 // Size of bad block table, rounded up to |nand_info_.page_size| multiple. 112 uint32_t bad_block_table_len_; 113}; 114} // namespace nand 115