drivers/ata/ahci_qoriq.c

Source file repositories/reference/linux-study-clean/drivers/ata/ahci_qoriq.c

File Facts

System
Linux kernel
Corpus path
drivers/ata/ahci_qoriq.c
Extension
.c
Size
10398 bytes
Lines
373
Domain
Driver Families
Bucket
drivers/ata
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 ahci_qoriq_priv {
	struct ccsr_ahci *reg_base;
	enum ahci_qoriq_type type;
	void __iomem *ecc_addr;
	bool is_dmacoherent;
};

static bool ecc_initialized;

static const struct of_device_id ahci_qoriq_of_match[] = {
	{ .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A},
	{ .compatible = "fsl,ls1028a-ahci", .data = (void *)AHCI_LS1028A},
	{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
	{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
	{ .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
	{ .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
	{ .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
	{ .compatible = "fsl,lx2160a-ahci", .data = (void *)AHCI_LX2160A},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);

static const struct acpi_device_id ahci_qoriq_acpi_match[] = {
	{"NXP0004", .driver_data = (kernel_ulong_t)AHCI_LX2160A},
	{ }
};
MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);

static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
			  unsigned long deadline)
{
	const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
	void __iomem *port_mmio = ahci_port_base(link->ap);
	u32 px_cmd, px_is, px_val;
	struct ata_port *ap = link->ap;
	struct ahci_port_priv *pp = ap->private_data;
	struct ahci_host_priv *hpriv = ap->host->private_data;
	struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data;
	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
	struct ata_taskfile tf;
	bool online;
	int rc;
	bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);

	hpriv->stop_engine(ap);

	/*
	 * There is a errata on ls1021a Rev1.0 and Rev2.0 which is:
	 * A-009042: The device detection initialization sequence
	 * mistakenly resets some registers.
	 *
	 * Workaround for this is:
	 * The software should read and store PxCMD and PxIS values
	 * before issuing the device detection initialization sequence.
	 * After the sequence is complete, software should restore the
	 * PxCMD and PxIS with the stored values.
	 */
	if (ls1021a_workaround) {
		px_cmd = readl(port_mmio + PORT_CMD);
		px_is = readl(port_mmio + PORT_IRQ_STAT);
	}

	/* clear D2H reception area to properly wait for D2H FIS */
	ata_tf_init(link->device, &tf);
	tf.status = ATA_BUSY;
	ata_tf_to_fis(&tf, 0, 0, d2h_fis);

	rc = sata_link_hardreset(link, timing, deadline, &online,
				 ahci_check_ready);

	/* restore the PxCMD and PxIS on ls1021 */
	if (ls1021a_workaround) {
		px_val = readl(port_mmio + PORT_CMD);
		if (px_val != px_cmd)
			writel(px_cmd, port_mmio + PORT_CMD);

		px_val = readl(port_mmio + PORT_IRQ_STAT);
		if (px_val != px_is)
			writel(px_is, port_mmio + PORT_IRQ_STAT);
	}

	hpriv->start_engine(ap);

	if (online)
		*class = ahci_dev_classify(ap);
	return rc;
}

static struct ata_port_operations ahci_qoriq_ops = {
	.inherits		= &ahci_ops,

Annotation

Implementation Notes