source: rtems/c/src/lib/libbsp/arm/lpc32xx/misc/nand-mlc.c @ f437107

4.115
Last change on this file since f437107 was f437107, checked in by Sebastian Huber <sebastian.huber@…>, on 03/28/11 at 09:00:01

2011-03-29 Sebastian Huber <sebastian.huber@…>

  • configure.ac, include/bspopts.h.in: New BSP option LPC32XX_SCRATCH_AREA_SIZE. Disable BSP option LPC32XX_DISABLE_READ_ONLY_PROTECTION for all BSPs.
  • include/boot.h: Removed application specific defines.
  • include/nand-mlc.h, misc/nand-mlc.c: Changed configuration layout.
  • include/mmu.h, misc/mmu.c: Documentation. Bugfix.
  • include/bsp.h, startup/bspstarthooks.c, misc/restart.c, startup/linkcmds.lpc32xx_mzx, startup/linkcmds.lpc32xx_mzx_stage_1, startup/linkcmds.lpc32xx_mzx_stage_2, startup/linkcmds.lpc32xx_phycore: Support for scratch area. Moved code into macros for reusability.
  • Property mode set to 100644
File size: 6.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup lpc32xx_nand_mlc
5 *
6 * @brief NAND MLC controller implementation.
7 */
8
9/*
10 * Copyright (c) 2010
11 * embedded brains GmbH
12 * Obere Lagerstr. 30
13 * D-82178 Puchheim
14 * Germany
15 * <rtems@embedded-brains.de>
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.com/license/LICENSE.
20 */
21
22#include <bsp/lpc32xx.h>
23#include <bsp/nand-mlc.h>
24
25static volatile lpc32xx_nand_mlc *const mlc = &lpc32xx.nand_mlc;
26
27static uint32_t mlc_flags;
28
29static uint32_t mlc_block_count;
30
31static uint32_t mlc_page_count;
32
33static bool mlc_small_pages(void)
34{
35  return (mlc_flags & MLC_SMALL_PAGES) != 0;
36}
37
38static bool mlc_many_address_cycles(void)
39{
40  return (mlc_flags & MLC_MANY_ADDRESS_CYCLES) != 0;
41}
42
43static bool mlc_normal_blocks(void)
44{
45  return (mlc_flags & MLC_NORMAL_BLOCKS) != 0;
46}
47
48uint32_t lpc32xx_mlc_page_size(void)
49{
50  if (mlc_small_pages()) {
51    return 512;
52  } else {
53    return 2048;
54  }
55}
56
57uint32_t lpc32xx_mlc_pages_per_block(void)
58{
59  if (mlc_small_pages()) {
60    return 32;
61  } else {
62    if (mlc_normal_blocks()) {
63      return 64;
64    } else {
65      return 128;
66    }
67  }
68}
69
70uint32_t lpc32xx_mlc_block_count(void)
71{
72  return mlc_block_count;
73}
74
75static void mlc_unlock(void)
76{
77  mlc->lock_pr = MLC_UNLOCK_PROT;
78}
79
80static void mlc_wait(uint32_t flags)
81{
82  while ((mlc->isr & flags) != flags) {
83    /* Wait */
84  }
85}
86
87static void mlc_wait_until_ready(void)
88{
89  mlc_wait(MLC_ISR_CONTROLLER_READY | MLC_ISR_NAND_READY);
90}
91
92static void mlc_reset(void)
93{
94  mlc->cmd = 0xff;
95}
96
97static uint32_t mlc_status(void)
98{
99  mlc_wait_until_ready();
100  mlc->cmd = 0x70;
101
102  return mlc->data.w8;
103}
104
105static bool mlc_was_operation_successful(void)
106{
107  return (mlc_status() & (NAND_STATUS_READY | NAND_STATUS_ERROR))
108    == NAND_STATUS_READY;
109}
110
111static void mlc_set_block_address(uint32_t block_index)
112{
113  if (mlc_small_pages()) {
114    mlc->addr = (uint8_t) (block_index << 5);
115    mlc->addr = (uint8_t) (block_index >> 3);
116    if (mlc_many_address_cycles()) {
117      mlc->addr = (uint8_t) (block_index >> 11);
118    }
119  } else {
120    if (mlc_normal_blocks()) {
121      mlc->addr = (uint8_t) (block_index << 6);
122      mlc->addr = (uint8_t) (block_index >> 2);
123      if (mlc_many_address_cycles()) {
124        mlc->addr = (uint8_t) (block_index >> 10);
125      }
126    } else {
127      mlc->addr = (uint8_t) (block_index << 7);
128      mlc->addr = (uint8_t) (block_index >> 1);
129      if (mlc_many_address_cycles()) {
130        mlc->addr = (uint8_t) (block_index >> 9);
131      }
132    }
133  }
134}
135
136static void mlc_set_page_address(uint32_t page_index)
137{
138  mlc->addr = 0;
139  if (mlc_small_pages()) {
140    mlc->addr = (uint8_t) page_index;
141    mlc->addr = (uint8_t) (page_index >> 8);
142    if (mlc_many_address_cycles()) {
143      mlc->addr = (uint8_t) (page_index >> 16);
144    }
145  } else {
146    mlc->addr = 0;
147    mlc->addr = (uint8_t) page_index;
148    mlc->addr = (uint8_t) (page_index >> 8);
149    if (mlc_many_address_cycles()) {
150      mlc->addr = (uint8_t) (page_index >> 16);
151    }
152  }
153}
154
155void lpc32xx_mlc_init(const lpc32xx_mlc_config *cfg)
156{
157  uint32_t icr = 0;
158
159  mlc_flags = cfg->flags;
160  mlc_block_count = cfg->block_count;
161  mlc_page_count = cfg->block_count * lpc32xx_mlc_pages_per_block();
162
163  /* Clock */
164  LPC32XX_FLASHCLK_CTRL = FLASHCLK_IRQ_MLC | FLASHCLK_MLC_CLK_ENABLE;
165
166  /* Timing settings */
167  mlc_unlock();
168  mlc->time = cfg->time;
169
170  /* Configuration */
171  if (!mlc_small_pages()) {
172    icr |= MLC_ICR_LARGE_PAGES;
173  }
174  if (mlc_many_address_cycles()) {
175    icr |= MLC_ICR_ADDR_WORD_COUNT_4_5;
176  }
177  mlc_unlock();
178  mlc->icr = icr;
179
180  mlc_reset();
181}
182
183void lpc32xx_mlc_write_protection(
184  uint32_t page_index_low,
185  uint32_t page_index_high
186)
187{
188  mlc_unlock();
189  mlc->sw_wp_add_low = page_index_low;
190  mlc_unlock();
191  mlc->sw_wp_add_hig = page_index_high;
192  mlc_unlock();
193  mlc->icr |= MLC_ICR_SOFT_WRITE_PROT;
194}
195
196rtems_status_code lpc32xx_mlc_read_page(
197  uint32_t page_index,
198  uint32_t *data,
199  uint32_t *spare
200)
201{
202  rtems_status_code sc = RTEMS_SUCCESSFUL;
203  size_t small_pages_count = mlc_small_pages() ? 1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
204  size_t sp = 0;
205  size_t i = 0;
206  uint32_t isr = 0;
207
208  if (page_index >= mlc_page_count) {
209    return RTEMS_INVALID_ID;
210  }
211
212  mlc_wait_until_ready();
213  mlc->cmd = 0x00;
214  if (!mlc_small_pages()) {
215    mlc->cmd = 0x30;
216  }
217  mlc_set_page_address(page_index);
218  mlc_wait(MLC_ISR_NAND_READY);
219
220  for (sp = 0; sc == RTEMS_SUCCESSFUL && sp < small_pages_count; ++sp) {
221    mlc->ecc_dec = 0;
222
223    for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
224      data [i] = mlc->data.w32;
225    }
226    for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
227      spare [i] = mlc->data.w32;
228    }
229
230    mlc_wait(MLC_ISR_ECC_READY);
231
232    isr = mlc->isr;
233    if ((isr & MLC_ISR_ERRORS_DETECTED) != 0) {
234      if ((isr & MLC_ISR_DECODER_FAILURE) == 0) {
235        mlc->rubp = 0;
236        for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
237          data [i] = mlc->buff.w32;
238        }
239        mlc->robp = 0;
240        for (i = 0; i < MLC_SMALL_SPARE_WORD_COUNT; ++i) {
241          spare [i] = mlc->buff.w32;
242        }
243      } else {
244        sc = RTEMS_IO_ERROR;
245      }
246    }
247
248    data += MLC_SMALL_DATA_WORD_COUNT;
249    spare += MLC_SMALL_SPARE_WORD_COUNT;
250  }
251
252  return sc;
253}
254
255void lpc32xx_mlc_read_id(uint8_t *id, size_t n)
256{
257  size_t i = 0;
258
259  mlc_wait_until_ready();
260  mlc->cmd = 0x90;
261  mlc->addr = 0;
262  mlc_wait(MLC_ISR_NAND_READY);
263
264  for (i = 0; i < n; ++i) {
265    id [i] = mlc->data.w8;
266  }
267}
268
269rtems_status_code lpc32xx_mlc_erase_block(uint32_t block_index)
270{
271  rtems_status_code sc = RTEMS_IO_ERROR;
272
273  if (block_index >= mlc_block_count) {
274    return RTEMS_INVALID_ID;
275  }
276
277  mlc_wait_until_ready();
278  mlc->cmd = 0x60;
279  mlc_set_block_address(block_index);
280  mlc->cmd = 0xd0;
281
282  if (mlc_was_operation_successful()) {
283    sc = RTEMS_SUCCESSFUL;
284  }
285
286  return sc;
287}
288
289rtems_status_code lpc32xx_mlc_write_page_with_ecc(
290  uint32_t page_index,
291  const uint32_t *data,
292  const uint32_t *spare
293)
294{
295  rtems_status_code sc = RTEMS_IO_ERROR;
296  size_t small_pages_count = mlc_small_pages() ? 1 : MLC_SMALL_PAGES_PER_LARGE_PAGE;
297  size_t sp = 0;
298  size_t i = 0;
299
300  if (page_index >= mlc_page_count) {
301    return RTEMS_INVALID_ID;
302  }
303
304  mlc_wait_until_ready();
305  mlc->cmd = 0x80;
306  mlc_set_page_address(page_index);
307
308  for (sp = 0; sp < small_pages_count; ++sp) {
309    mlc->ecc_enc = 0;
310
311    for (i = 0; i < MLC_SMALL_DATA_WORD_COUNT; ++i) {
312      mlc->data.w32 = data [i];
313    }
314    mlc->data.w32 = spare [0];
315    mlc->data.w16 = (uint16_t) spare [1];
316    mlc->wpr = 0;
317
318    mlc_wait(MLC_ISR_CONTROLLER_READY);
319
320    data += MLC_SMALL_DATA_WORD_COUNT;
321    spare += MLC_SMALL_SPARE_WORD_COUNT;
322  }
323
324  mlc->cmd = 0x10;
325
326  if (mlc_was_operation_successful()) {
327    sc = RTEMS_SUCCESSFUL;
328  }
329
330  return sc;
331}
Note: See TracBrowser for help on using the repository browser.