- patches.suse/slab-handle-memoryless-nodes-v2a.patch: Refresh.
[linux-flexiantxendom0-3.2.10.git] / drivers / mtd / nand / nand_bcm_umi.c
1 /*****************************************************************************
2 * Copyright 2004 - 2009 Broadcom Corporation.  All rights reserved.
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8 *
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
12 * consent.
13 *****************************************************************************/
14
15 /* ---- Include Files ---------------------------------------------------- */
16 #include <mach/reg_umi.h>
17 #include "nand_bcm_umi.h"
18 #ifdef BOOT0_BUILD
19 #include <uart.h>
20 #endif
21
22 /* ---- External Variable Declarations ----------------------------------- */
23 /* ---- External Function Prototypes ------------------------------------- */
24 /* ---- Public Variables ------------------------------------------------- */
25 /* ---- Private Constants and Types -------------------------------------- */
26 /* ---- Private Function Prototypes -------------------------------------- */
27 /* ---- Private Variables ------------------------------------------------ */
28 /* ---- Private Functions ------------------------------------------------ */
29
30 #if NAND_ECC_BCH
31 /****************************************************************************
32 *  nand_bch_ecc_flip_bit - Routine to flip an errored bit
33 *
34 *  PURPOSE:
35 *     This is a helper routine that flips the bit (0 -> 1 or 1 -> 0) of the
36 *     errored bit specified
37 *
38 *  PARAMETERS:
39 *     datap - Container that holds the 512 byte data
40 *     errorLocation - Location of the bit that needs to be flipped
41 *
42 *  RETURNS:
43 *     None
44 ****************************************************************************/
45 static void nand_bcm_umi_bch_ecc_flip_bit(uint8_t *datap, int errorLocation)
46 {
47         int locWithinAByte = (errorLocation & REG_UMI_BCH_ERR_LOC_BYTE) >> 0;
48         int locWithinAWord = (errorLocation & REG_UMI_BCH_ERR_LOC_WORD) >> 3;
49         int locWithinAPage = (errorLocation & REG_UMI_BCH_ERR_LOC_PAGE) >> 5;
50
51         uint8_t errorByte = 0;
52         uint8_t byteMask = 1 << locWithinAByte;
53
54         /* BCH uses big endian, need to change the location
55          * bits to little endian */
56         locWithinAWord = 3 - locWithinAWord;
57
58         errorByte = datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord];
59
60 #ifdef BOOT0_BUILD
61         puthexs("\nECC Correct Offset: ",
62                 locWithinAPage * sizeof(uint32_t) + locWithinAWord);
63         puthexs(" errorByte:", errorByte);
64         puthex8(" Bit: ", locWithinAByte);
65 #endif
66
67         if (errorByte & byteMask) {
68                 /* bit needs to be cleared */
69                 errorByte &= ~byteMask;
70         } else {
71                 /* bit needs to be set */
72                 errorByte |= byteMask;
73         }
74
75         /* write back the value with the fixed bit */
76         datap[locWithinAPage * sizeof(uint32_t) + locWithinAWord] = errorByte;
77 }
78
79 /****************************************************************************
80 *  nand_correct_page_bch - Routine to correct bit errors when reading NAND
81 *
82 *  PURPOSE:
83 *     This routine reads the BCH registers to determine if there are any bit
84 *     errors during the read of the last 512 bytes of data + ECC bytes.  If
85 *     errors exists, the routine fixes it.
86 *
87 *  PARAMETERS:
88 *     datap - Container that holds the 512 byte data
89 *
90 *  RETURNS:
91 *     0 or greater = Number of errors corrected
92 *                    (No errors are found or errors have been fixed)
93 *    -1 = Error(s) cannot be fixed
94 ****************************************************************************/
95 int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
96                                   int numEccBytes)
97 {
98         int numErrors;
99         int errorLocation;
100         int idx;
101         uint32_t regValue;
102
103         /* wait for read ECC to be valid */
104         regValue = nand_bcm_umi_bch_poll_read_ecc_calc();
105
106         /*
107          * read the control status register to determine if there
108          * are error'ed bits
109          * see if errors are correctible
110          */
111         if ((regValue & REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR) > 0) {
112                 int i;
113
114                 for (i = 0; i < numEccBytes; i++) {
115                         if (readEccData[i] != 0xff) {
116                                 /* errors cannot be fixed, return -1 */
117                                 return -1;
118                         }
119                 }
120                 /* If ECC is unprogrammed then we can't correct,
121                  * assume everything OK */
122                 return 0;
123         }
124
125         if ((regValue & REG_UMI_BCH_CTRL_STATUS_CORR_ERR) == 0) {
126                 /* no errors */
127                 return 0;
128         }
129
130         /*
131          * Fix errored bits by doing the following:
132          * 1. Read the number of errors in the control and status register
133          * 2. Read the error location registers that corresponds to the number
134          *    of errors reported
135          * 3. Invert the bit in the data
136          */
137         numErrors = (regValue & REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR) >> 20;
138
139         for (idx = 0; idx < numErrors; idx++) {
140                 errorLocation =
141                     REG_UMI_BCH_ERR_LOC_ADDR(idx) & REG_UMI_BCH_ERR_LOC_MASK;
142
143                 /* Flip bit */
144                 nand_bcm_umi_bch_ecc_flip_bit(datap, errorLocation);
145         }
146         /* Errors corrected */
147         return numErrors;
148 }
149 #endif