Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* error correcting code for nand flash */
#include        "u.h"
#include        "../port/lib.h"
#include        "mem.h"
#include        "dat.h"
#include        "fns.h"
#include        "io.h"
#include        "../port/error.h"
#include        "nandecc.h"

#define CORRECTABLEMASK 0x545555

static uchar ecctab[] = {
        0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
        0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
        0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
        0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
        0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
        0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
        0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
        0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
        0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
        0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
        0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
        0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
        0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
        0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
        0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
        0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
        0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
        0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
        0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
        0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
        0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
        0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
        0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
        0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
        0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
        0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
        0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
        0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
        0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
        0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
        0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
        0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};

ulong
nandecc(uchar *buf)
{
        int cp, zeros, ones, im, lp, om, i;

        cp = 0xff;
        zeros = 0xff;
        ones = 0xff;
        for (i = 0; i < 256; i++) {
                int tabent = ecctab[buf[i]];

                cp ^= tabent;
                if (tabent & 1) {
                        zeros ^= ~i;
                        ones ^= i;
                }
        }
        lp = 0;
        for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
                if (ones & im)
                        lp |= om;
                om >>= 1;
                if (zeros & im)
                        lp |= om;
        }
        return (((cp & 0xff) | 3) << 16) | lp;
}

NandEccError
nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
{
        ulong xorecc, mask;
        int k;

        if (calcecc == *storedecc)
                return NandEccErrorGood;
        if (reportbad)
                print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n",
                        calcecc, *storedecc);
        xorecc = calcecc ^ *storedecc;
        if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
                ulong imask;
                ushort out, omask;
                int line, col;

                for (imask = 0x800000, omask = 0x800, out = 0; imask;
                    imask >>= 2, omask >>= 1)
                        if (xorecc & imask)
                                out |= omask;
                line = out & 0xff;
                col = out >> 9;
                if (reportbad)
                        print("nandecccorrect: single bit error line %d col %d\n",
                                line, col);
                buf[line] ^= (1 << col);
                *storedecc = calcecc;
                return NandEccErrorOneBit;
        }
        for (mask = 0x800000, k = 0; mask; mask >>= 1)
                if (mask & xorecc)
                        k++;
        if (k == 1) {
                if (reportbad)
                        print("nandecccorrect: single bit error in ecc\n");
                /* assume the stored ecc was wrong */
                *storedecc = calcecc;
                return NandEccErrorOneBitInEcc;
        }
        if (reportbad)
                print("nandecccorrect: 2 bit error\n");
        return NandEccErrorBad;
}