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