0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/bitops.h>
0011 #include <linux/device.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/platform_device.h>
0016
0017 #include "ingenic_ecc.h"
0018
0019 #define JZ_REG_NAND_ECC_CTRL 0x00
0020 #define JZ_REG_NAND_DATA 0x04
0021 #define JZ_REG_NAND_PAR0 0x08
0022 #define JZ_REG_NAND_PAR1 0x0C
0023 #define JZ_REG_NAND_PAR2 0x10
0024 #define JZ_REG_NAND_IRQ_STAT 0x14
0025 #define JZ_REG_NAND_IRQ_CTRL 0x18
0026 #define JZ_REG_NAND_ERR(x) (0x1C + ((x) << 2))
0027
0028 #define JZ_NAND_ECC_CTRL_PAR_READY BIT(4)
0029 #define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
0030 #define JZ_NAND_ECC_CTRL_RS BIT(2)
0031 #define JZ_NAND_ECC_CTRL_RESET BIT(1)
0032 #define JZ_NAND_ECC_CTRL_ENABLE BIT(0)
0033
0034 #define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29))
0035 #define JZ_NAND_STATUS_PAD_FINISH BIT(4)
0036 #define JZ_NAND_STATUS_DEC_FINISH BIT(3)
0037 #define JZ_NAND_STATUS_ENC_FINISH BIT(2)
0038 #define JZ_NAND_STATUS_UNCOR_ERROR BIT(1)
0039 #define JZ_NAND_STATUS_ERROR BIT(0)
0040
0041 static const uint8_t empty_block_ecc[] = {
0042 0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f
0043 };
0044
0045 static void jz4740_ecc_reset(struct ingenic_ecc *ecc, bool calc_ecc)
0046 {
0047 uint32_t reg;
0048
0049
0050 writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT);
0051
0052
0053 reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
0054 reg |= JZ_NAND_ECC_CTRL_RESET;
0055 reg |= JZ_NAND_ECC_CTRL_ENABLE;
0056 reg |= JZ_NAND_ECC_CTRL_RS;
0057 if (calc_ecc)
0058 reg |= JZ_NAND_ECC_CTRL_ENCODING;
0059 else
0060 reg &= ~JZ_NAND_ECC_CTRL_ENCODING;
0061
0062 writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
0063 }
0064
0065 static int jz4740_ecc_calculate(struct ingenic_ecc *ecc,
0066 struct ingenic_ecc_params *params,
0067 const u8 *buf, u8 *ecc_code)
0068 {
0069 uint32_t reg, status;
0070 unsigned int timeout = 1000;
0071 int i;
0072
0073 jz4740_ecc_reset(ecc, true);
0074
0075 do {
0076 status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT);
0077 } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);
0078
0079 if (timeout == 0)
0080 return -ETIMEDOUT;
0081
0082 reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
0083 reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
0084 writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
0085
0086 for (i = 0; i < params->bytes; ++i)
0087 ecc_code[i] = readb(ecc->base + JZ_REG_NAND_PAR0 + i);
0088
0089
0090
0091
0092
0093 if (memcmp(ecc_code, empty_block_ecc, sizeof(empty_block_ecc)) == 0)
0094 memset(ecc_code, 0xff, sizeof(empty_block_ecc));
0095
0096 return 0;
0097 }
0098
0099 static void jz_nand_correct_data(uint8_t *buf, int index, int mask)
0100 {
0101 int offset = index & 0x7;
0102 uint16_t data;
0103
0104 index += (index >> 3);
0105
0106 data = buf[index];
0107 data |= buf[index + 1] << 8;
0108
0109 mask ^= (data >> offset) & 0x1ff;
0110 data &= ~(0x1ff << offset);
0111 data |= (mask << offset);
0112
0113 buf[index] = data & 0xff;
0114 buf[index + 1] = (data >> 8) & 0xff;
0115 }
0116
0117 static int jz4740_ecc_correct(struct ingenic_ecc *ecc,
0118 struct ingenic_ecc_params *params,
0119 u8 *buf, u8 *ecc_code)
0120 {
0121 int i, error_count, index;
0122 uint32_t reg, status, error;
0123 unsigned int timeout = 1000;
0124
0125 jz4740_ecc_reset(ecc, false);
0126
0127 for (i = 0; i < params->bytes; ++i)
0128 writeb(ecc_code[i], ecc->base + JZ_REG_NAND_PAR0 + i);
0129
0130 reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
0131 reg |= JZ_NAND_ECC_CTRL_PAR_READY;
0132 writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
0133
0134 do {
0135 status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT);
0136 } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout);
0137
0138 if (timeout == 0)
0139 return -ETIMEDOUT;
0140
0141 reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
0142 reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
0143 writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
0144
0145 if (status & JZ_NAND_STATUS_ERROR) {
0146 if (status & JZ_NAND_STATUS_UNCOR_ERROR)
0147 return -EBADMSG;
0148
0149 error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29;
0150
0151 for (i = 0; i < error_count; ++i) {
0152 error = readl(ecc->base + JZ_REG_NAND_ERR(i));
0153 index = ((error >> 16) & 0x1ff) - 1;
0154 if (index >= 0 && index < params->size)
0155 jz_nand_correct_data(buf, index, error & 0x1ff);
0156 }
0157
0158 return error_count;
0159 }
0160
0161 return 0;
0162 }
0163
0164 static void jz4740_ecc_disable(struct ingenic_ecc *ecc)
0165 {
0166 u32 reg;
0167
0168 writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT);
0169 reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
0170 reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
0171 writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
0172 }
0173
0174 static const struct ingenic_ecc_ops jz4740_ecc_ops = {
0175 .disable = jz4740_ecc_disable,
0176 .calculate = jz4740_ecc_calculate,
0177 .correct = jz4740_ecc_correct,
0178 };
0179
0180 static const struct of_device_id jz4740_ecc_dt_match[] = {
0181 { .compatible = "ingenic,jz4740-ecc", .data = &jz4740_ecc_ops },
0182 {},
0183 };
0184 MODULE_DEVICE_TABLE(of, jz4740_ecc_dt_match);
0185
0186 static struct platform_driver jz4740_ecc_driver = {
0187 .probe = ingenic_ecc_probe,
0188 .driver = {
0189 .name = "jz4740-ecc",
0190 .of_match_table = jz4740_ecc_dt_match,
0191 },
0192 };
0193 module_platform_driver(jz4740_ecc_driver);
0194
0195 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
0196 MODULE_DESCRIPTION("Ingenic JZ4740 ECC controller driver");
0197 MODULE_LICENSE("GPL v2");