// SPDX-License-Identifier: GPL-2.0
//
// Driver for the SPI-NAND mode of Mediatek NAND Flash Interface
//
// Copyright (c) 2022 Chuanhong Guo <gch981213@gmail.com>
//
// This driver is based on the SPI-NAND mtd driver from Mediatek SDK:
//
// Copyright (C) 2020 MediaTek Inc.
// Author: Weijie Gao <weijie.gao@mediatek.com>
//
// This controller organize the page data as several interleaved sectors
// like the following: (sizeof(FDM + ECC) = snf->nfi_cfg.spare_size)
// +---------+------+------+---------+------+------+-----+
// | Sector1 | FDM1 | ECC1 | Sector2 | FDM2 | ECC2 | ... |
// +---------+------+------+---------+------+------+-----+
// With auto-format turned on, DMA only returns this part:
// +---------+---------+-----+
// | Sector1 | Sector2 | ... |
// +---------+---------+-----+
// The FDM data will be filled to the registers, and ECC parity data isn't
// accessible.
// With auto-format off, all ((Sector+FDM+ECC)*nsectors) will be read over DMA
// in it's original order shown in the first table. ECC can't be turned on when
// auto-format is off.
//
// However, Linux SPI-NAND driver expects the data returned as:
// +------+-----+
// | Page | OOB |
// +------+-----+
// where the page data is continuously stored instead of interleaved.
// So we assume all instructions matching the page_op template between ECC
// prepare_io_req and finish_io_req are for page cache r/w.
// Here's how this spi-mem driver operates when reading:
// 1. Always set snf->autofmt = true in prepare_io_req (even when ECC is off).
// 2. Perform page ops and let the controller fill the DMA bounce buffer with
// de-interleaved sector data and set FDM registers.
// 3. Return the data as:
// +---------+---------+-----+------+------+-----+
// | Sector1 | Sector2 | ... | FDM1 | FDM2 | ... |
// +---------+---------+-----+------+------+-----+
// 4. For other matching spi_mem ops outside a prepare/finish_io_req pair,
// read the data with auto-format off into the bounce buffer and copy
// needed data to the buffer specified in the request.
//
// Write requests operates in a similar manner.
// As a limitation of this strategy, we won't be able to access any ECC parity
// data at all in Linux.
//
// Here's the bad block mark situation on MTK chips:
// In older chips like mt7622, MTK uses the first FDM byte in the first sector
// as the bad block mark. After de-interleaving, this byte appears at [pagesize]
// in the returned data, which is the BBM position expected by kernel. However,
// the conventional bad block mark is the first byte of the OOB, which is part
// of the last sector data in the interleaved layout. Instead of fixing their
// hardware, MTK decided to address this inconsistency in software. On these
// later chips, the BootROM expects the following:
// 1. The [pagesize] byte on a nand page is used as BBM, which will appear at
// (page_size - (nsectors - 1) * spare_size) in the DMA buffer.
// 2. The original byte s