162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017 Free Electrons
462306a36Sopenharmony_ci * Copyright (C) 2017 NextThing Co
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "internals.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic void amd_nand_decode_id(struct nand_chip *chip)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	struct mtd_info *mtd = nand_to_mtd(chip);
1462306a36Sopenharmony_ci	struct nand_memory_organization *memorg;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	memorg = nanddev_get_memorg(&chip->base);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	nand_decode_ext_id(chip);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	/*
2162306a36Sopenharmony_ci	 * Check for Spansion/AMD ID + repeating 5th, 6th byte since
2262306a36Sopenharmony_ci	 * some Spansion chips have erasesize that conflicts with size
2362306a36Sopenharmony_ci	 * listed in nand_ids table.
2462306a36Sopenharmony_ci	 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
2762306a36Sopenharmony_ci	    chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
2862306a36Sopenharmony_ci	    memorg->pagesize == 512) {
2962306a36Sopenharmony_ci		memorg->pages_per_eraseblock = 256;
3062306a36Sopenharmony_ci		memorg->pages_per_eraseblock <<= ((chip->id.data[3] & 0x03) << 1);
3162306a36Sopenharmony_ci		mtd->erasesize = memorg->pages_per_eraseblock *
3262306a36Sopenharmony_ci				 memorg->pagesize;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int amd_nand_init(struct nand_chip *chip)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	if (nand_is_slc(chip))
3962306a36Sopenharmony_ci		/*
4062306a36Sopenharmony_ci		 * According to the datasheet of some Cypress SLC NANDs,
4162306a36Sopenharmony_ci		 * the bad block markers can be in the first, second or last
4262306a36Sopenharmony_ci		 * page of a block. So let's check all three locations.
4362306a36Sopenharmony_ci		 */
4462306a36Sopenharmony_ci		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE |
4562306a36Sopenharmony_ci				 NAND_BBM_LASTPAGE;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return 0;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciconst struct nand_manufacturer_ops amd_nand_manuf_ops = {
5162306a36Sopenharmony_ci	.detect = amd_nand_decode_id,
5262306a36Sopenharmony_ci	.init = amd_nand_init,
5362306a36Sopenharmony_ci};
54