162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Broadcom specific AMBA
362306a36Sopenharmony_ci * ChipCommon NAND flash interface
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "bcma_private.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/platform_data/brcmnand.h>
1362306a36Sopenharmony_ci#include <linux/bcma/bcma.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Alternate NAND controller driver name in order to allow both bcm47xxnflash
1662306a36Sopenharmony_ci * and bcma_brcmnand to be built into the same kernel image.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_cistatic const char *bcma_nflash_alt_name = "bcma_brcmnand";
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct platform_device bcma_nflash_dev = {
2162306a36Sopenharmony_ci	.name		= "bcma_nflash",
2262306a36Sopenharmony_ci	.num_resources	= 0,
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const char *probes[] = { "bcm47xxpart", NULL };
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Initialize NAND flash access */
2862306a36Sopenharmony_ciint bcma_nflash_init(struct bcma_drv_cc *cc)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
3162306a36Sopenharmony_ci	u32 reg;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
3462306a36Sopenharmony_ci	    cc->core->id.rev != 38) {
3562306a36Sopenharmony_ci		bcma_err(bus, "NAND flash on unsupported board!\n");
3662306a36Sopenharmony_ci		return -ENOTSUPP;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
4062306a36Sopenharmony_ci		bcma_err(bus, "NAND flash not present according to ChipCommon\n");
4162306a36Sopenharmony_ci		return -ENODEV;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	cc->nflash.present = true;
4562306a36Sopenharmony_ci	if (cc->core->id.rev == 38 &&
4662306a36Sopenharmony_ci	    (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)) {
4762306a36Sopenharmony_ci		cc->nflash.boot = true;
4862306a36Sopenharmony_ci		/* Determine the chip select that is being used */
4962306a36Sopenharmony_ci		reg = bcma_cc_read32(cc, BCMA_CC_NAND_CS_NAND_SELECT) & 0xff;
5062306a36Sopenharmony_ci		cc->nflash.brcmnand_info.chip_select = ffs(reg) - 1;
5162306a36Sopenharmony_ci		cc->nflash.brcmnand_info.part_probe_types = probes;
5262306a36Sopenharmony_ci		cc->nflash.brcmnand_info.ecc_stepsize = 512;
5362306a36Sopenharmony_ci		cc->nflash.brcmnand_info.ecc_strength = 1;
5462306a36Sopenharmony_ci		bcma_nflash_dev.name = bcma_nflash_alt_name;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Prepare platform device, but don't register it yet. It's too early,
5862306a36Sopenharmony_ci	 * malloc (required by device_private_init) is not available yet. */
5962306a36Sopenharmony_ci	bcma_nflash_dev.dev.platform_data = &cc->nflash;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
63