forked from Minki/linux
memory: tegra: Introduce Tegra30 EMC driver
Introduce driver for the External Memory Controller (EMC) found on Tegra30 chips, it controls the external DRAM on the board. The purpose of this driver is to program memory timing for external memory on the EMC clock rate change. Acked-by: Peter De Schrijver <pdeschrijver@nvidia.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Tested-by: Peter Geis <pgwipeout@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
88c5bfecaa
commit
e34212c75a
@ -17,6 +17,16 @@ config TEGRA20_EMC
|
|||||||
This driver is required to change memory timings / clock rate for
|
This driver is required to change memory timings / clock rate for
|
||||||
external memory.
|
external memory.
|
||||||
|
|
||||||
|
config TEGRA30_EMC
|
||||||
|
bool "NVIDIA Tegra30 External Memory Controller driver"
|
||||||
|
default y
|
||||||
|
depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
|
||||||
|
help
|
||||||
|
This driver is for the External Memory Controller (EMC) found on
|
||||||
|
Tegra30 chips. The EMC controls the external DRAM on the board.
|
||||||
|
This driver is required to change memory timings / clock rate for
|
||||||
|
external memory.
|
||||||
|
|
||||||
config TEGRA124_EMC
|
config TEGRA124_EMC
|
||||||
bool "NVIDIA Tegra124 External Memory Controller driver"
|
bool "NVIDIA Tegra124 External Memory Controller driver"
|
||||||
default y
|
default y
|
||||||
|
@ -11,5 +11,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
|||||||
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
|
||||||
|
|
||||||
obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o
|
obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o
|
||||||
|
obj-$(CONFIG_TEGRA30_EMC) += tegra30-emc.o
|
||||||
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
|
obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o
|
||||||
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o
|
||||||
|
@ -49,9 +49,6 @@
|
|||||||
#define MC_EMEM_ADR_CFG 0x54
|
#define MC_EMEM_ADR_CFG 0x54
|
||||||
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||||
|
|
||||||
#define MC_TIMING_CONTROL 0xfc
|
|
||||||
#define MC_TIMING_UPDATE BIT(0)
|
|
||||||
|
|
||||||
static const struct of_device_id tegra_mc_of_match[] = {
|
static const struct of_device_id tegra_mc_of_match[] = {
|
||||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||||
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
|
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
|
||||||
@ -308,7 +305,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct tegra_mc_timing *timing = NULL;
|
struct tegra_mc_timing *timing = NULL;
|
||||||
@ -323,11 +320,13 @@ void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
|||||||
if (!timing) {
|
if (!timing) {
|
||||||
dev_err(mc->dev, "no memory timing registered for rate %lu\n",
|
dev_err(mc->dev, "no memory timing registered for rate %lu\n",
|
||||||
rate);
|
rate);
|
||||||
return;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < mc->soc->num_emem_regs; ++i)
|
for (i = 0; i < mc->soc->num_emem_regs; ++i)
|
||||||
mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]);
|
mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
|
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
|
||||||
|
@ -6,20 +6,32 @@
|
|||||||
#ifndef MEMORY_TEGRA_MC_H
|
#ifndef MEMORY_TEGRA_MC_H
|
||||||
#define MEMORY_TEGRA_MC_H
|
#define MEMORY_TEGRA_MC_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include <soc/tegra/mc.h>
|
#include <soc/tegra/mc.h>
|
||||||
|
|
||||||
#define MC_INT_DECERR_MTS (1 << 16)
|
#define MC_INT_DECERR_MTS BIT(16)
|
||||||
#define MC_INT_SECERR_SEC (1 << 13)
|
#define MC_INT_SECERR_SEC BIT(13)
|
||||||
#define MC_INT_DECERR_VPR (1 << 12)
|
#define MC_INT_DECERR_VPR BIT(12)
|
||||||
#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
|
#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
|
||||||
#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
|
#define MC_INT_INVALID_SMMU_PAGE BIT(10)
|
||||||
#define MC_INT_ARBITRATION_EMEM (1 << 9)
|
#define MC_INT_ARBITRATION_EMEM BIT(9)
|
||||||
#define MC_INT_SECURITY_VIOLATION (1 << 8)
|
#define MC_INT_SECURITY_VIOLATION BIT(8)
|
||||||
#define MC_INT_INVALID_GART_PAGE (1 << 7)
|
#define MC_INT_INVALID_GART_PAGE BIT(7)
|
||||||
#define MC_INT_DECERR_EMEM (1 << 6)
|
#define MC_INT_DECERR_EMEM BIT(6)
|
||||||
|
|
||||||
|
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
||||||
|
#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK 0x1ff
|
||||||
|
#define MC_EMEM_ARB_OUTSTANDING_REQ_HOLDOFF_OVERRIDE BIT(30)
|
||||||
|
#define MC_EMEM_ARB_OUTSTANDING_REQ_LIMIT_ENABLE BIT(31)
|
||||||
|
|
||||||
|
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
||||||
|
#define MC_EMEM_ARB_OVERRIDE_EACK_MASK 0x3
|
||||||
|
|
||||||
|
#define MC_TIMING_CONTROL 0xfc
|
||||||
|
#define MC_TIMING_UPDATE BIT(0)
|
||||||
|
|
||||||
static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
|
static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
|
||||||
{
|
{
|
||||||
|
1232
drivers/memory/tegra/tegra30-emc.c
Normal file
1232
drivers/memory/tegra/tegra30-emc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,46 @@
|
|||||||
|
|
||||||
#include "mc.h"
|
#include "mc.h"
|
||||||
|
|
||||||
|
#define MC_EMEM_ARB_CFG 0x90
|
||||||
|
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
|
||||||
|
#define MC_EMEM_ARB_TIMING_RCD 0x98
|
||||||
|
#define MC_EMEM_ARB_TIMING_RP 0x9c
|
||||||
|
#define MC_EMEM_ARB_TIMING_RC 0xa0
|
||||||
|
#define MC_EMEM_ARB_TIMING_RAS 0xa4
|
||||||
|
#define MC_EMEM_ARB_TIMING_FAW 0xa8
|
||||||
|
#define MC_EMEM_ARB_TIMING_RRD 0xac
|
||||||
|
#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
|
||||||
|
#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
|
||||||
|
#define MC_EMEM_ARB_TIMING_R2R 0xb8
|
||||||
|
#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_DA_TURNS 0xd0
|
||||||
|
#define MC_EMEM_ARB_DA_COVERS 0xd4
|
||||||
|
#define MC_EMEM_ARB_MISC0 0xd8
|
||||||
|
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||||
|
|
||||||
|
static const unsigned long tegra30_mc_emem_regs[] = {
|
||||||
|
MC_EMEM_ARB_CFG,
|
||||||
|
MC_EMEM_ARB_OUTSTANDING_REQ,
|
||||||
|
MC_EMEM_ARB_TIMING_RCD,
|
||||||
|
MC_EMEM_ARB_TIMING_RP,
|
||||||
|
MC_EMEM_ARB_TIMING_RC,
|
||||||
|
MC_EMEM_ARB_TIMING_RAS,
|
||||||
|
MC_EMEM_ARB_TIMING_FAW,
|
||||||
|
MC_EMEM_ARB_TIMING_RRD,
|
||||||
|
MC_EMEM_ARB_TIMING_RAP2PRE,
|
||||||
|
MC_EMEM_ARB_TIMING_WAP2PRE,
|
||||||
|
MC_EMEM_ARB_TIMING_R2R,
|
||||||
|
MC_EMEM_ARB_TIMING_W2W,
|
||||||
|
MC_EMEM_ARB_TIMING_R2W,
|
||||||
|
MC_EMEM_ARB_TIMING_W2R,
|
||||||
|
MC_EMEM_ARB_DA_TURNS,
|
||||||
|
MC_EMEM_ARB_DA_COVERS,
|
||||||
|
MC_EMEM_ARB_MISC0,
|
||||||
|
MC_EMEM_ARB_RING1_THROTTLE,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct tegra_mc_client tegra30_mc_clients[] = {
|
static const struct tegra_mc_client tegra30_mc_clients[] = {
|
||||||
{
|
{
|
||||||
.id = 0x00,
|
.id = 0x00,
|
||||||
@ -997,6 +1037,8 @@ const struct tegra_mc_soc tegra30_mc_soc = {
|
|||||||
.atom_size = 16,
|
.atom_size = 16,
|
||||||
.client_id_mask = 0x7f,
|
.client_id_mask = 0x7f,
|
||||||
.smmu = &tegra30_smmu_soc,
|
.smmu = &tegra30_smmu_soc,
|
||||||
|
.emem_regs = tegra30_mc_emem_regs,
|
||||||
|
.num_emem_regs = ARRAY_SIZE(tegra30_mc_emem_regs),
|
||||||
.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
|
.intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
|
||||||
MC_INT_DECERR_EMEM,
|
MC_INT_DECERR_EMEM,
|
||||||
.reset_ops = &tegra_mc_reset_ops_common,
|
.reset_ops = &tegra_mc_reset_ops_common,
|
||||||
|
@ -181,7 +181,7 @@ struct tegra_mc {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
|
int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate);
|
||||||
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
|
unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc);
|
||||||
|
|
||||||
#endif /* __SOC_TEGRA_MC_H__ */
|
#endif /* __SOC_TEGRA_MC_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user