summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/lpc32xx/include/nand-mlc.h
blob: c5849103d0c73c45c8f6a59c3b959ce007a17088 (plain) (blame)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/**
 * @file
 *
 * @ingroup lpc32xx_nand_mlc
 *
 * @brief NAND MLC controller API.
 */

/*
 * Copyright (c) 2010
 * embedded brains GmbH
 * Obere Lagerstr. 30
 * D-82178 Puchheim
 * Germany
 * <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 */

#ifndef LIBBSP_ARM_LPC32XX_NAND_MLC_H
#define LIBBSP_ARM_LPC32XX_NAND_MLC_H

#include <rtems.h>

#include <bsp/utility.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @defgroup lpc32xx_nand_mlc NAND MLC Controller
 *
 * @ingroup lpc32xx
 *
 * @brief NAND MLC Controller.
 *
 * Timing constraints:
 *
 * -# (WR_LOW + 1) / HCLK >= tWP
 * -# (WR_HIGH - WR_LOW) / HCLK >= tWH
 * -# (WR_LOW + 1) / HCLK + (WR_HIGH - WR_LOW) / HCLK >= tWC
 * -# (RD_LOW + 1) / HCLK >= tRP
 * -# (RD_LOW + 1) / HCLK >= tREA + tSU
 * -# (RD_HIGH - RD_LOW) / HCLK >= tREH
 * -# (RD_LOW + 1) / HCLK + (RD_HIGH - RD_LOW) / HCLK >= tRC
 * -# (RD_HIGH - RD_LOW) / HCLK + NAND_TA / HCLK >= tRHZ
 * -# BUSY_DELAY / HCLK >= max(tWB, tRB)
 * -# TCEA_DELAY / HCLK >= tCEA - tREA
 *
 * Known flash layouts (Format: SP = small pages, LP = large pages / address
 * cycles / pages per block):
 *
 * -# SP/3/32
 * -# SP/4/32
 * -# LP/4/64
 * -# LP/5/64
 * -# LP/5/128
 *
 * @{
 */

/**
 * @name MLC NAND Flash Dimensions
 *
 * @{
 */

#define MLC_SMALL_PAGE_SIZE 528
#define MLC_SMALL_DATA_SIZE 512
#define MLC_SMALL_SPARE_SIZE 16
#define MLC_SMALL_DATA_WORD_COUNT (MLC_SMALL_DATA_SIZE / 4)
#define MLC_SMALL_SPARE_WORD_COUNT (MLC_SMALL_SPARE_SIZE / 4)
#define MLC_SMALL_PAGES_PER_LARGE_PAGE 4
#define MLC_LARGE_PAGE_SIZE \
  (MLC_SMALL_PAGES_PER_LARGE_PAGE * MLC_SMALL_PAGE_SIZE)
#define MLC_LARGE_DATA_SIZE \
  (MLC_SMALL_PAGES_PER_LARGE_PAGE * MLC_SMALL_DATA_SIZE)
#define MLC_LARGE_SPARE_SIZE \
  (MLC_SMALL_PAGES_PER_LARGE_PAGE * MLC_SMALL_SPARE_SIZE)
#define MLC_LARGE_DATA_WORD_COUNT (MLC_LARGE_DATA_SIZE / 4)
#define MLC_LARGE_SPARE_WORD_COUNT (MLC_LARGE_SPARE_SIZE / 4)

/** @} */

/**
 * @name NAND Flash Clock Control Register (FLASHCLK_CTRL)
 *
 * @{
 */

#define FLASHCLK_IRQ_MLC BIT32(5)
#define FLASHCLK_MLC_DMA_RNB BIT32(4)
#define FLASHCLK_MLC_DMA_INT BIT32(3)
#define FLASHCLK_SELECT_SLC BIT32(2)
#define FLASHCLK_MLC_CLK_ENABLE BIT32(1)
#define FLASHCLK_SLC_CLK_ENABLE BIT32(0)

/** @} */

/**
 * @name MLC NAND Timing Register (MLC_TIME_REG)
 *
 * @{
 */

#define MLC_TIME_WR_LOW(val) FIELD32(val, 0, 3)
#define MLC_TIME_WR_HIGH(val) FIELD32(val, 4, 7)
#define MLC_TIME_RD_LOW(val) FIELD32(val, 8, 11)
#define MLC_TIME_RD_HIGH(val) FIELD32(val, 12, 15)
#define MLC_TIME_NAND_TA(val) FIELD32(val, 16, 18)
#define MLC_TIME_BUSY_DELAY(val) FIELD32(val, 19, 23)
#define MLC_TIME_TCEA_DELAY(val) FIELD32(val, 24, 25)

/** @} */

/**
 * @name MLC NAND Lock Protection Register (MLC_LOCK_PR)
 *
 * @{
 */

#define MLC_UNLOCK_PROT 0xa25e

/** @} */

/**
 * @name MLC NAND Status Register (MLC_ISR)
 *
 * @{
 */

#define MLC_ISR_DECODER_FAILURE BIT32(6)
#define MLC_ISR_ERRORS_DETECTED BIT32(3)
#define MLC_ISR_ECC_READY BIT32(2)
#define MLC_ISR_CONTROLLER_READY BIT32(1)
#define MLC_ISR_NAND_READY BIT32(0)

/** @} */

/**
 * @name MLC NAND Controller Configuration Register (MLC_ICR)
 *
 * @{
 */

#define MLC_ICR_SOFT_WRITE_PROT BIT32(3)
#define MLC_ICR_LARGE_PAGES BIT32(2)
#define MLC_ICR_ADDR_WORD_COUNT_4_5 BIT32(1)
#define MLC_ICR_IO_BUS_16 BIT32(0)

/** @} */

/**
 * @name MLC NAND Auto Encode Register (MLC_ECC_AUTO_ENC)
 *
 * @{
 */

#define MLC_ECC_AUTO_ENC_PROGRAM BIT32(8)

/** @} */

#define MLC_BAD_BLOCK_MASK ((uint32_t) 0xff00)

/**
 * @name NAND Status Register
 *
 * @{
 */

#define NAND_STATUS_ERROR (1U << 0)
#define NAND_STATUS_READY (1U << 6)
#define NAND_STATUS_NOT_PROTECTED (1U << 7)

/** @} */

/**
 * @brief MLC NAND controller configuration.
 */
typedef struct {
  /**
   * @brief Selects small pages (512 Bytes user data and 16 Bytes spare data)
   * or large pages (2048 Bytes user data and 64 Bytes spare data).
   */
  bool small_pages;

  /**
   * @brief Selects 3/4 address cycles for small pages/large pages or 4/5
   * address cycles.
   */
  bool many_address_cycles;

  /**
   * @brief Selects 64 or 128 pages per block in case of large pages.
   */
  bool normal_blocks;

  uint32_t block_count;

  /**
   * @brief Value for the MLC NAND Timing Register (MLC_TIME_REG).
   */
  uint32_t time;
} lpc32xx_mlc_config;

/**
 * @brief Initializes the MLC NAND controller according to @a cfg.
 */
void lpc32xx_mlc_init(const lpc32xx_mlc_config *cfg);

uint32_t lpc32xx_mlc_page_size(void);

uint32_t lpc32xx_mlc_pages_per_block(void);

uint32_t lpc32xx_mlc_block_count(void);

void lpc32xx_mlc_write_protection(
  uint32_t page_index_low,
  uint32_t page_index_high
);

void lpc32xx_mlc_read_id(uint8_t *id, size_t n);

/**
 * @brief Reads the page with index @a page_index.
 *
 * 32-bit reads will be performed.
 *
 * Bytes 7 to 15 of the spare area will contain the ECC.
 *
 * @retval RTEMS_SUCCESSFUL Successful operation.
 * @retval RTEMS_INVALID_ID Invalid @a page_index value.
 * @retval RTEMS_IO_ERROR Uncorrectable bit error.
 */
rtems_status_code lpc32xx_mlc_read_page(
  uint32_t page_index,
  uint32_t *data,
  uint32_t *spare
);

/**
 * @brief Erases the block with index @a block_index.
 *
 * @retval RTEMS_SUCCESSFUL Successful operation.
 * @retval RTEMS_INVALID_ID Invalid @a block_index value.
 * @retval RTEMS_IO_ERROR Erase error.
 */
rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index);

/**
 * @brief Writes the page with index @a page_index.
 *
 * 32-bit writes will be performed.
 *
 * Bytes 7 to 15 of the spare area will be used for the automatically generated
 * ECC.
 *
 * @retval RTEMS_SUCCESSFUL Successful operation.
 * @retval RTEMS_INVALID_ID Invalid @a page_index value.
 * @retval RTEMS_IO_ERROR Write error.
 */
rtems_status_code lpc32xx_mlc_write_page_with_ecc(
  uint32_t page_index,
  const uint32_t *data,
  const uint32_t *spare
);

/**
 * @brief Writes @a src_size Bytes from @a src to the flash area specified by
 * @a block_begin and @a block_end.
 *
 * The @a page_buffer will be used as an intermediate buffer.
 *
 * @retval RTEMS_SUCCESSFUL Successful operation.
 * @retval RTEMS_INVALID_ID Invalid @a block_begin or @a block_end value.
 * @retval RTEMS_IO_ERROR To many bad blocks or source area to big.
 */
rtems_status_code lpc32xx_mlc_write_blocks(
  uint32_t block_begin,
  uint32_t block_end,
  const void *src,
  size_t src_size,
  uint32_t page_buffer [MLC_LARGE_DATA_WORD_COUNT]
);

/**
 * @brief Read blocks process function type.
 *
 * @see lpc32xx_mlc_read_blocks().
 *
 * @retval false Continue processing.
 * @retval true Stop processing.
 */
typedef bool (*lpc32xx_mlc_read_process)(
  void *process_arg,
  uint32_t page_index,
  uint32_t page_size,
  uint32_t page_data [MLC_LARGE_DATA_WORD_COUNT],
  uint32_t page_spare [MLC_LARGE_SPARE_WORD_COUNT]
);

/**
 * @brief Reads the pages of block @a block_begin up to and excluding
 * @a block_end.
 *
 * For each page @a process will be called with the @a process_arg parameter,
 * the page_index, the page data and the page spare.
 *
 * The @a page_buffer_0 and @a page_buffer_1 will be used as
 * intermediate buffers.
 */
rtems_status_code lpc32xx_mlc_read_blocks(
  uint32_t block_begin,
  uint32_t block_end,
  lpc32xx_mlc_read_process process,
  void *process_arg,
  uint32_t page_buffer_0 [MLC_LARGE_DATA_WORD_COUNT],
  uint32_t page_buffer_1 [MLC_LARGE_DATA_WORD_COUNT]
);

static inline bool lpc32xx_mlc_is_bad_page(const uint32_t *spare)
{
  return (spare [1] & MLC_BAD_BLOCK_MASK) != MLC_BAD_BLOCK_MASK;
}

/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* LIBBSP_ARM_LPC32XX_NAND_MLC_H */