^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Handles the M-Systems DiskOnChip G3 chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2011 Robert Jarzmik
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/bitrev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/bch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CREATE_TRACE_POINTS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "docg3.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * This driver handles the DiskOnChip G3 flash memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * As no specification is available from M-Systems/Sandisk, this drivers lacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * several functions available on the chip, as :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * - IPL write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * the driver assumes a 16bits data bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * DocG3 relies on 2 ECC algorithms, which are handled in hardware :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * - a 1 byte Hamming code stored in the OOB for each page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * - a 7 bytes BCH code stored in the OOB for each page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * The BCH ECC is :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * - BCH is in GF(2^14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * - BCH is over data of 520 bytes (512 page + 7 page_info bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * + 1 hamming byte)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * - BCH can correct up to 4 bits (t = 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * - BCH syndroms are calculated in hardware, and checked in hardware as well
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static unsigned int reliable_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) module_param(reliable_mode, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) "2=reliable) : MLC normal operations are in normal mode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static int docg3_ooblayout_ecc(struct mtd_info *mtd, int section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct mtd_oob_region *oobregion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (section)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* byte 7 is Hamming ECC, byte 8-14 are BCH ECC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) oobregion->offset = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) oobregion->length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int docg3_ooblayout_free(struct mtd_info *mtd, int section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct mtd_oob_region *oobregion)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (section > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* free bytes: byte 0 until byte 6, byte 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (!section) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) oobregion->offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) oobregion->length = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) oobregion->offset = 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) oobregion->length = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static const struct mtd_ooblayout_ops nand_ooblayout_docg3_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .ecc = docg3_ooblayout_ecc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .free = docg3_ooblayout_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u8 val = readb(docg3->cascade->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) trace_docg3_io(0, 8, reg, (int)val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static inline u16 doc_readw(struct docg3 *docg3, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u16 val = readw(docg3->cascade->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) trace_docg3_io(0, 16, reg, (int)val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) writeb(val, docg3->cascade->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) trace_docg3_io(1, 8, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) writew(val, docg3->cascade->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) trace_docg3_io(1, 16, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static inline void doc_flash_command(struct docg3 *docg3, u8 cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) doc_writeb(docg3, cmd, DOC_FLASHCOMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static inline void doc_flash_sequence(struct docg3 *docg3, u8 seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) doc_writeb(docg3, seq, DOC_FLASHSEQUENCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static inline void doc_flash_address(struct docg3 *docg3, u8 addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) doc_writeb(docg3, addr, DOC_FLASHADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static char const * const part_probes[] = { "cmdlinepart", "saftlpart", NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static int doc_register_readb(struct docg3 *docg3, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u8 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) doc_writew(docg3, reg, DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) val = doc_readb(docg3, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) doc_vdbg("Read register %04x : %02x\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static int doc_register_readw(struct docg3 *docg3, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) u16 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) doc_writew(docg3, reg, DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) val = doc_readw(docg3, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) doc_vdbg("Read register %04x : %04x\n", reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * doc_delay - delay docg3 operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * @nbNOPs: the number of NOPs to issue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * As no specification is available, the right timings between chip commands are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * unknown. The only available piece of information are the observed nops on a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * working docg3 chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * Therefore, doc_delay relies on a busy loop of NOPs, instead of scheduler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * friendlier msleep() functions or blocking mdelay().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void doc_delay(struct docg3 *docg3, int nbNOPs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) doc_vdbg("NOP x %d\n", nbNOPs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) for (i = 0; i < nbNOPs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) doc_writeb(docg3, 0, DOC_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int is_prot_seq_error(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return ctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int doc_is_ready(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return ctrl & DOC_CTRL_FLASHREADY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static int doc_wait_ready(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int maxWaitCycles = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) doc_delay(docg3, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) } while (!doc_is_ready(docg3) && maxWaitCycles--);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (maxWaitCycles > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int doc_reset_seq(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) doc_writeb(docg3, 0x10, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) doc_flash_sequence(docg3, DOC_SEQ_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) doc_flash_command(docg3, DOC_CMD_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) ret = doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) doc_dbg("doc_reset_seq() -> isReady=%s\n", ret ? "false" : "true");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * doc_read_data_area - Read data from data area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * @buf: the buffer to fill in (might be NULL is dummy reads)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * @len: the length to read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * @first: first time read, DOC_READADDRESS should be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * Reads bytes from flash data. Handles the single byte / even bytes reads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static void doc_read_data_area(struct docg3 *docg3, void *buf, int len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int first)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) int i, cdr, len4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) u16 data16, *dst16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) u8 data8, *dst8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) cdr = len & 0x1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) len4 = len - cdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (first)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) dst16 = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) for (i = 0; i < len4; i += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) data16 = doc_readw(docg3, DOC_IOSPACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (dst16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *dst16 = data16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dst16++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (cdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) dst8 = (u8 *)dst16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) for (i = 0; i < cdr; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) data8 = doc_readb(docg3, DOC_IOSPACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (dst8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) *dst8 = data8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dst8++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * doc_write_data_area - Write data into data area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * @buf: the buffer to get input bytes from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * @len: the length to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * Writes bytes into flash data. Handles the single byte / even bytes writes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static void doc_write_data_area(struct docg3 *docg3, const void *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) int i, cdr, len4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) u16 *src16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) u8 *src8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) doc_dbg("doc_write_data_area(buf=%p, len=%d)\n", buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) cdr = len & 0x3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) len4 = len - cdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) src16 = (u16 *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) for (i = 0; i < len4; i += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) doc_writew(docg3, *src16, DOC_IOSPACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) src16++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) src8 = (u8 *)src16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) for (i = 0; i < cdr; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) DOC_READADDRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) doc_writeb(docg3, *src8, DOC_IOSPACE_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) src8++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^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) * doc_set_data_mode - Sets the flash to normal or reliable data mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * The reliable data mode is a bit slower than the fast mode, but less errors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * occur. Entering the reliable mode cannot be done without entering the fast
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * mode first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * In reliable mode, pages 2*n and 2*n+1 are clones. Writing to page 0 of blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * (4,5) make the hardware write also to page 1 of blocks blocks(4,5). Reading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * from page 0 of blocks (4,5) or from page 1 of blocks (4,5) gives the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * result, which is a logical and between bytes from page 0 and page 1 (which is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * consistent with the fact that writing to a page is _clearing_ bits of that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * page).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static void doc_set_reliable_mode(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static char *strmode[] = { "normal", "fast", "reliable", "invalid" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) doc_dbg("doc_set_reliable_mode(%s)\n", strmode[docg3->reliable]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) switch (docg3->reliable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) doc_flash_sequence(docg3, DOC_SEQ_SET_FASTMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) doc_flash_command(docg3, DOC_CMD_FAST_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) doc_flash_sequence(docg3, DOC_SEQ_SET_RELIABLEMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) doc_flash_command(docg3, DOC_CMD_FAST_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) doc_err("doc_set_reliable_mode(): invalid mode\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) doc_delay(docg3, 2);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * doc_set_asic_mode - Set the ASIC mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) * @mode: the mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * The ASIC can work in 3 modes :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * - RESET: all registers are zeroed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) * - NORMAL: receives and handles commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * - POWERDOWN: minimal poweruse, flash parts shut off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static void doc_set_asic_mode(struct docg3 *docg3, u8 mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) for (i = 0; i < 12; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) doc_readb(docg3, DOC_IOSPACE_IPL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) mode |= DOC_ASICMODE_MDWREN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) doc_dbg("doc_set_asic_mode(%02x)\n", mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) doc_writeb(docg3, mode, DOC_ASICMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) doc_writeb(docg3, ~mode, DOC_ASICMODECONFIRM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * doc_set_device_id - Sets the devices id for cascaded G3 chips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * @id: the chip to select (amongst 0, 1, 2, 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * There can be 4 cascaded G3 chips. This function selects the one which will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * should be the active one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static void doc_set_device_id(struct docg3 *docg3, int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) u8 ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) doc_dbg("doc_set_device_id(%d)\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) doc_writeb(docg3, id, DOC_DEVICESELECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) ctrl &= ~DOC_CTRL_VIOLATION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ctrl |= DOC_CTRL_CE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) doc_writeb(docg3, ctrl, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * doc_set_extra_page_mode - Change flash page layout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * Normally, the flash page is split into the data (512 bytes) and the out of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * band data (16 bytes). For each, 4 more bytes can be accessed, where the wear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * leveling counters are stored. To access this last area of 4 bytes, a special
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * mode must be input to the flash ASIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * Returns 0 if no error occurred, -EIO else.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int doc_set_extra_page_mode(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int fctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) doc_dbg("doc_set_extra_page_mode()\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) doc_flash_sequence(docg3, DOC_SEQ_PAGE_SIZE_532);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) doc_flash_command(docg3, DOC_CMD_PAGE_SIZE_532);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (fctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * doc_setup_addr_sector - Setup blocks/page/ofs address for one plane
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * @sector: the sector
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static void doc_setup_addr_sector(struct docg3 *docg3, int sector)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) doc_flash_address(docg3, sector & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) doc_flash_address(docg3, (sector >> 8) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) doc_flash_address(docg3, (sector >> 16) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * doc_setup_writeaddr_sector - Setup blocks/page/ofs address for one plane
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * @sector: the sector
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * @ofs: the offset in the page, between 0 and (512 + 16 + 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static void doc_setup_writeaddr_sector(struct docg3 *docg3, int sector, int ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) ofs = ofs >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) doc_flash_address(docg3, ofs & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) doc_flash_address(docg3, sector & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) doc_flash_address(docg3, (sector >> 8) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) doc_flash_address(docg3, (sector >> 16) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * doc_seek - Set both flash planes to the specified block, page for reading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * @block0: the first plane block index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) * @block1: the second plane block index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * @page: the page index within the block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * @wear: if true, read will occur on the 4 extra bytes of the wear area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * @ofs: offset in page to read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * Programs the flash even and odd planes to the specific block and page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * Alternatively, programs the flash to the wear area of the specified page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) static int doc_read_seek(struct docg3 *docg3, int block0, int block1, int page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int wear, int ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) int sector, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) doc_dbg("doc_seek(blocks=(%d,%d), page=%d, ofs=%d, wear=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) block0, block1, page, ofs, wear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (!wear && (ofs < 2 * DOC_LAYOUT_PAGE_SIZE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) doc_flash_command(docg3, DOC_CMD_READ_PLANE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) doc_flash_command(docg3, DOC_CMD_READ_PLANE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) doc_set_reliable_mode(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (wear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) ret = doc_set_extra_page_mode(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) doc_flash_sequence(docg3, DOC_SEQ_READ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) doc_setup_addr_sector(docg3, sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) doc_setup_addr_sector(docg3, sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * doc_write_seek - Set both flash planes to the specified block, page for writing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * @block0: the first plane block index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * @block1: the second plane block index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * @page: the page index within the block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * @ofs: offset in page to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * Programs the flash even and odd planes to the specific block and page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * Alternatively, programs the flash to the wear area of the specified page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static int doc_write_seek(struct docg3 *docg3, int block0, int block1, int page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) int ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int ret = 0, sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) doc_dbg("doc_write_seek(blocks=(%d,%d), page=%d, ofs=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) block0, block1, page, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) doc_set_reliable_mode(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (ofs < 2 * DOC_LAYOUT_PAGE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) doc_flash_command(docg3, DOC_CMD_READ_PLANE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) doc_flash_command(docg3, DOC_CMD_READ_PLANE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) doc_flash_sequence(docg3, DOC_SEQ_PAGE_SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) doc_flash_command(docg3, DOC_CMD_PROG_CYCLE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) doc_setup_writeaddr_sector(docg3, sector, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) doc_flash_command(docg3, DOC_CMD_PROG_CYCLE3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) ret = doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) doc_flash_command(docg3, DOC_CMD_PROG_CYCLE1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) doc_setup_writeaddr_sector(docg3, sector, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * doc_read_page_ecc_init - Initialize hardware ECC engine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * @len: the number of bytes covered by the ECC (BCH covered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * The function does initialize the hardware ECC engine to compute the Hamming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * ECC (on 1 byte) and the BCH hardware ECC (on 7 bytes).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * Return 0 if succeeded, -EIO on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) static int doc_read_page_ecc_init(struct docg3 *docg3, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) doc_writew(docg3, DOC_ECCCONF0_READ_MODE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) | (len & DOC_ECCCONF0_DATA_BYTES_MASK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) DOC_ECCCONF0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) doc_delay(docg3, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * doc_write_page_ecc_init - Initialize hardware BCH ECC engine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * @len: the number of bytes covered by the ECC (BCH covered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * The function does initialize the hardware ECC engine to compute the Hamming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * ECC (on 1 byte) and the BCH hardware ECC (on 7 bytes).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * Return 0 if succeeded, -EIO on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) static int doc_write_page_ecc_init(struct docg3 *docg3, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) doc_writew(docg3, DOC_ECCCONF0_WRITE_MODE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) | (len & DOC_ECCCONF0_DATA_BYTES_MASK),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) DOC_ECCCONF0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) doc_delay(docg3, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) return doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) * doc_ecc_disable - Disable Hamming and BCH ECC hardware calculator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) * Disables the hardware ECC generator and checker, for unchecked reads (as when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * reading OOB only or write status byte).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static void doc_ecc_disable(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) doc_writew(docg3, DOC_ECCCONF0_READ_MODE, DOC_ECCCONF0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) doc_delay(docg3, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) * doc_hamming_ecc_init - Initialize hardware Hamming ECC engine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * @nb_bytes: the number of bytes covered by the ECC (Hamming covered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * This function programs the ECC hardware to compute the hamming code on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) * last provided N bytes to the hardware generator.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) static void doc_hamming_ecc_init(struct docg3 *docg3, int nb_bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) u8 ecc_conf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) ecc_conf1 = doc_register_readb(docg3, DOC_ECCCONF1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ecc_conf1 &= ~DOC_ECCCONF1_HAMMING_BITS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) ecc_conf1 |= (nb_bytes & DOC_ECCCONF1_HAMMING_BITS_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) doc_writeb(docg3, ecc_conf1, DOC_ECCCONF1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * doc_ecc_bch_fix_data - Fix if need be read data from flash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * @buf: the buffer of read data (512 + 7 + 1 bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * @hwecc: the hardware calculated ECC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * It's in fact recv_ecc ^ calc_ecc, where recv_ecc was read from OOB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * area data, and calc_ecc the ECC calculated by the hardware generator.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * Checks if the received data matches the ECC, and if an error is detected,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * tries to fix the bit flips (at most 4) in the buffer buf. As the docg3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * understands the (data, ecc, syndroms) in an inverted order in comparison to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * the BCH library, the function reverses the order of bits (ie. bit7 and bit0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * bit6 and bit 1, ...) for all ECC data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * algorithm is used to decode this. However the hw operates on page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * data in a bit order that is the reverse of that of the bch alg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * requiring that the bits be reversed on the result. Thanks to Ivan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * Djelic for his analysis.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * Returns number of fixed bits (0, 1, 2, 3, 4) or -EBADMSG if too many bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * errors were detected and cannot be fixed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) u8 ecc[DOC_ECC_BCH_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) int errorpos[DOC_ECC_BCH_T], i, numerrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) ecc[i] = bitrev8(hwecc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) numerrs = bch_decode(docg3->cascade->bch, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) DOC_ECC_BCH_COVERED_BYTES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) NULL, ecc, NULL, errorpos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) BUG_ON(numerrs == -EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (numerrs < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) for (i = 0; i < numerrs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) errorpos[i] = (errorpos[i] & ~7) | (7 - (errorpos[i] & 7));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) for (i = 0; i < numerrs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (errorpos[i] < DOC_ECC_BCH_COVERED_BYTES*8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) /* error is located in data, correct it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) change_bit(errorpos[i], buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) doc_dbg("doc_ecc_bch_fix_data: flipped %d bits\n", numerrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return numerrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * doc_read_page_prepare - Prepares reading data from a flash page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * @block0: the first plane block index on flash memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * @block1: the second plane block index on flash memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) * @page: the page index in the block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) * @offset: the offset in the page (must be a multiple of 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * Prepares the page to be read in the flash memory :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * - tell ASIC to map the flash pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * - tell ASIC to be in read mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * After a call to this method, a call to doc_read_page_finish is mandatory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * to end the read cycle of the flash.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * Read data from a flash page. The length to be read must be between 0 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * (page_size + oob_size + wear_size), ie. 532, and a multiple of 4 (because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) * the extra bytes reading is not implemented).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * As pages are grouped by 2 (in 2 planes), reading from a page must be done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * in two steps:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * - one read of 512 bytes at offset 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * - one read of 512 bytes at offset 512 + 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * Returns 0 if successful, -EIO if a read error occurred.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) int page, int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) int wear_area = 0, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) doc_dbg("doc_read_page_prepare(blocks=(%d,%d), page=%d, ofsInPage=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) block0, block1, page, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (offset >= DOC_LAYOUT_WEAR_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) wear_area = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (!wear_area && offset > (DOC_LAYOUT_PAGE_OOB_SIZE * 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) ret = doc_reset_seq(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) /* Program the flash address block and page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) ret = doc_read_seek(docg3, block0, block1, page, wear_area, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) doc_flash_command(docg3, DOC_CMD_READ_ALL_PLANES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) doc_flash_command(docg3, DOC_CMD_SET_ADDR_READ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (offset >= DOC_LAYOUT_PAGE_SIZE * 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) offset -= 2 * DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) doc_flash_address(docg3, offset >> 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) doc_wait_ready(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) doc_flash_command(docg3, DOC_CMD_READ_FLASH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) doc_writeb(docg3, 0, DOC_DATAEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) * doc_read_page_getbytes - Reads bytes from a prepared page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) * @len: the number of bytes to be read (must be a multiple of 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) * @buf: the buffer to be filled in (or NULL is forget bytes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) * @first: 1 if first time read, DOC_READADDRESS should be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) * @last_odd: 1 if last read ended up on an odd byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) * Reads bytes from a prepared page. There is a trickery here : if the last read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) * ended up on an odd offset in the 1024 bytes double page, ie. between the 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) * planes, the first byte must be read apart. If a word (16bit) read was used,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) * the read would return the byte of plane 2 as low *and* high endian, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) * will mess the read.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) int first, int last_odd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (last_odd && len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) doc_read_data_area(docg3, buf, 1, first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) doc_read_data_area(docg3, buf, len, first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) * doc_write_page_putbytes - Writes bytes into a prepared page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) * @len: the number of bytes to be written
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) * @buf: the buffer of input bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) static void doc_write_page_putbytes(struct docg3 *docg3, int len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) const u_char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) doc_write_data_area(docg3, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) * doc_get_bch_hw_ecc - Get hardware calculated BCH ECC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) * @hwecc: the array of 7 integers where the hardware ecc will be stored
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) static void doc_get_bch_hw_ecc(struct docg3 *docg3, u8 *hwecc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) hwecc[i] = doc_register_readb(docg3, DOC_BCH_HW_ECC(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) * doc_page_finish - Ends reading/writing of a flash page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) static void doc_page_finish(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) doc_writeb(docg3, 0, DOC_DATAEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) * doc_read_page_finish - Ends reading of a flash page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * As a side effect, resets the chip selector to 0. This ensures that after each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * read operation, the floor 0 is selected. Therefore, if the systems halts, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) * reboot will boot on floor 0, where the IPL is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) static void doc_read_page_finish(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) doc_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * calc_block_sector - Calculate blocks, pages and ofs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * @from: offset in flash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * @block0: first plane block index calculated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) * @block1: second plane block index calculated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * @page: page calculated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * @ofs: offset in page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * @reliable: 0 if docg3 in normal mode, 1 if docg3 in fast mode, 2 if docg3 in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * reliable mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) * The calculation is based on the reliable/normal mode. In normal mode, the 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) * pages of a block are available. In reliable mode, as pages 2*n and 2*n+1 are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) * clones, only 32 pages per block are available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) static void calc_block_sector(loff_t from, int *block0, int *block1, int *page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) int *ofs, int reliable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) uint sector, pages_biblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) pages_biblock = DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) if (reliable == 1 || reliable == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) pages_biblock /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) sector = from / DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) *block0 = sector / pages_biblock * DOC_LAYOUT_NBPLANES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) *block1 = *block0 + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) *page = sector % pages_biblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) *page /= DOC_LAYOUT_NBPLANES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (reliable == 1 || reliable == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) *page *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (sector % 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) *ofs = DOC_LAYOUT_PAGE_OOB_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) *ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * doc_read_oob - Read out of band bytes from flash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * @mtd: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * @from: the offset from first block and first page, in bytes, aligned on page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) * @ops: the mtd oob structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) * Reads flash memory OOB area of pages.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) static int doc_read_oob(struct mtd_info *mtd, loff_t from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) struct mtd_oob_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) int block0, block1, page, ret, skip, ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) u8 *oobbuf = ops->oobbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) u8 *buf = ops->datbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) size_t len, ooblen, nbdata, nboob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) int max_bitflips = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) if (buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) len = ops->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (oobbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) ooblen = ops->ooblen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ooblen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) if (oobbuf && ops->mode == MTD_OPS_PLACE_OOB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) oobbuf += ops->ooboffs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) from, ops->mode, buf, len, oobbuf, ooblen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (ooblen % DOC_LAYOUT_OOB_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) ops->oobretlen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) ops->retlen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) skip = from % DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) while (ret >= 0 && (len > 0 || ooblen > 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) goto err_in_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (ret < skip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) goto err_in_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (ret < nbdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) goto err_in_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) doc_read_page_getbytes(docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) DOC_LAYOUT_PAGE_SIZE - nbdata - skip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) NULL, 0, (skip + nbdata) % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) if (ret < nboob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) goto err_in_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) NULL, 0, nboob % 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) doc_get_bch_hw_ecc(docg3, hwecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) if (nboob >= DOC_LAYOUT_OOB_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) doc_dbg("OOB - INFO: %*phC\n", 7, oobbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) doc_dbg("OOB - HAMMING: %02x\n", oobbuf[7]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) doc_dbg("OOB - BCH_ECC: %*phC\n", 7, oobbuf + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) doc_dbg("ECC HW_ECC: %*phC\n", 7, hwecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) if (is_prot_seq_error(docg3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) goto err_in_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if ((block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) (eccconf1 & DOC_ECCCONF1_PAGE_IS_WRITTEN) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) (ops->mode != MTD_OPS_RAW) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) (nbdata == DOC_LAYOUT_PAGE_SIZE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) ret = doc_ecc_bch_fix_data(docg3, buf, hwecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) mtd->ecc_stats.failed++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) ret = -EBADMSG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) if (ret > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) mtd->ecc_stats.corrected += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) max_bitflips = max(max_bitflips, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) ret = max_bitflips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) doc_read_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) ops->retlen += nbdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) ops->oobretlen += nboob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) buf += nbdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) oobbuf += nboob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) len -= nbdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) ooblen -= nboob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) from += DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) skip = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) err_in_read:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) doc_read_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static int doc_reload_bbt(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) int block = DOC_LAYOUT_BLOCK_BBT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) int ret = 0, nbpages, page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) u_char *buf = docg3->bbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) for (page = 0; !ret && (page < nbpages); page++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) ret = doc_read_page_prepare(docg3, block, block + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) page + DOC_LAYOUT_PAGE_BBT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) ret = doc_read_page_ecc_init(docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) DOC_LAYOUT_PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) buf, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) buf += DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) doc_read_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * doc_block_isbad - Checks whether a block is good or not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * @mtd: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * @from: the offset to find the correct block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * Returns 1 if block is bad, 0 if block is good
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) static int doc_block_isbad(struct mtd_info *mtd, loff_t from)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) int block0, block1, page, ofs, is_good;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) calc_block_sector(from, &block0, &block1, &page, &ofs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) from, block0, block1, page, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (block0 < DOC_LAYOUT_BLOCK_FIRST_DATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (block1 > docg3->max_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) is_good = docg3->bbt[block0 >> 3] & (1 << (block0 & 0x7));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) return !is_good;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * doc_get_erase_count - Get block erase count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) * @from: the offset in which the block is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) * Get the number of times a block was erased. The number is the maximum of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) * erase times between first and second plane (which should be equal normally).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) * Returns The number of erases, or -EINVAL or -EIO on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) static int doc_get_erase_count(struct docg3 *docg3, loff_t from)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) u8 buf[DOC_LAYOUT_WEAR_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) int ret, plane1_erase_count, plane2_erase_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) int block0, block1, page, ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) doc_dbg("doc_get_erase_count(from=%lld, buf=%p)\n", from, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) if (from % DOC_LAYOUT_PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) calc_block_sector(from, &block0, &block1, &page, &ofs, docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) if (block1 > docg3->max_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) ret = doc_reset_seq(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) ret = doc_read_page_prepare(docg3, block0, block1, page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) ofs + DOC_LAYOUT_WEAR_OFFSET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) buf, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) doc_read_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) plane1_erase_count = (u8)(~buf[1]) | ((u8)(~buf[4]) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) | ((u8)(~buf[5]) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) plane2_erase_count = (u8)(~buf[3]) | ((u8)(~buf[6]) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) | ((u8)(~buf[7]) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) return max(plane1_erase_count, plane2_erase_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) * doc_get_op_status - get erase/write operation status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) * Queries the status from the chip, and returns it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) * Returns the status (bits DOC_PLANES_STATUS_*)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) static int doc_get_op_status(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) u8 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) doc_flash_sequence(docg3, DOC_SEQ_PLANES_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) doc_flash_command(docg3, DOC_CMD_PLANES_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) doc_delay(docg3, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) doc_ecc_disable(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) doc_read_data_area(docg3, &status, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) * doc_write_erase_wait_status - wait for write or erase completion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) * Wait for the chip to be ready again after erase or write operation, and check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) * erase/write status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * Returns 0 if erase successful, -EIO if erase/write issue, -ETIMEOUT if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) static int doc_write_erase_wait_status(struct docg3 *docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) int i, status, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) for (i = 0; !doc_is_ready(docg3) && i < 5; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) msleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (!doc_is_ready(docg3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) doc_dbg("Timeout reached and the chip is still not ready\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) ret = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) status = doc_get_op_status(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (status & DOC_PLANES_STATUS_FAIL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) doc_dbg("Erase/Write failed on (a) plane(s), status = %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) doc_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * doc_erase_block - Erase a couple of blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) * @block0: the first block to erase (leftmost plane)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) * @block1: the second block to erase (rightmost plane)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) * Erase both blocks, and return operation status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) * Returns 0 if erase successful, -EIO if erase issue, -ETIMEOUT if chip not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) * ready for too long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) static int doc_erase_block(struct docg3 *docg3, int block0, int block1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) int ret, sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) doc_dbg("doc_erase_block(blocks=(%d,%d))\n", block0, block1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) ret = doc_reset_seq(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) doc_set_reliable_mode(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) doc_flash_sequence(docg3, DOC_SEQ_ERASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) sector = block0 << DOC_ADDR_BLOCK_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) doc_setup_addr_sector(docg3, sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) sector = block1 << DOC_ADDR_BLOCK_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) doc_setup_addr_sector(docg3, sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) doc_delay(docg3, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) doc_flash_command(docg3, DOC_CMD_ERASECYCLE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) if (is_prot_seq_error(docg3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) doc_err("Erase blocks %d,%d error\n", block0, block1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return doc_write_erase_wait_status(docg3);
^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) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) * doc_erase - Erase a portion of the chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) * @mtd: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) * @info: the erase info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) * Erase a bunch of contiguous blocks, by pairs, as a "mtd" page of 1024 is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) * split into 2 pages of 512 bytes on 2 contiguous blocks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) * Returns 0 if erase successful, -EINVAL if addressing error, -EIO if erase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) * issue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) uint64_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) int block0, block1, page, ret = 0, ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) doc_dbg("doc_erase(from=%lld, len=%lld\n", info->addr, info->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) calc_block_sector(info->addr + info->len, &block0, &block1, &page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) &ofs, docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) if (info->addr + info->len > mtd->size || page || ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) doc_set_reliable_mode(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) ret = doc_erase_block(docg3, block0, block1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) block0 += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) block1 += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) }
^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) * doc_write_page - Write a single page to the chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) * @to: the offset from first block and first page, in bytes, aligned on page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) * size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) * @buf: buffer to get bytes from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) * @oob: buffer to get out of band bytes from (can be NULL if no OOB should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) * written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) * @autoecc: if 0, all 16 bytes from OOB are taken, regardless of HW Hamming or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) * BCH computations. If 1, only bytes 0-7 and byte 15 are taken,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) * remaining ones are filled with hardware Hamming and BCH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) * computations. Its value is not meaningfull is oob == NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) * Write one full page (ie. 1 page split on two planes), of 512 bytes, with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) * OOB data. The OOB ECC is automatically computed by the hardware Hamming and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) * BCH generator if autoecc is not null.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) * Returns 0 if write successful, -EIO if write error, -EAGAIN if timeout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) static int doc_write_page(struct docg3 *docg3, loff_t to, const u_char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) const u_char *oob, int autoecc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) int block0, block1, page, ret, ofs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) u8 hwecc[DOC_ECC_BCH_SIZE], hamming;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) doc_dbg("doc_write_page(to=%lld)\n", to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) calc_block_sector(to, &block0, &block1, &page, &ofs, docg3->reliable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) ret = doc_reset_seq(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) /* Program the flash address block and page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) ret = doc_write_seek(docg3, block0, block1, page, ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) doc_write_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) doc_write_page_putbytes(docg3, DOC_LAYOUT_PAGE_SIZE, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) if (oob && autoecc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_PAGEINFO_SZ, oob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) oob += DOC_LAYOUT_OOB_UNUSED_OFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) hamming = doc_register_readb(docg3, DOC_HAMMINGPARITY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_HAMMING_SZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) &hamming);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) doc_get_bch_hw_ecc(docg3, hwecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_BCH_SZ, hwecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_UNUSED_SZ, oob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) if (oob && !autoecc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_SIZE, oob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) doc_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) doc_flash_command(docg3, DOC_CMD_PROG_CYCLE2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) doc_delay(docg3, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) * The wait status will perform another doc_page_finish() call, but that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) * seems to please the docg3, so leave it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) ret = doc_write_erase_wait_status(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) doc_read_page_finish(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) * doc_guess_autoecc - Guess autoecc mode from mbd_oob_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) * @ops: the oob operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) * Returns 0 or 1 if success, -EINVAL if invalid oob mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) static int doc_guess_autoecc(struct mtd_oob_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) int autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) switch (ops->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) case MTD_OPS_PLACE_OOB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) case MTD_OPS_AUTO_OOB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) autoecc = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) case MTD_OPS_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) autoecc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) autoecc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) return autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) * doc_fill_autooob - Fill a 16 bytes OOB from 8 non-ECC bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) * @dst: the target 16 bytes OOB buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) * @oobsrc: the source 8 bytes non-ECC OOB buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) static void doc_fill_autooob(u8 *dst, u8 *oobsrc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) memcpy(dst, oobsrc, DOC_LAYOUT_OOB_PAGEINFO_SZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) dst[DOC_LAYOUT_OOB_UNUSED_OFS] = oobsrc[DOC_LAYOUT_OOB_PAGEINFO_SZ];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * doc_backup_oob - Backup OOB into docg3 structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) * @docg3: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) * @to: the page offset in the chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) * @ops: the OOB size and buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) * As the docg3 should write a page with its OOB in one pass, and some userland
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) * applications do write_oob() to setup the OOB and then write(), store the OOB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) * into a temporary storage. This is very dangerous, as 2 concurrent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) * applications could store an OOB, and then write their pages (which will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) * result into one having its OOB corrupted).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) * The only reliable way would be for userland to call doc_write_oob() with both
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) * the page data _and_ the OOB area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) * Returns 0 if success, -EINVAL if ops content invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) static int doc_backup_oob(struct docg3 *docg3, loff_t to,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) struct mtd_oob_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) int ooblen = ops->ooblen, autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) if (ooblen != DOC_LAYOUT_OOB_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) autoecc = doc_guess_autoecc(ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) if (autoecc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) return autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) docg3->oob_write_ofs = to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) docg3->oob_autoecc = autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) if (ops->mode == MTD_OPS_AUTO_OOB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) doc_fill_autooob(docg3->oob_write_buf, ops->oobbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) ops->oobretlen = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) memcpy(docg3->oob_write_buf, ops->oobbuf, DOC_LAYOUT_OOB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) ops->oobretlen = DOC_LAYOUT_OOB_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) * doc_write_oob - Write out of band bytes to flash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) * @mtd: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) * @ofs: the offset from first block and first page, in bytes, aligned on page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) * size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) * @ops: the mtd oob structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) * Either write OOB data into a temporary buffer, for the subsequent write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) * page. The provided OOB should be 16 bytes long. If a data buffer is provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) * as well, issue the page write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) * Or provide data without OOB, and then a all zeroed OOB will be used (ECC will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) * still be filled in if asked for).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) * Returns 0 is successful, EINVAL if length is not 14 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) struct mtd_oob_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) int ret, autoecc, oobdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) u8 *oobbuf = ops->oobbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) u8 *buf = ops->datbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) size_t len, ooblen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) u8 oob[DOC_LAYOUT_OOB_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) if (buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) len = ops->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (oobbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) ooblen = ops->ooblen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) ooblen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) if (oobbuf && ops->mode == MTD_OPS_PLACE_OOB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) oobbuf += ops->ooboffs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) doc_dbg("doc_write_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) ofs, ops->mode, buf, len, oobbuf, ooblen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) switch (ops->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) case MTD_OPS_PLACE_OOB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) case MTD_OPS_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) oobdelta = mtd->oobsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) case MTD_OPS_AUTO_OOB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) oobdelta = mtd->oobavail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) (ofs % DOC_LAYOUT_PAGE_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) if (len && ooblen &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) ops->oobretlen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) ops->retlen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) if (len == 0 && ooblen == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) if (len == 0 && ooblen > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return doc_backup_oob(docg3, ofs, ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) autoecc = doc_guess_autoecc(ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (autoecc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) return autoecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) while (!ret && len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) memset(oob, 0, sizeof(oob));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) if (ofs == docg3->oob_write_ofs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) memcpy(oob, docg3->oob_write_buf, DOC_LAYOUT_OOB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) else if (ooblen > 0 && ops->mode == MTD_OPS_AUTO_OOB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) doc_fill_autooob(oob, oobbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) else if (ooblen > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) memcpy(oob, oobbuf, DOC_LAYOUT_OOB_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) ret = doc_write_page(docg3, ofs, buf, oob, autoecc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) ofs += DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) len -= DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) buf += DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) if (ooblen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) oobbuf += oobdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) ooblen -= oobdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) ops->oobretlen += oobdelta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) ops->retlen += DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) static struct docg3 *sysfs_dev2docg3(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) struct device_attribute *attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) int floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) struct mtd_info **docg3_floors = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) floor = attr->attr.name[1] - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) if (floor < 0 || floor >= DOC_MAX_NBFLOORS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) return docg3_floors[floor]->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) static ssize_t dps0_is_key_locked(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) int dps0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) static ssize_t dps1_is_key_locked(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) int dps1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) static ssize_t dps0_insert_key(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) static ssize_t dps1_insert_key(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) doc_set_device_id(docg3, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) #define FLOOR_SYSFS(id) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) __ATTR(f##id##_dps0_is_keylocked, S_IRUGO, dps0_is_key_locked, NULL), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) __ATTR(f##id##_dps1_is_keylocked, S_IRUGO, dps1_is_key_locked, NULL), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) __ATTR(f##id##_dps0_protection_key, S_IWUSR|S_IWGRP, NULL, dps0_insert_key), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) __ATTR(f##id##_dps1_protection_key, S_IWUSR|S_IWGRP, NULL, dps1_insert_key), \
^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) static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) FLOOR_SYSFS(0), FLOOR_SYSFS(1), FLOOR_SYSFS(2), FLOOR_SYSFS(3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) static int doc_register_sysfs(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) struct docg3_cascade *cascade)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) int floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) for (floor = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) floor < DOC_MAX_NBFLOORS && cascade->floors[floor];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) floor++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) goto remove_files;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) remove_files:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) while (--i >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) device_remove_file(dev, &doc_sys_attrs[floor][i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) i = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) } while (--floor >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) static void doc_unregister_sysfs(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) struct docg3_cascade *cascade)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) int floor, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) for (floor = 0; floor < DOC_MAX_NBFLOORS && cascade->floors[floor];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) floor++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) for (i = 0; i < 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) device_remove_file(dev, &doc_sys_attrs[floor][i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) * Debug sysfs entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) static int flashcontrol_show(struct seq_file *s, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) struct docg3 *docg3 = (struct docg3 *)s->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) u8 fctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) seq_printf(s, "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) fctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) fctrl & DOC_CTRL_CE ? "active" : "inactive",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) DEFINE_SHOW_ATTRIBUTE(flashcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) static int asic_mode_show(struct seq_file *s, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) struct docg3 *docg3 = (struct docg3 *)s->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) int pctrl, mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) pctrl = doc_register_readb(docg3, DOC_ASICMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) mode = pctrl & 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) seq_printf(s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) pctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) pctrl & DOC_ASICMODE_MDWREN ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) mode >> 1, mode & 0x1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) switch (mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) case DOC_ASICMODE_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) seq_puts(s, "reset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) case DOC_ASICMODE_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) seq_puts(s, "normal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) case DOC_ASICMODE_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) seq_puts(s, "powerdown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) seq_puts(s, ")\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) DEFINE_SHOW_ATTRIBUTE(asic_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) static int device_id_show(struct seq_file *s, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) struct docg3 *docg3 = (struct docg3 *)s->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) id = doc_register_readb(docg3, DOC_DEVICESELECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) seq_printf(s, "DeviceId = %d\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) DEFINE_SHOW_ATTRIBUTE(device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) static int protection_show(struct seq_file *s, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) struct docg3 *docg3 = (struct docg3 *)s->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) mutex_lock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) protect = doc_register_readb(docg3, DOC_PROTECTION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) dps0_low = doc_register_readw(docg3, DOC_DPS0_ADDRLOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) dps0_high = doc_register_readw(docg3, DOC_DPS0_ADDRHIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) dps1_low = doc_register_readw(docg3, DOC_DPS1_ADDRLOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) mutex_unlock(&docg3->cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) seq_printf(s, "Protection = 0x%02x (", protect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) seq_puts(s, "FOUNDRY_OTP_LOCK,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) seq_puts(s, "CUSTOMER_OTP_LOCK,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) if (protect & DOC_PROTECT_LOCK_INPUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) seq_puts(s, "LOCK_INPUT,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) if (protect & DOC_PROTECT_STICKY_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) seq_puts(s, "STICKY_LOCK,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) if (protect & DOC_PROTECT_PROTECTION_ENABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) seq_puts(s, "PROTECTION ON,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) seq_puts(s, "IPL_DOWNLOAD_LOCK,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) if (protect & DOC_PROTECT_PROTECTION_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) seq_puts(s, "PROTECT_ERR,");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) seq_puts(s, "NO_PROTECT_ERR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) seq_puts(s, ")\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) seq_printf(s, "DPS0 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) dps0, dps0_low, dps0_high,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) !!(dps0 & DOC_DPS_OTP_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) !!(dps0 & DOC_DPS_READ_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) !!(dps0 & DOC_DPS_WRITE_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) !!(dps0 & DOC_DPS_HW_LOCK_ENABLED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) !!(dps0 & DOC_DPS_KEY_OK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) seq_printf(s, "DPS1 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) dps1, dps1_low, dps1_high,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) !!(dps1 & DOC_DPS_OTP_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) !!(dps1 & DOC_DPS_READ_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) !!(dps1 & DOC_DPS_WRITE_PROTECTED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) !!(dps1 & DOC_DPS_HW_LOCK_ENABLED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) !!(dps1 & DOC_DPS_KEY_OK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) DEFINE_SHOW_ATTRIBUTE(protection);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) static void __init doc_dbg_register(struct mtd_info *floor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) struct dentry *root = floor->dbg.dfs_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) struct docg3 *docg3 = floor->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) if (IS_ERR_OR_NULL(root)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) if (IS_ENABLED(CONFIG_DEBUG_FS) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) !IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) dev_warn(floor->dev.parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) "CONFIG_MTD_PARTITIONED_MASTER must be enabled to expose debugfs stuff\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) debugfs_create_file("docg3_flashcontrol", S_IRUSR, root, docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) &flashcontrol_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) debugfs_create_file("docg3_asic_mode", S_IRUSR, root, docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) &asic_mode_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) debugfs_create_file("docg3_device_id", S_IRUSR, root, docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) &device_id_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) debugfs_create_file("docg3_protection", S_IRUSR, root, docg3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) &protection_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) * doc_set_driver_info - Fill the mtd_info structure and docg3 structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) * @chip_id: The chip ID of the supported chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) * @mtd: The structure to fill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) int cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) cfg = doc_register_readb(docg3, DOC_CONFIGURATION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) docg3->reliable = reliable_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) switch (chip_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) case DOC_CHIPID_G3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) mtd->name = devm_kasprintf(docg3->dev, GFP_KERNEL, "docg3.%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) if (!mtd->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) docg3->max_block = 2047;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) mtd->type = MTD_NANDFLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) mtd->flags = MTD_CAP_NANDFLASH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) if (docg3->reliable == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) mtd->size /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) if (docg3->reliable == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) mtd->erasesize /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) mtd->writebufsize = mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) mtd->_erase = doc_erase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) mtd->_read_oob = doc_read_oob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) mtd->_write_oob = doc_write_oob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) mtd->_block_isbad = doc_block_isbad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) mtd_set_ooblayout(mtd, &nand_ooblayout_docg3_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) mtd->oobavail = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) mtd->ecc_strength = DOC_ECC_BCH_T;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) * doc_probe_device - Check if a device is available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) * @base: the io space where the device is probed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) * @floor: the floor of the probed device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) * @dev: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) * @cascade: the cascade of chips this devices will belong to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) * Checks whether a device at the specified IO range, and floor is available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) * Returns a mtd_info struct if there is a device, ENODEV if none found, ENOMEM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) * if a memory allocation failed. If floor 0 is checked, a reset of the ASIC is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) * launched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) static struct mtd_info * __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) int ret, bbt_nbpages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) u16 chip_id, chip_id_inv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) struct docg3 *docg3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) if (!docg3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) goto nomem1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) if (!mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) goto nomem2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) mtd->priv = docg3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) mtd->dev.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) 8 * DOC_LAYOUT_PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) docg3->bbt = kcalloc(DOC_LAYOUT_PAGE_SIZE, bbt_nbpages, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) if (!docg3->bbt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) goto nomem3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) docg3->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) docg3->device_id = floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) docg3->cascade = cascade;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) doc_set_device_id(docg3, docg3->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) if (!floor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) doc_set_asic_mode(docg3, DOC_ASICMODE_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) chip_id = doc_register_readw(docg3, DOC_CHIPID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) if (chip_id != (u16)(~chip_id_inv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) goto nomem4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) switch (chip_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) case DOC_CHIPID_G3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) docg3->cascade->base, floor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) goto nomem4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) ret = doc_set_driver_info(chip_id, mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) goto nomem4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) doc_hamming_ecc_init(docg3, DOC_LAYOUT_OOB_PAGEINFO_SZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) doc_reload_bbt(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) return mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) nomem4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) kfree(docg3->bbt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) nomem3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) nomem2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) kfree(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) nomem1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) return ret ? ERR_PTR(ret) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) * doc_release_device - Release a docg3 floor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) * @mtd: the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) static void doc_release_device(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) struct docg3 *docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) mtd_device_unregister(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) kfree(docg3->bbt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) kfree(docg3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) kfree(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) * docg3_resume - Awakens docg3 floor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) * @pdev: platfrom device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) * Returns 0 (always successful)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) static int docg3_resume(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) struct docg3_cascade *cascade;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) struct mtd_info **docg3_floors, *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) struct docg3 *docg3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) cascade = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) docg3_floors = cascade->floors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) mtd = docg3_floors[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) doc_dbg("docg3_resume()\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) for (i = 0; i < 12; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) doc_readb(docg3, DOC_IOSPACE_IPL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) * docg3_suspend - Put in low power mode the docg3 floor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) * @pdev: platform device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) * @state: power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) * Shuts off most of docg3 circuitery to lower power consumption.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) * Returns 0 if suspend succeeded, -EIO if chip refused suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) static int docg3_suspend(struct platform_device *pdev, pm_message_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) int floor, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) struct docg3_cascade *cascade;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) struct mtd_info **docg3_floors, *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) struct docg3 *docg3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) u8 ctrl, pwr_down;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) cascade = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) docg3_floors = cascade->floors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) mtd = docg3_floors[floor];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) if (!mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) doc_writeb(docg3, floor, DOC_DEVICESELECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) ctrl &= ~DOC_CTRL_VIOLATION & ~DOC_CTRL_CE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) doc_writeb(docg3, ctrl, DOC_FLASHCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) for (i = 0; i < 10; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) usleep_range(3000, 4000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) pwr_down = doc_register_readb(docg3, DOC_POWERMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) if (pwr_down & DOC_POWERDOWN_READY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) if (pwr_down & DOC_POWERDOWN_READY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) doc_dbg("docg3_suspend(): floor %d powerdown ok\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) floor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) doc_err("docg3_suspend(): floor %d powerdown failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) floor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) mtd = docg3_floors[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) docg3 = mtd->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) doc_set_asic_mode(docg3, DOC_ASICMODE_POWERDOWN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) * doc_probe - Probe the IO space for a DiskOnChip G3 chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) * @pdev: platform device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) * Probes for a G3 chip at the specified IO space in the platform data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) * ressources. The floor 0 must be available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) * Returns 0 on success, -ENOMEM, -ENXIO on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) static int __init docg3_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) struct resource *ress;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) int ret, floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) struct docg3_cascade *cascade;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) if (!ress) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) dev_err(dev, "No I/O memory resource defined\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) cascade = devm_kcalloc(dev, DOC_MAX_NBFLOORS, sizeof(*cascade),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) if (!cascade)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) cascade->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) mutex_init(&cascade->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) cascade->bch = bch_init(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) DOC_ECC_BCH_PRIMPOLY, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) if (!cascade->bch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) mtd = doc_probe_device(cascade, floor, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) if (IS_ERR(mtd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) ret = PTR_ERR(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) goto err_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) if (!mtd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) if (floor == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) goto notfound;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) cascade->floors[floor] = mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) goto err_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) doc_dbg_register(cascade->floors[floor]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) ret = doc_register_sysfs(pdev, cascade);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) goto err_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) platform_set_drvdata(pdev, cascade);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) notfound:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) dev_info(dev, "No supported DiskOnChip found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) err_probe:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) bch_free(cascade->bch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) if (cascade->floors[floor])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) doc_release_device(cascade->floors[floor]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) * docg3_release - Release the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) * @pdev: the platform device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) * Returns 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) static int docg3_release(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) struct docg3_cascade *cascade = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) struct docg3 *docg3 = cascade->floors[0]->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) int floor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) doc_unregister_sysfs(pdev, cascade);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) if (cascade->floors[floor])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) doc_release_device(cascade->floors[floor]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) bch_free(docg3->cascade->bch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) static const struct of_device_id docg3_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) { .compatible = "m-systems,diskonchip-g3" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) MODULE_DEVICE_TABLE(of, docg3_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) static struct platform_driver g3_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) .name = "docg3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) .of_match_table = of_match_ptr(docg3_dt_ids),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) .suspend = docg3_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) .resume = docg3_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) .remove = docg3_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) module_platform_driver_probe(g3_driver, docg3_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) MODULE_DESCRIPTION("MTD driver for DiskOnChip G3");