1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2021 Aidan MacDonald
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __NAND_X1000_H__
#define __NAND_X1000_H__
/* NOTE: this is a very minimal API designed only to support a bootloader.
* Not suitable for general data storage. It doesn't have proper support for
* partial page writes, access to spare area, etc, which are all necessary
* for an effective flash translation layer.
*
* There's no ECC support. This can be added if necessary, but it's unlikely
* the boot area on any X1000 device uses software ECC as Ingenic's SPL simply
* doesn't have much room for more code (theirs programmed to work on multiple
* hardware configurations, so it's bigger than ours).
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "nand-x1000-err.h"
/* Chip supports quad I/O for page read/write */
#define NANDCHIP_FLAG_QUAD 0x01
/* Set/clear the BRWD bit when enabling/disabling write protection */
#define NANDCHIP_FLAG_USE_BRWD 0x02
typedef struct nand_chip_data {
/* Chip manufacturer / device ID */
uint8_t mf_id;
uint8_t dev_id;
/* Width of row/column addresses in bytes */
uint8_t rowaddr_width;
uint8_t coladdr_width;
/* SFC dev conf and clock frequency to use for this device */
uint32_t dev_conf;
uint32_t clock_freq;
/* Page size in bytes = 1 << log2_page_size */
uint32_t log2_page_size;
/* Block size in number of pages = 1 << log2_block_size */
uint32_t log2_block_size;
/* Chip flags */
uint32_t flags;
} nand_chip_data;
/* Open or close the NAND driver. The NAND driver takes control of the SFC,
* so that driver must be in the closed state before opening the NAND driver.
*/
extern int nand_open(void);
extern void nand_close(void);
/* Identify the NAND chip. This must be done after opening the driver and
* prior to any data access, in order to set the chip parameters. */
extern int nand_identify(int* mf_id, int* dev_id);
/* Return the chip data for the identified NAND chip.
* Returns NULL if the chip is not identified. */
const nand_chip_data* nand_get_chip_data(void);
/* Controls the chip's write protect features. The driver also keeps track of
* this flag and refuses to perform write or erase operations unless you have
* enabled writes. Writes should be disabled again when you finish writing. */
extern int nand_enable_writes(bool en);
/* Reading and writing operates on whole pages at a time. If the address or
* size is not aligned to a multiple of the page size, no data will be read
* or written and an error code is returned. */
extern int nand_read(uint32_t addr, uint32_t size, uint8_t* buf);
extern int nand_write(uint32_t addr, uint32_t size, const uint8_t* buf);
/* Ereas eoperates on whole blocks. Like the page read/write operations,
* the address and size must be aligned to a multiple of the block size.
* If not, no blocks are erased and an error code is returned. */
extern int nand_erase(uint32_t addr, uint32_t size);
#endif /* __NAND_X1000_H__ */
|