drivers/mtd/nand/raw/ingenic/jz4740_ecc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mtd/nand/raw/ingenic/jz4740_ecc.c
Extension
.c
Size
5145 bytes
Lines
198
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

// SPDX-License-Identifier: GPL-2.0
/*
 * JZ4740 ECC controller driver
 *
 * Copyright (c) 2019 Paul Cercueil <paul@crapouillou.net>
 *
 * based on jz4740-nand.c
 */

#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>

#include "ingenic_ecc.h"

#define JZ_REG_NAND_ECC_CTRL	0x00
#define JZ_REG_NAND_DATA	0x04
#define JZ_REG_NAND_PAR0	0x08
#define JZ_REG_NAND_PAR1	0x0C
#define JZ_REG_NAND_PAR2	0x10
#define JZ_REG_NAND_IRQ_STAT	0x14
#define JZ_REG_NAND_IRQ_CTRL	0x18
#define JZ_REG_NAND_ERR(x)	(0x1C + ((x) << 2))

#define JZ_NAND_ECC_CTRL_PAR_READY	BIT(4)
#define JZ_NAND_ECC_CTRL_ENCODING	BIT(3)
#define JZ_NAND_ECC_CTRL_RS		BIT(2)
#define JZ_NAND_ECC_CTRL_RESET		BIT(1)
#define JZ_NAND_ECC_CTRL_ENABLE		BIT(0)

#define JZ_NAND_STATUS_ERR_COUNT	(BIT(31) | BIT(30) | BIT(29))
#define JZ_NAND_STATUS_PAD_FINISH	BIT(4)
#define JZ_NAND_STATUS_DEC_FINISH	BIT(3)
#define JZ_NAND_STATUS_ENC_FINISH	BIT(2)
#define JZ_NAND_STATUS_UNCOR_ERROR	BIT(1)
#define JZ_NAND_STATUS_ERROR		BIT(0)

static const uint8_t empty_block_ecc[] = {
	0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f
};

static void jz4740_ecc_reset(struct ingenic_ecc *ecc, bool calc_ecc)
{
	uint32_t reg;

	/* Clear interrupt status */
	writel(0, ecc->base + JZ_REG_NAND_IRQ_STAT);

	/* Initialize and enable ECC hardware */
	reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
	reg |= JZ_NAND_ECC_CTRL_RESET;
	reg |= JZ_NAND_ECC_CTRL_ENABLE;
	reg |= JZ_NAND_ECC_CTRL_RS;
	if (calc_ecc) /* calculate ECC from data */
		reg |= JZ_NAND_ECC_CTRL_ENCODING;
	else /* correct data from ECC */
		reg &= ~JZ_NAND_ECC_CTRL_ENCODING;

	writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);
}

static int jz4740_ecc_calculate(struct ingenic_ecc *ecc,
				struct ingenic_ecc_params *params,
				const u8 *buf, u8 *ecc_code)
{
	uint32_t reg, status;
	unsigned int timeout = 1000;
	int i;

	jz4740_ecc_reset(ecc, true);

	do {
		status = readl(ecc->base + JZ_REG_NAND_IRQ_STAT);
	} while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout);

	if (timeout == 0)
		return -ETIMEDOUT;

	reg = readl(ecc->base + JZ_REG_NAND_ECC_CTRL);
	reg &= ~JZ_NAND_ECC_CTRL_ENABLE;
	writel(reg, ecc->base + JZ_REG_NAND_ECC_CTRL);

	for (i = 0; i < params->bytes; ++i)
		ecc_code[i] = readb(ecc->base + JZ_REG_NAND_PAR0 + i);

	/*
	 * If the written data is completely 0xff, we also want to write 0xff as

Annotation

Implementation Notes