drivers/mtd/nand/raw/hisi504_nand.c

Source file repositories/reference/linux-study-clean/drivers/mtd/nand/raw/hisi504_nand.c

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/hisi504_nand.c
Extension
.c
Size
23708 bytes
Lines
870
Domain
Driver Families
Bucket
drivers/mtd
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct hinfc_host {
	struct nand_chip	chip;
	struct device		*dev;
	void __iomem		*iobase;
	void __iomem		*mmio;
	struct completion       cmd_complete;
	unsigned int		offset;
	unsigned int		command;
	int			chipselect;
	unsigned int		addr_cycle;
	u32                     addr_value[2];
	u32                     cache_addr_value[2];
	char			*buffer;
	dma_addr_t		dma_buffer;
	dma_addr_t		dma_oob;
	int			version;
	unsigned int            irq_status; /* interrupt status */
};

static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
{
	return readl(host->iobase + reg);
}

static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
			       unsigned int reg)
{
	writel(value, host->iobase + reg);
}

static void wait_controller_finished(struct hinfc_host *host)
{
	unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
	int val;

	while (time_before(jiffies, timeout)) {
		val = hinfc_read(host, HINFC504_STATUS);
		if (host->command == NAND_CMD_ERASE2) {
			/* nfc is ready */
			while (!(val & HINFC504_READY))	{
				usleep_range(500, 1000);
				val = hinfc_read(host, HINFC504_STATUS);
			}
			return;
		}

		if (val & HINFC504_READY)
			return;
	}

	/* wait cmd timeout */
	dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
}

static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
{
	struct nand_chip *chip = &host->chip;
	struct mtd_info	*mtd = nand_to_mtd(chip);
	unsigned long val;
	int ret;

	hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
	hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);

	if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_NONE) {
		hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
			<< HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);

		hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
			| HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
	} else {
		if (host->command == NAND_CMD_READOOB)
			hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
			| HINFC504_DMA_PARA_OOB_EDC_EN
			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
		else
			hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
			| HINFC504_DMA_PARA_OOB_RW_EN
			| HINFC504_DMA_PARA_DATA_EDC_EN
			| HINFC504_DMA_PARA_OOB_EDC_EN
			| HINFC504_DMA_PARA_DATA_ECC_EN
			| HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);

	}

	val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
		| HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
		| HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
		| ((host->addr_cycle == 4 ? 1 : 0)
			<< HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)

Annotation

Implementation Notes