^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * (C) 2003 Red Hat, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (C) 2004 Dan Brown <dan_brown@ieee.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (C) 2004 Kalev Lember <kalev@smartlink.ee>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: David Woodhouse <dwmw2@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Error correction code lifted from the old docecc code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 2000 Netgem S.A.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Interface to generic NAND code for M-Systems DiskOnChip devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/rslib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/mtd/rawnand.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/mtd/doc2000.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/mtd/inftl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Where to look for the devices? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static unsigned long doc_locations[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) 0xc8000, 0xca000, 0xcc000, 0xce000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) 0xd0000, 0xd2000, 0xd4000, 0xd6000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) 0xd8000, 0xda000, 0xdc000, 0xde000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) 0xe0000, 0xe2000, 0xe4000, 0xe6000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) 0xe8000, 0xea000, 0xec000, 0xee000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) 0xffffffff };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static struct mtd_info *doclist = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct doc_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct nand_controller base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) void __iomem *virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long physadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u_char ChipID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u_char CDSNControl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int chips_per_floor; /* The number of chips detected on each floor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int curfloor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) int curchip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int mh0_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int mh1_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct rs_control *rs_decoder;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct mtd_info *nextdoc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) bool supports_32b_reads;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Handle the last stage of initialization (BBT scan, partitioning) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int (*late_init)(struct mtd_info *mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* This is the ecc value computed by the HW ecc generator upon writing an empty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) page, one with all 0xff for data. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define INFTL_BBT_RESERVED_BLOCKS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int debug = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) module_param(debug, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static int try_dword = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) module_param(try_dword, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int no_ecc_failures = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) module_param(no_ecc_failures, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int no_autopart = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) module_param(no_autopart, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int show_firmware_partition = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) module_param(show_firmware_partition, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int inftl_bbt_write = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int inftl_bbt_write = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) module_param(inftl_bbt_write, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) module_param(doc_config_location, ulong, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Sector size for HW ECC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define SECTOR_SIZE 512
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* The sector bytes are packed into NB_DATA 10 bit words */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Number of roots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define NROOTS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* First consective root */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define FCR 510
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* Number of symbols */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define NN 1023
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * The HW decoder in the DoC ASIC's provides us a error syndrome,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * which we must convert to a standard syndrome usable by the generic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Reed-Solomon library code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * Fabrice Bellard figured this out in the old docecc code. I added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * some comments, improved a minor bit and converted it to make use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * of the generic Reed-Solomon library. tglx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int i, j, nerr, errpos[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) uint8_t parity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) uint16_t ds[4], s[5], tmp, errval[8], syn[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct rs_codec *cd = rs->codec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) memset(syn, 0, sizeof(syn));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Convert the ecc bytes into words */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) parity = ecc[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Initialize the syndrome buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) for (i = 0; i < NROOTS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) s[i] = ds[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * Evaluate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * where x = alpha^(FCR + i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) for (j = 1; j < NROOTS; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (ds[j] == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) tmp = cd->index_of[ds[j]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) for (i = 0; i < NROOTS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) s[i] ^= cd->alpha_to[rs_modnn(cd, tmp + (FCR + i) * j)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* Calc syn[i] = s[i] / alpha^(v + i) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) for (i = 0; i < NROOTS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (s[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) syn[i] = rs_modnn(cd, cd->index_of[s[i]] + (NN - FCR - i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Call the decoder library */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* Incorrectable errors ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (nerr < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return nerr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Correct the errors. The bitpositions are a bit of magic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * but they are given by the design of the de/encoder circuit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * in the DoC ASIC's.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) for (i = 0; i < nerr; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) int index, bitpos, pos = 1015 - errpos[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) uint8_t val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (pos >= NB_DATA && pos < 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (pos < NB_DATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* extract bit position (MSB first) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) pos = 10 * (NB_DATA - 1 - pos) - 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /* now correct the following 10 bits. At most two bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) can be modified since pos is even */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) index = (pos >> 3) ^ 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) bitpos = pos & 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) val = (uint8_t) (errval[i] >> (2 + bitpos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) parity ^= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (index < SECTOR_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) data[index] ^= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) index = ((pos >> 3) + 1) ^ 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) bitpos = (bitpos + 10) & 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (bitpos == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) bitpos = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) val = (uint8_t) (errval[i] << (8 - bitpos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) parity ^= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (index < SECTOR_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) data[index] ^= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* If the parity is wrong, no rescue possible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return parity ? -EBADMSG : nerr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) volatile char dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) for (i = 0; i < cycles; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (DoC_is_Millennium(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) dummy = ReadDOC(doc->virtadr, NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) else if (DoC_is_MillenniumPlus(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) dummy = ReadDOC(doc->virtadr, Mplus_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) dummy = ReadDOC(doc->virtadr, DOCStatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static int _DoC_WaitReady(struct doc_priv *doc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) unsigned long timeo = jiffies + (HZ * 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) printk("_DoC_WaitReady...\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) /* Out-of-line routine to wait for chip response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (DoC_is_MillenniumPlus(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (time_after(jiffies, timeo)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) printk("_DoC_WaitReady timed out.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (time_after(jiffies, timeo)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) printk("_DoC_WaitReady timed out.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static inline int DoC_WaitReady(struct doc_priv *doc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (DoC_is_MillenniumPlus(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) DoC_Delay(doc, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /* Call the out-of-line routine to wait */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ret = _DoC_WaitReady(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) DoC_Delay(doc, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Call the out-of-line routine to wait */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) ret = _DoC_WaitReady(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) DoC_Delay(doc, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) printk("DoC_WaitReady OK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static void doc2000_write_byte(struct nand_chip *this, u_char datum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) printk("write_byte %02x\n", datum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) WriteDOC(datum, docptr, CDSNSlowIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) WriteDOC(datum, docptr, 2k_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) printk("writebuf of %d bytes: ", len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) for (i = 0; i < len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (debug && i < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) printk("%02x ", buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) u32 *buf32 = (u32 *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) printk("readbuf of %d bytes: ", len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!doc->supports_32b_reads ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) ((((unsigned long)buf) | len) & 3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) for (i = 0; i < len / 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) buf32[i] = readl(docptr + DoC_2k_CDSN_IO + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * We need our own readid() here because it's called before the NAND chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * has been initialized, and calling nand_op_readid() would lead to a NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * pointer exception when dereferencing the NAND timings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static void doc200x_readid(struct nand_chip *this, unsigned int cs, u8 *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) u8 addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct nand_op_instr instrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) NAND_OP_CMD(NAND_CMD_READID, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) NAND_OP_ADDR(1, &addr, 50),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) NAND_OP_8BIT_DATA_IN(2, id, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct nand_operation op = NAND_OPERATION(cs, instrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (!id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) op.ninstrs--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) this->controller->ops->exec_op(this, &op, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) uint16_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) u8 id[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) doc200x_readid(this, nr, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) ret = ((u16)id[0] << 8) | id[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) /* First chip probe. See if we get same results by 32-bit access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) uint32_t dword;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) uint8_t byte[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) } ident;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) doc200x_readid(this, nr, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) ident.dword = readl(docptr + DoC_2k_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) pr_info("DiskOnChip 2000 responds to DWORD access\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) doc->supports_32b_reads = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static void __init doc2000_count_chips(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) uint16_t mfrid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /* Max 4 chips per floor on DiskOnChip 2000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) doc->chips_per_floor = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) /* Find out what the first chip is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) mfrid = doc200x_ident_chip(mtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /* Find how many chips in each floor. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) for (i = 1; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (doc200x_ident_chip(mtd, i) != mfrid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) doc->chips_per_floor = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) pr_debug("Detected %d chips per floor.\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static void doc2001_write_byte(struct nand_chip *this, u_char datum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) WriteDOC(datum, docptr, CDSNSlowIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) WriteDOC(datum, docptr, Mil_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) WriteDOC(datum, docptr, WritePipeTerm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) /* Terminate write pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) WriteDOC(0x00, docptr, WritePipeTerm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) /* Start read pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) ReadDOC(docptr, ReadPipeInit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) for (i = 0; i < len - 1; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /* Terminate read pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) buf[i] = ReadDOC(docptr, LastDataRead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) printk("writebuf of %d bytes: ", len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) for (i = 0; i < len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (debug && i < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) printk("%02x ", buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) printk("readbuf of %d bytes: ", len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /* Start read pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) ReadDOC(docptr, Mplus_ReadPipeInit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) ReadDOC(docptr, Mplus_ReadPipeInit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) for (i = 0; i < len - 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (debug && i < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) printk("%02x ", buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) /* Terminate read pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (len >= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (debug && i < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) printk("%02x ", buf[len - 2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (debug && i < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) printk("%02x ", buf[len - 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) static void doc200x_write_control(struct doc_priv *doc, u8 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) WriteDOC(value, doc->virtadr, CDSNControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* 11.4.3 -- 4 NOPs after CSDNControl write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) DoC_Delay(doc, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static void doc200x_exec_instr(struct nand_chip *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) const struct nand_op_instr *instr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) switch (instr->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) case NAND_OP_CMD_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_CLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) doc2000_write_byte(this, instr->ctx.cmd.opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) case NAND_OP_ADDR_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_ALE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) for (i = 0; i < instr->ctx.addr.naddrs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) u8 addr = instr->ctx.addr.addrs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (DoC_is_2000(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) doc2000_write_byte(this, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) doc2001_write_byte(this, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) case NAND_OP_DATA_IN_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) doc200x_write_control(doc, CDSN_CTRL_CE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (DoC_is_2000(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) doc2000_readbuf(this, instr->ctx.data.buf.in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) doc2001_readbuf(this, instr->ctx.data.buf.in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) case NAND_OP_DATA_OUT_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) doc200x_write_control(doc, CDSN_CTRL_CE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (DoC_is_2000(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) doc2000_writebuf(this, instr->ctx.data.buf.out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) doc2001_writebuf(this, instr->ctx.data.buf.out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) case NAND_OP_WAITRDY_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) DoC_WaitReady(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (instr->delay_ns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) ndelay(instr->delay_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int doc200x_exec_op(struct nand_chip *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) const struct nand_operation *op,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) bool check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) doc->curchip = op->cs % doc->chips_per_floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) doc->curfloor = op->cs / doc->chips_per_floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) WriteDOC(doc->curfloor, doc->virtadr, FloorSelect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) WriteDOC(doc->curchip, doc->virtadr, CDSNDeviceSelect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /* Assert CE pin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) doc200x_write_control(doc, CDSN_CTRL_CE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) for (i = 0; i < op->ninstrs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) doc200x_exec_instr(this, &op->instrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /* De-assert CE pin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) doc200x_write_control(doc, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) static void doc2001plus_write_pipe_term(struct doc_priv *doc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) static void doc2001plus_exec_instr(struct nand_chip *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) const struct nand_op_instr *instr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) switch (instr->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) case NAND_OP_CMD_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) WriteDOC(instr->ctx.cmd.opcode, doc->virtadr, Mplus_FlashCmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) doc2001plus_write_pipe_term(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) case NAND_OP_ADDR_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) for (i = 0; i < instr->ctx.addr.naddrs; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) u8 addr = instr->ctx.addr.addrs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) WriteDOC(addr, doc->virtadr, Mplus_FlashAddress);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) doc2001plus_write_pipe_term(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /* deassert ALE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) WriteDOC(0, doc->virtadr, Mplus_FlashControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) case NAND_OP_DATA_IN_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) doc2001plus_readbuf(this, instr->ctx.data.buf.in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) case NAND_OP_DATA_OUT_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) doc2001plus_writebuf(this, instr->ctx.data.buf.out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) instr->ctx.data.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) doc2001plus_write_pipe_term(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) case NAND_OP_WAITRDY_INSTR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) DoC_WaitReady(doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (instr->delay_ns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) ndelay(instr->delay_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) static int doc2001plus_exec_op(struct nand_chip *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) const struct nand_operation *op,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) bool check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (check_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) doc->curchip = op->cs % doc->chips_per_floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) doc->curfloor = op->cs / doc->chips_per_floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /* Assert ChipEnable and deassert WriteProtect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) WriteDOC(DOC_FLASH_CE, doc->virtadr, Mplus_FlashSelect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) for (i = 0; i < op->ninstrs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) doc2001plus_exec_instr(this, &op->instrs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) /* De-assert ChipEnable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) WriteDOC(0, doc->virtadr, Mplus_FlashSelect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) /* Prime the ECC engine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) switch (mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) case NAND_ECC_READ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) WriteDOC(DOC_ECC_EN, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) case NAND_ECC_WRITE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) /* Prime the ECC engine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) switch (mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) case NAND_ECC_READ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) case NAND_ECC_WRITE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) /* This code is only called on write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) unsigned char *ecc_code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) int emptymatch = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) /* flush the pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (DoC_is_2000(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) WriteDOC(0, docptr, 2k_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) WriteDOC(0, docptr, 2k_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) WriteDOC(0, docptr, 2k_CDSN_IO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) WriteDOC(doc->CDSNControl, docptr, CDSNControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) } else if (DoC_is_MillenniumPlus(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) WriteDOC(0, docptr, Mplus_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) WriteDOC(0, docptr, Mplus_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) WriteDOC(0, docptr, Mplus_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) WriteDOC(0, docptr, NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) WriteDOC(0, docptr, NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) WriteDOC(0, docptr, NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) for (i = 0; i < 6; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (DoC_is_MillenniumPlus(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (ecc_code[i] != empty_write_ecc[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) emptymatch = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (DoC_is_MillenniumPlus(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /* If emptymatch=1, we might have an all-0xff data buffer. Check. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (emptymatch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /* Note: this somewhat expensive test should not be triggered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) often. It could be optimized away by examining the data in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) the writebuf routine, and remembering the result. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) for (i = 0; i < 512; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (dat[i] == 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) emptymatch = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) /* If emptymatch still =1, we do have an all-0xff data buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) Return all-0xff ecc value instead of the computed one, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) it'll look just like a freshly-erased page. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (emptymatch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) memset(ecc_code, 0xff, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) u_char *read_ecc, u_char *isnull)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) void __iomem *docptr = doc->virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) uint8_t calc_ecc[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) volatile u_char dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) /* flush the pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (DoC_is_2000(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) dummy = ReadDOC(docptr, 2k_ECCStatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) dummy = ReadDOC(docptr, 2k_ECCStatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) dummy = ReadDOC(docptr, 2k_ECCStatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) } else if (DoC_is_MillenniumPlus(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) dummy = ReadDOC(docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) dummy = ReadDOC(docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) dummy = ReadDOC(docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) dummy = ReadDOC(docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) dummy = ReadDOC(docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) dummy = ReadDOC(docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) /* Error occurred ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (dummy & 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) for (i = 0; i < 6; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (DoC_is_MillenniumPlus(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) ret = doc_ecc_decode(doc->rs_decoder, dat, calc_ecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (ret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) pr_err("doc200x_correct_data corrected %d errors\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (DoC_is_MillenniumPlus(doc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (no_ecc_failures && mtd_is_eccerr(ret)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) pr_err("suppressing ECC failure\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) //u_char mydatabuf[528];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) struct mtd_oob_region *oobregion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (section)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) oobregion->offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) oobregion->length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) struct mtd_oob_region *oobregion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (section > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) * The strange out-of-order free bytes definition is a (possibly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) * unneeded) attempt to retain compatibility. It used to read:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) * .oobfree = { {8, 8} }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) * Since that leaves two bytes unusable, it was changed. But the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) * following scheme might affect existing jffs2 installs by moving the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) * cleanmarker:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) * .oobfree = { {6, 10} }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) * jffs2 seems to handle the above gracefully, but the current scheme
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * seems safer. The only problem with it is that any code retrieving
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) * free bytes position must be able to handle out-of-order segments.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (!section) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) oobregion->offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) oobregion->length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) oobregion->offset = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) oobregion->length = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) .ecc = doc200x_ooblayout_ecc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) .free = doc200x_ooblayout_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) On successful return, buf will contain a copy of the media header for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) further processing. id is the string to scan for, and will presumably be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) header. The page #s of the found media headers are placed in mh0_page and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) mh1_page in the DOC private structure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) unsigned offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (retlen != mtd->writesize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) pr_warn("ECC error scanning DOC at 0x%x\n", offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (memcmp(buf, id, 6))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) pr_info("Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (doc->mh0_page == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) doc->mh0_page = offs >> this->page_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) if (!findmirror)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) doc->mh1_page = offs >> this->page_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (doc->mh0_page == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) pr_warn("DiskOnChip %s Media Header not found.\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) /* Only one mediaheader was found. We want buf to contain a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) mediaheader on return, so we'll have to re-read the one we found. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) offs = doc->mh0_page << this->page_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (retlen != mtd->writesize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) /* Insanity. Give up. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) pr_err("Read DiskOnChip Media Header once, but can't reread it???\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) struct nand_memory_organization *memorg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) u_char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) struct NFTLMediaHeader *mh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) const unsigned psize = 1 << this->page_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) int numparts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) unsigned blocks, maxblocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) int offs, numheaders;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) memorg = nanddev_get_memorg(&this->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) buf = kmalloc(mtd->writesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) mh = (struct NFTLMediaHeader *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) le16_to_cpus(&mh->NumEraseUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) le16_to_cpus(&mh->FirstPhysicalEUN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) le32_to_cpus(&mh->FormattedSize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) pr_info(" DataOrgID = %s\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) " NumEraseUnits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) " FirstPhysicalEUN = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) " FormattedSize = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) " UnitSizeFactor = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) mh->DataOrgID, mh->NumEraseUnits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) mh->FirstPhysicalEUN, mh->FormattedSize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) blocks = mtd->size >> this->phys_erase_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) maxblocks = min(32768U, mtd->erasesize - psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) if (mh->UnitSizeFactor == 0x00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) /* Auto-determine UnitSizeFactor. The constraints are:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) - There can be at most 32768 virtual blocks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) - There can be at most (virtual block size - page size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) virtual blocks (because MediaHeader+BBT must fit in 1).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) mh->UnitSizeFactor = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) while (blocks > maxblocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) blocks >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) maxblocks = min(32768U, (maxblocks << 1) + psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) mh->UnitSizeFactor--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) pr_warn("UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) /* NOTE: The lines below modify internal variables of the NAND and MTD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) layers; variables with have already been configured by nand_scan.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) Unfortunately, we didn't know before this point what these values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) should be. Thus, this code is somewhat dependent on the exact
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) implementation of the NAND layer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (mh->UnitSizeFactor != 0xff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) blocks = mtd->size >> this->bbt_erase_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) maxblocks = min(32768U, mtd->erasesize - psize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) if (blocks > maxblocks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) pr_err("UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) /* Skip past the media headers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) offs = max(doc->mh0_page, doc->mh1_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) offs <<= this->page_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) offs += mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) if (show_firmware_partition == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) parts[0].name = " DiskOnChip Firmware / Media Header partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) parts[0].offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) parts[0].size = offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) numparts = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) parts[numparts].name = " DiskOnChip BDTL partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) parts[numparts].offset = offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) offs += parts[numparts].size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) numparts++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (offs < mtd->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) parts[numparts].name = " DiskOnChip Remainder partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) parts[numparts].offset = offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) parts[numparts].size = mtd->size - offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) numparts++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) ret = numparts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) /* This is a stripped-down copy of the code in inftlmount.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) u_char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) struct INFTLMediaHeader *mh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) struct INFTLPartition *ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) int numparts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) int blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) int vshift, lastvunit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) int end = mtd->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) if (inftl_bbt_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) buf = kmalloc(mtd->writesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) if (!find_media_headers(mtd, buf, "BNAND", 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) mh = (struct INFTLMediaHeader *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) le32_to_cpus(&mh->NoOfBootImageBlocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) le32_to_cpus(&mh->NoOfBinaryPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) le32_to_cpus(&mh->NoOfBDTLPartitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) le32_to_cpus(&mh->BlockMultiplierBits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) le32_to_cpus(&mh->FormatFlags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) le32_to_cpus(&mh->PercentUsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) pr_info(" bootRecordID = %s\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) " NoOfBootImageBlocks = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) " NoOfBinaryPartitions = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) " NoOfBDTLPartitions = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) " BlockMultiplierBits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) " FormatFlgs = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) " OsakVersion = %d.%d.%d.%d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) " PercentUsed = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) mh->bootRecordID, mh->NoOfBootImageBlocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) mh->NoOfBinaryPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) mh->NoOfBDTLPartitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) mh->BlockMultiplierBits, mh->FormatFlags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) mh->PercentUsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) blocks = mtd->size >> vshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) if (blocks > 32768) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) pr_err("BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (inftl_bbt_write && (blocks > mtd->erasesize)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) pr_err("Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) /* Scan the partitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) for (i = 0; (i < 4); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) ip = &(mh->Partitions[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) le32_to_cpus(&ip->virtualUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) le32_to_cpus(&ip->firstUnit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) le32_to_cpus(&ip->lastUnit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) le32_to_cpus(&ip->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) le32_to_cpus(&ip->spareUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) le32_to_cpus(&ip->Reserved0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) pr_info(" PARTITION[%d] ->\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) " virtualUnits = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) " firstUnit = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) " lastUnit = %d\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) " flags = 0x%x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) " spareUnits = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) i, ip->virtualUnits, ip->firstUnit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) ip->lastUnit, ip->flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) ip->spareUnits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) if ((show_firmware_partition == 1) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) (i == 0) && (ip->firstUnit > 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) parts[0].name = " DiskOnChip IPL / Media Header partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) parts[0].offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) parts[0].size = mtd->erasesize * ip->firstUnit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) numparts = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (ip->flags & INFTL_BINARY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) parts[numparts].name = " DiskOnChip BDK partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) parts[numparts].name = " DiskOnChip BDTL partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) parts[numparts].offset = ip->firstUnit << vshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) numparts++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (ip->lastUnit > lastvunit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) lastvunit = ip->lastUnit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) if (ip->flags & INFTL_LAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) lastvunit++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if ((lastvunit << vshift) < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) parts[numparts].name = " DiskOnChip Remainder partition";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) parts[numparts].offset = lastvunit << vshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) parts[numparts].size = end - parts[numparts].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) numparts++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) ret = numparts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) static int __init nftl_scan_bbt(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) int ret, numparts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) struct mtd_partition parts[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) memset((char *)parts, 0, sizeof(parts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) /* On NFTL, we have to find the media headers before we can read the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) BBTs, since they're stored in the media header eraseblocks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) numparts = nftl_partscan(mtd, parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) if (!numparts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) NAND_BBT_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) this->bbt_td->veroffs = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) this->bbt_td->pages[0] = doc->mh0_page + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (doc->mh1_page != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) NAND_BBT_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) this->bbt_md->veroffs = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) this->bbt_md->pages[0] = doc->mh1_page + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) this->bbt_md = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) ret = nand_create_bbt(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) static int __init inftl_scan_bbt(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) int ret, numparts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) struct mtd_partition parts[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) if (nanddev_ntargets(&this->base) > doc->chips_per_floor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) pr_err("Multi-floor INFTL devices not yet supported.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) if (DoC_is_MillenniumPlus(doc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) if (inftl_bbt_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) this->bbt_td->options |= NAND_BBT_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) this->bbt_td->pages[0] = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) this->bbt_md = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) if (inftl_bbt_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) this->bbt_td->options |= NAND_BBT_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) this->bbt_td->offs = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) this->bbt_td->len = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) this->bbt_td->veroffs = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) this->bbt_td->reserved_block_code = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) this->bbt_td->pattern = "MSYS_BBT";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) if (inftl_bbt_write)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) this->bbt_md->options |= NAND_BBT_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) this->bbt_md->offs = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) this->bbt_md->len = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) this->bbt_md->veroffs = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) this->bbt_md->reserved_block_code = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) this->bbt_md->pattern = "TBB_SYSM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) ret = nand_create_bbt(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) memset((char *)parts, 0, sizeof(parts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) numparts = inftl_partscan(mtd, parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) /* At least for now, require the INFTL Media Header. We could probably
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) do without it for non-INFTL use, since all it gives us is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) autopartitioning, but I want to give it more thought. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) if (!numparts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) static inline int __init doc2000_init(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) doc->late_init = nftl_scan_bbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) doc2000_count_chips(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) mtd->name = "DiskOnChip 2000 (NFTL Model)";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) return (4 * doc->chips_per_floor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) static inline int __init doc2001_init(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) ReadDOC(doc->virtadr, ChipID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) ReadDOC(doc->virtadr, ChipID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) ReadDOC(doc->virtadr, ChipID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) /* It's not a Millennium; it's one of the newer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) DiskOnChip 2000 units with a similar ASIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) Treat it like a Millennium, except that it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) can have multiple chips. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) doc2000_count_chips(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) mtd->name = "DiskOnChip 2000 (INFTL Model)";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) doc->late_init = inftl_scan_bbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) return (4 * doc->chips_per_floor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) /* Bog-standard Millennium */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) doc->chips_per_floor = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) mtd->name = "DiskOnChip Millennium";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) doc->late_init = nftl_scan_bbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) static inline int __init doc2001plus_init(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) struct nand_chip *this = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) struct doc_priv *doc = nand_get_controller_data(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) doc->late_init = inftl_scan_bbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) this->ecc.hwctl = doc2001plus_enable_hwecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) doc->chips_per_floor = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) mtd->name = "DiskOnChip Millennium Plus";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) static int doc200x_attach_chip(struct nand_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) chip->ecc.size = 512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) chip->ecc.bytes = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) chip->ecc.strength = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) chip->ecc.hwctl = doc200x_enable_hwecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) chip->ecc.calculate = doc200x_calculate_ecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) chip->ecc.correct = doc200x_correct_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) static const struct nand_controller_ops doc200x_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) .exec_op = doc200x_exec_op,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) .attach_chip = doc200x_attach_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) static const struct nand_controller_ops doc2001plus_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) .exec_op = doc2001plus_exec_op,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) .attach_chip = doc200x_attach_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) static int __init doc_probe(unsigned long physadr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) struct nand_chip *nand = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) struct doc_priv *doc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) unsigned char ChipID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) void __iomem *virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) unsigned char save_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) unsigned char tmp, tmpb, tmpc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) int reg, len, numchips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) if (!virtadr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) DOC_IOREMAP_LEN, physadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) goto error_ioremap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) /* It's not possible to cleanly detect the DiskOnChip - the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) * bootup procedure will put the device into reset mode, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) * it's not possible to talk to it without actually writing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) * to the DOCControl register. So we store the current contents
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) * of the DOCControl register's location, in case we later decide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) * that it's not a DiskOnChip, and want to put it back how we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) * found it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) save_control = ReadDOC(virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) /* Reset the DiskOnChip ASIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) /* Enable the DiskOnChip ASIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) ChipID = ReadDOC(virtadr, ChipID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) switch (ChipID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) case DOC_ChipID_Doc2k:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) reg = DoC_2k_ECCStatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) case DOC_ChipID_DocMil:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) reg = DoC_ECCConf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) case DOC_ChipID_DocMilPlus16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) case DOC_ChipID_DocMilPlus32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) /* Possible Millennium Plus, need to do more checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) /* Possibly release from power down mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) for (tmp = 0; (tmp < 4); tmp++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) ReadDOC(virtadr, Mplus_Power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) /* Reset the Millennium Plus ASIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) WriteDOC(tmp, virtadr, Mplus_DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) /* Enable the Millennium Plus ASIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) WriteDOC(tmp, virtadr, Mplus_DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) ChipID = ReadDOC(virtadr, ChipID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) switch (ChipID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) case DOC_ChipID_DocMilPlus16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) reg = DoC_Mplus_Toggle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) case DOC_ChipID_DocMilPlus32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) goto notfound;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) goto notfound;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) /* Check the TOGGLE bit in the ECC register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) if ((tmp == tmpb) || (tmp != tmpc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) goto notfound;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) for (mtd = doclist; mtd; mtd = doc->nextdoc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) unsigned char oldval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) unsigned char newval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) nand = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) doc = nand_get_controller_data(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) /* Use the alias resolution register to determine if this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) in fact the same DOC aliased to a new address. If writes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) to one chip's alias resolution register change the value on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) the other chip, they're the same chip. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) if (ChipID == DOC_ChipID_DocMilPlus16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) newval = ReadDOC(virtadr, Mplus_AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) oldval = ReadDOC(doc->virtadr, AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) newval = ReadDOC(virtadr, AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) if (oldval != newval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) if (ChipID == DOC_ChipID_DocMilPlus16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) WriteDOC(~newval, virtadr, Mplus_AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) WriteDOC(~newval, virtadr, AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) oldval = ReadDOC(doc->virtadr, AliasResolution);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) WriteDOC(newval, virtadr, AliasResolution); // restore it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) newval = ~newval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (oldval == newval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) doc->physadr, physadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) goto notfound;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) pr_notice("DiskOnChip found at 0x%lx\n", physadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) (2 * sizeof(struct nand_bbt_descr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) nand = kzalloc(len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if (!nand) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) * Allocate a RS codec instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) * Symbolsize is 10 (bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) * Primitve polynomial is x^10+x^3+1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) * First consecutive root is 510
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) * Primitve element to generate roots = 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) * Generator polinomial degree = 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) doc = (struct doc_priv *) (nand + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) if (!doc->rs_decoder) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) pr_err("DiskOnChip: Could not create a RS codec\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) nand_controller_init(&doc->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) if (ChipID == DOC_ChipID_DocMilPlus16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) doc->base.ops = &doc2001plus_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) doc->base.ops = &doc200x_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) mtd = nand_to_mtd(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) nand->bbt_td = (struct nand_bbt_descr *) (doc + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) nand->bbt_md = nand->bbt_td + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) mtd->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) nand->controller = &doc->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) nand_set_controller_data(nand, doc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) nand->bbt_options = NAND_BBT_USE_FLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) /* Skip the automatic BBT scan so we can run it manually */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) nand->options |= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) doc->physadr = physadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) doc->virtadr = virtadr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) doc->ChipID = ChipID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) doc->curfloor = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) doc->curchip = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) doc->mh0_page = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) doc->mh1_page = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) doc->nextdoc = doclist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) if (ChipID == DOC_ChipID_Doc2k)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) numchips = doc2000_init(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) else if (ChipID == DOC_ChipID_DocMilPlus16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) numchips = doc2001plus_init(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) numchips = doc2001_init(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) /* DBB note: i believe nand_cleanup is necessary here, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) buffers may have been allocated in nand_base. Check with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) Thomas. FIX ME! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) nand_cleanup(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) /* Success! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) doclist = mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) notfound:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) /* Put back the contents of the DOCControl register, in case it's not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) actually a DiskOnChip. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) WriteDOC(save_control, virtadr, DOCControl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) if (doc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) free_rs(doc->rs_decoder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) kfree(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) iounmap(virtadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) error_ioremap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) release_mem_region(physadr, DOC_IOREMAP_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) static void release_nanddoc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) struct mtd_info *mtd, *nextmtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) struct nand_chip *nand;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) struct doc_priv *doc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) for (mtd = doclist; mtd; mtd = nextmtd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) nand = mtd_to_nand(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) doc = nand_get_controller_data(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) nextmtd = doc->nextdoc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) ret = mtd_device_unregister(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) WARN_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) nand_cleanup(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) iounmap(doc->virtadr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) free_rs(doc->rs_decoder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) kfree(nand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) static int __init init_nanddoc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) if (doc_config_location) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) pr_info("Using configured DiskOnChip probe address 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) doc_config_location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) ret = doc_probe(doc_config_location);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) doc_probe(doc_locations[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) /* No banner message any more. Print a message if no DiskOnChip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) found, so the user knows we at least tried. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (!doclist) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) pr_info("No valid DiskOnChip devices found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) static void __exit cleanup_nanddoc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) /* Cleanup the nand/DoC resources */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) release_nanddoc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) module_init(init_nanddoc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) module_exit(cleanup_nanddoc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");