Commit 10de2114 authored by Joseph Lo's avatar Joseph Lo Committed by Thierry Reding
Browse files

memory: tegra: Add EMC scaling support code for Tegra210



This is the initial patch for Tegra210 EMC frequency scaling. It has the
code to program various aspects of the EMC that are standardized, but it
does not yet include the specific programming sequence needed for clock
scaling.

The driver is designed to support LPDDR4 SDRAM. Devices that use LPDDR4
need to perform training of the RAM before it can be used. Firmware will
perform this training during early boot and pass a table of supported
frequencies to the kernel via device tree.

For the frequencies above 800 MHz, periodic retraining is needed to
compensate for changes in timing. This periodic training will have to be
performed until the frequency drops back to or below 800 MHz.

This driver provides helpers used during this runtime retraining that
will be used by the sequence specific code in a follow-up patch.

Based on work by Peter De Schrijver <pdeschrijver@nvidia.com>.

Signed-off-by: default avatarJoseph Lo <josephl@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 6cc8823a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -36,3 +36,17 @@ config TEGRA124_EMC
	  Tegra124 chips. The EMC controls the external DRAM on the board.
	  This driver is required to change memory timings / clock rate for
	  external memory.

config TEGRA210_EMC_TABLE
	bool
	depends on ARCH_TEGRA_210_SOC

config TEGRA210_EMC
	tristate "NVIDIA Tegra210 External Memory Controller driver"
	depends on TEGRA_MC && ARCH_TEGRA_210_SOC
	select TEGRA210_EMC_TABLE
	help
	  This driver is for the External Memory Controller (EMC) found on
	  Tegra210 chips. The EMC controls the external DRAM on the board.
	  This driver is required to change memory timings / clock rate for
	  external memory.
+4 −0
Original line number Diff line number Diff line
@@ -13,5 +13,9 @@ obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
obj-$(CONFIG_TEGRA20_EMC)  += tegra20-emc.o
obj-$(CONFIG_TEGRA30_EMC)  += tegra30-emc.o
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o
obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o tegra186-emc.o
obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra186-emc.o

tegra210-emc-y := tegra210-emc-core.o
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#define MC_EMEM_ARB_TIMING_W2W				0xbc
#define MC_EMEM_ARB_TIMING_R2W				0xc0
#define MC_EMEM_ARB_TIMING_W2R				0xc4
#define MC_EMEM_ARB_MISC2				0xc8
#define MC_EMEM_ARB_DA_TURNS				0xd0
#define MC_EMEM_ARB_DA_COVERS				0xd4
#define MC_EMEM_ARB_MISC0				0xd8
+1809 −0

File added.

Preview size limit exceeded, changes collapsed.

+59 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
 */

#include <linux/of_reserved_mem.h>

#include "tegra210-emc.h"

#define TEGRA_EMC_MAX_FREQS		16

static int tegra210_emc_table_device_init(struct reserved_mem *rmem,
					  struct device *dev)
{
	struct tegra210_emc *emc = dev_get_drvdata(dev);
	unsigned int i;

	emc->timings = memremap(rmem->base, rmem->size, MEMREMAP_WB);
	if (!emc->timings) {
		dev_err(dev, "failed to map EMC table\n");
		return -ENOMEM;
	}

	emc->num_timings = 0;

	for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) {
		if (emc->timings[i].revision == 0)
			break;

		emc->num_timings++;
	}

	return 0;
}

static void tegra210_emc_table_device_release(struct reserved_mem *rmem,
					      struct device *dev)
{
	struct tegra210_emc *emc = dev_get_drvdata(dev);

	memunmap(emc->timings);
}

static const struct reserved_mem_ops tegra210_emc_table_ops = {
	.device_init = tegra210_emc_table_device_init,
	.device_release = tegra210_emc_table_device_release,
};

static int tegra210_emc_table_init(struct reserved_mem *rmem)
{
	pr_debug("Tegra210 EMC table at %pa, size %lu bytes\n", &rmem->base,
		 (unsigned long)rmem->size);

	rmem->ops = &tegra210_emc_table_ops;

	return 0;
}
RESERVEDMEM_OF_DECLARE(tegra210_emc_table, "nvidia,tegra210-emc-table",
		       tegra210_emc_table_init);
Loading