drivers/ata/ahci_brcm.c

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

File Facts

System
Linux kernel
Corpus path
drivers/ata/ahci_brcm.c
Extension
.c
Size
15613 bytes
Lines
591
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 brcm_ahci_priv {
	struct device *dev;
	void __iomem *top_ctrl;
	u32 port_mask;
	u32 quirks;
	enum brcm_ahci_version version;
	struct reset_control *rcdev_rescal;
	struct reset_control *rcdev_ahci;
};

static inline u32 brcm_sata_readreg(void __iomem *addr)
{
	/*
	 * MIPS endianness is configured by boot strap, which also reverses all
	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
	 * endian I/O).
	 *
	 * Other architectures (e.g., ARM) either do not support big endian, or
	 * else leave I/O in little endian mode.
	 */
	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
		return __raw_readl(addr);
	else
		return readl_relaxed(addr);
}

static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
{
	/* See brcm_sata_readreg() comments */
	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
		__raw_writel(val, addr);
	else
		writel_relaxed(val, addr);
}

static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
{
	struct brcm_ahci_priv *priv = hpriv->plat_data;
	u32 port_ctrl, host_caps;
	int i;

	/* Enable support for ALPM */
	host_caps = readl(hpriv->mmio + HOST_CAP);
	if (!(host_caps & HOST_CAP_ALPM))
		hpriv->flags |= AHCI_HFLAG_YES_ALPM;

	/*
	 * Adjust timeout to allow PLL sufficient time to lock while waking
	 * up from slumber mode.
	 */
	for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
	     i < SATA_TOP_MAX_PHYS;
	     i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
		if (priv->port_mask & BIT(i))
			writel(0xff1003fc,
			       hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
	}
}

static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
{
	void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
				(port * SATA_TOP_CTRL_PHY_OFFS);
	void __iomem *p;
	u32 reg;

	if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
		return;

	/* clear PHY_DEFAULT_POWER_STATE */
	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
	reg = brcm_sata_readreg(p);
	reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
	brcm_sata_writereg(reg, p);

	/* reset the PHY digital logic */
	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
	reg = brcm_sata_readreg(p);
	reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
		 SATA_TOP_CTRL_2_SW_RST_RX);
	reg |= SATA_TOP_CTRL_2_SW_RST_TX;
	brcm_sata_writereg(reg, p);
	reg = brcm_sata_readreg(p);
	reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
	brcm_sata_writereg(reg, p);
	reg = brcm_sata_readreg(p);
	reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
	brcm_sata_writereg(reg, p);
	(void)brcm_sata_readreg(p);
}

Annotation

Implementation Notes