drivers/ata/ahci_da850.c

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

File Facts

System
Linux kernel
Corpus path
drivers/ata/ahci_da850.c
Extension
.c
Size
6395 bytes
Lines
253
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

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * DaVinci DA850 AHCI SATA platform driver
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include "ahci.h"

#define DRV_NAME		"ahci_da850"
#define HARDRESET_RETRIES	5

/* SATA PHY Control Register offset from AHCI base */
#define SATA_P0PHYCR_REG	0x178

#define SATA_PHY_MPY(x)		((x) << 0)
#define SATA_PHY_LOS(x)		((x) << 6)
#define SATA_PHY_RXCDR(x)	((x) << 10)
#define SATA_PHY_RXEQ(x)	((x) << 13)
#define SATA_PHY_TXSWING(x)	((x) << 19)
#define SATA_PHY_ENPLL(x)	((x) << 31)

static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
			    void __iomem *ahci_base, u32 mpy)
{
	unsigned int val;

	/* Enable SATA clock receiver */
	val = readl(pwrdn_reg);
	val &= ~BIT(0);
	writel(val, pwrdn_reg);

	val = SATA_PHY_MPY(mpy) | SATA_PHY_LOS(1) | SATA_PHY_RXCDR(4) |
	      SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) | SATA_PHY_ENPLL(1);

	writel(val, ahci_base + SATA_P0PHYCR_REG);
}

static u32 ahci_da850_calculate_mpy(unsigned long refclk_rate)
{
	u32 pll_output = 1500000000, needed;

	/*
	 * We need to determine the value of the multiplier (MPY) bits.
	 * In order to include the 12.5 multiplier we need to first divide
	 * the refclk rate by ten.
	 *
	 * __div64_32() turned out to be unreliable, sometimes returning
	 * false results.
	 */
	WARN((refclk_rate % 10) != 0, "refclk must be divisible by 10");
	needed = pll_output / (refclk_rate / 10);

	/*
	 * What we have now is (multiplier * 10).
	 *
	 * Let's determine the actual register value we need to write.
	 */

	switch (needed) {
	case 50:
		return 0x1;
	case 60:
		return 0x2;
	case 80:
		return 0x4;
	case 100:
		return 0x5;
	case 120:
		return 0x6;
	case 125:
		return 0x7;
	case 150:
		return 0x8;
	case 200:
		return 0x9;
	case 250:
		return 0xa;
	default:
		/*
		 * We should have divided evenly - if not, return an invalid
		 * value.
		 */
		return 0;
	}

Annotation

Implementation Notes