drivers/memory/tegra/tegra20-emc.c

Source file repositories/reference/linux-study-clean/drivers/memory/tegra/tegra20-emc.c

File Facts

System
Linux kernel
Corpus path
drivers/memory/tegra/tegra20-emc.c
Extension
.c
Size
29036 bytes
Lines
1171
Domain
Driver Families
Bucket
drivers/memory
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 emc_timing {
	unsigned long rate;
	u32 data[ARRAY_SIZE(emc_timing_registers)];
};

struct tegra_emc {
	struct device *dev;
	struct tegra_mc *mc;
	struct icc_provider provider;
	struct notifier_block clk_nb;
	struct clk *clk;
	void __iomem *regs;
	unsigned int dram_bus_width;

	struct emc_timing *timings;
	unsigned int num_timings;

	struct {
		struct dentry *root;
		unsigned long min_rate;
		unsigned long max_rate;
	} debugfs;

	struct tegra_emc_rate_requests reqs;

	struct devfreq_simple_ondemand_data ondemand_data;

	/* memory chip identity information */
	union lpddr2_basic_config4 basic_conf4;
	unsigned int manufacturer_id;
	unsigned int revision_id1;
	unsigned int revision_id2;

	bool mrr_error;
};

static irqreturn_t tegra20_emc_isr(int irq, void *data)
{
	struct tegra_emc *emc = data;
	u32 intmask = EMC_REFRESH_OVERFLOW_INT;
	u32 status;

	status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask;
	if (!status)
		return IRQ_NONE;

	/* notify about HW problem */
	if (status & EMC_REFRESH_OVERFLOW_INT)
		dev_err_ratelimited(emc->dev,
				    "refresh request overflow timeout\n");

	/* clear interrupts */
	writel_relaxed(status, emc->regs + EMC_INTSTATUS);

	return IRQ_HANDLED;
}

static struct emc_timing *tegra20_emc_find_timing(struct tegra_emc *emc,
						  unsigned long rate)
{
	struct emc_timing *timing = NULL;
	unsigned int i;

	for (i = 0; i < emc->num_timings; i++) {
		if (emc->timings[i].rate >= rate) {
			timing = &emc->timings[i];
			break;
		}
	}

	if (!timing) {
		dev_err(emc->dev, "no timing for rate %lu\n", rate);
		return NULL;
	}

	return timing;
}

static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
{
	struct emc_timing *timing = tegra20_emc_find_timing(emc, rate);
	unsigned int i;

	if (!timing)
		return -EINVAL;

	dev_dbg(emc->dev, "%s: using timing rate %lu for requested rate %lu\n",
		__func__, timing->rate, rate);

	/* program shadow registers */

Annotation

Implementation Notes