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#include "aml.h"
6
7#include <stdio.h>
8#include <string.h>
9
10namespace {
11
12// Simplified Amlogic data structures.
13struct ExtInfo {
14    uint32_t read_info;
15    uint32_t new_type;
16    uint32_t pages_per_block;
17    uint32_t xlc;               // slc=1, mlc=2, tlc=3.
18    uint32_t ce_mask;
19    uint32_t boot_num;
20    uint32_t each_boot_pages;
21    uint32_t bbt_occupy_pages;
22    uint32_t bbt_start_block;
23};
24
25struct Page0 {
26    uint32_t config;
27    uint16_t id;
28    uint16_t max;
29    uint8_t page_list[16];
30    uint16_t retry_usr[32];
31    ExtInfo ext_info;
32};
33
34// The number of pages on a single table.
35uint32_t g_bbt_size = 0;
36
37// Returns the number of valid bad block tables found.
38int GetNumTables(const char* oob, const nand_info_t& info) {
39    int found = 0;
40    for (uint32_t page = 0; page < info.pages_per_block; page++) {
41        if (memcmp(oob + page * info.oob_size, "nbbt", 4) != 0) {
42            break;
43        }
44        found++;
45    }
46    return found / g_bbt_size;
47}
48
49}  // namespace
50
51void DumpPage0(const void* data) {
52    const Page0* page0 = reinterpret_cast<const Page0*>(data);
53
54    printf("Config: 0x%x\n", page0->config);
55    printf("ECC step: %u\n", page0->config & 0x3f);
56    printf("Page size (encoded): %u\n", (page0->config >> 6) & 0x7f);
57    printf("Pages per block: %u\n", page0->ext_info.pages_per_block);
58    printf("Boot type: %u\n", page0->ext_info.boot_num);
59    printf("Boot pages: %u\n", page0->ext_info.each_boot_pages);
60    printf("BBT size (pages): %u\n", page0->ext_info.bbt_occupy_pages);
61    printf("BBT block start: %u\n", page0->ext_info.bbt_start_block);
62}
63
64void GetBbtLocation(const void* data, uint32_t* first_block, uint32_t* num_blocks) {
65    const Page0* page0 = reinterpret_cast<const Page0*>(data);
66    g_bbt_size = page0->ext_info.bbt_occupy_pages;
67    *first_block = page0->ext_info.bbt_start_block;
68    *num_blocks = 4;
69}
70
71int DumpBbt(const void* data, const void* oob, const nand_info_t& info) {
72    if (g_bbt_size * info.page_size < info.num_blocks) {
73        printf("BBT too small\n");
74        return 0;
75    }
76
77    const char* table = reinterpret_cast<const char*>(data);
78    const char* oob_data = reinterpret_cast<const char*>(oob);
79    int num_tables = GetNumTables(oob_data, info);
80
81    for (int cur_table = 0; cur_table < num_tables; cur_table++) {
82        printf("BBT Table %d\n", cur_table);
83        for (uint32_t block = 0; block < info.num_blocks; block++) {
84            if (table[block]) {
85                printf("Block %d marked bad\n", block);
86            }
87        }
88        oob_data += info.oob_size * g_bbt_size;
89        table += info.page_size * g_bbt_size;
90    }
91    return num_tables;
92}
93