Merge tag 'tegra-for-5.5-memory-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/drivers
memory: tegra: Changes for v5.5-rc1 This contains a couple of fixes and adds support for EMC frequency scaling on Tegra30. * tag 'tegra-for-5.5-memory-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: memory: tegra: Consolidate registers definition into common header memory: tegra: Ensure timing control debug features are disabled memory: tegra: Introduce Tegra30 EMC driver memory: tegra: Do not handle error from wait_for_completion_timeout() memory: tegra: Increase handshake timeout on Tegra20 memory: tegra: Print a brief info message about EMC timings memory: tegra: Pre-configure debug register on Tegra20 memory: tegra: Include io.h instead of iopoll.h memory: tegra: Adapt for Tegra20 clock driver changes memory: tegra: Don't set EMC rate to maximum on probe for Tegra20 memory: tegra: Add gr2d and gr3d to DRM IOMMU group memory: tegra: Set DMA mask based on supported address bits clk: tegra: Add Tegra20/30 EMC clock implementation Link: https://lore.kernel.org/r/20191111143836.4027200-1-thierry.reding@gmail.com Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
@@ -17,6 +17,16 @@ config TEGRA20_EMC
|
||||
This driver is required to change memory timings / clock rate for
|
||||
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
|
||||
bool "NVIDIA Tegra124 External Memory Controller driver"
|
||||
default y
|
||||
|
@@ -11,5 +11,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
|
||||
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_ARCH_TEGRA_186_SOC) += tegra186.o
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@@ -18,39 +19,6 @@
|
||||
|
||||
#include "mc.h"
|
||||
|
||||
#define MC_INTSTATUS 0x000
|
||||
|
||||
#define MC_INTMASK 0x004
|
||||
|
||||
#define MC_ERR_STATUS 0x08
|
||||
#define MC_ERR_STATUS_TYPE_SHIFT 28
|
||||
#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT)
|
||||
#define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT)
|
||||
#define MC_ERR_STATUS_READABLE (1 << 27)
|
||||
#define MC_ERR_STATUS_WRITABLE (1 << 26)
|
||||
#define MC_ERR_STATUS_NONSECURE (1 << 25)
|
||||
#define MC_ERR_STATUS_ADR_HI_SHIFT 20
|
||||
#define MC_ERR_STATUS_ADR_HI_MASK 0x3
|
||||
#define MC_ERR_STATUS_SECURITY (1 << 17)
|
||||
#define MC_ERR_STATUS_RW (1 << 16)
|
||||
|
||||
#define MC_ERR_ADR 0x0c
|
||||
|
||||
#define MC_GART_ERROR_REQ 0x30
|
||||
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
|
||||
#define MC_SECURITY_VIOLATION_STATUS 0x74
|
||||
|
||||
#define MC_EMEM_ARB_CFG 0x90
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
|
||||
#define MC_EMEM_ARB_MISC0 0xd8
|
||||
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#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[] = {
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
{ .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
|
||||
@@ -307,7 +275,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
|
||||
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;
|
||||
struct tegra_mc_timing *timing = NULL;
|
||||
@@ -322,11 +290,13 @@ void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate)
|
||||
if (!timing) {
|
||||
dev_err(mc->dev, "no memory timing registered for rate %lu\n",
|
||||
rate);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < mc->soc->num_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)
|
||||
@@ -626,6 +596,7 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct tegra_mc *mc;
|
||||
void *isr;
|
||||
u64 mask;
|
||||
int err;
|
||||
|
||||
mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
|
||||
@@ -637,6 +608,14 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||
mc->soc = of_device_get_match_data(&pdev->dev);
|
||||
mc->dev = &pdev->dev;
|
||||
|
||||
mask = DMA_BIT_MASK(mc->soc->num_address_bits);
|
||||
|
||||
err = dma_coerce_mask_and_coherent(&pdev->dev, mask);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* length of MC tick in nanoseconds */
|
||||
mc->tick = 30;
|
||||
|
||||
@@ -658,6 +637,9 @@ static int tegra_mc_probe(struct platform_device *pdev)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* ensure that debug features are disabled */
|
||||
mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG);
|
||||
|
||||
err = tegra_mc_setup_latency_allowance(mc);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
|
@@ -6,20 +6,76 @@
|
||||
#ifndef MEMORY_TEGRA_MC_H
|
||||
#define MEMORY_TEGRA_MC_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/tegra/mc.h>
|
||||
|
||||
#define MC_INT_DECERR_MTS (1 << 16)
|
||||
#define MC_INT_SECERR_SEC (1 << 13)
|
||||
#define MC_INT_DECERR_VPR (1 << 12)
|
||||
#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
|
||||
#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
|
||||
#define MC_INT_ARBITRATION_EMEM (1 << 9)
|
||||
#define MC_INT_SECURITY_VIOLATION (1 << 8)
|
||||
#define MC_INT_INVALID_GART_PAGE (1 << 7)
|
||||
#define MC_INT_DECERR_EMEM (1 << 6)
|
||||
#define MC_INTSTATUS 0x00
|
||||
#define MC_INTMASK 0x04
|
||||
#define MC_ERR_STATUS 0x08
|
||||
#define MC_ERR_ADR 0x0c
|
||||
#define MC_GART_ERROR_REQ 0x30
|
||||
#define MC_EMEM_ADR_CFG 0x54
|
||||
#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
|
||||
#define MC_SECURITY_VIOLATION_STATUS 0x74
|
||||
#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_MISC1 0xdc
|
||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||
#define MC_EMEM_ARB_OVERRIDE 0xe8
|
||||
#define MC_TIMING_CONTROL_DBG 0xf8
|
||||
#define MC_TIMING_CONTROL 0xfc
|
||||
|
||||
#define MC_INT_DECERR_MTS BIT(16)
|
||||
#define MC_INT_SECERR_SEC BIT(13)
|
||||
#define MC_INT_DECERR_VPR BIT(12)
|
||||
#define MC_INT_INVALID_APB_ASID_UPDATE BIT(11)
|
||||
#define MC_INT_INVALID_SMMU_PAGE BIT(10)
|
||||
#define MC_INT_ARBITRATION_EMEM BIT(9)
|
||||
#define MC_INT_SECURITY_VIOLATION BIT(8)
|
||||
#define MC_INT_INVALID_GART_PAGE BIT(7)
|
||||
#define MC_INT_DECERR_EMEM BIT(6)
|
||||
|
||||
#define MC_ERR_STATUS_TYPE_SHIFT 28
|
||||
#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (0x6 << 28)
|
||||
#define MC_ERR_STATUS_TYPE_MASK (0x7 << 28)
|
||||
#define MC_ERR_STATUS_READABLE BIT(27)
|
||||
#define MC_ERR_STATUS_WRITABLE BIT(26)
|
||||
#define MC_ERR_STATUS_NONSECURE BIT(25)
|
||||
#define MC_ERR_STATUS_ADR_HI_SHIFT 20
|
||||
#define MC_ERR_STATUS_ADR_HI_MASK 0x3
|
||||
#define MC_ERR_STATUS_SECURITY BIT(17)
|
||||
#define MC_ERR_STATUS_RW BIT(16)
|
||||
|
||||
#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
|
||||
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) ((x) & 0x1ff)
|
||||
#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
|
||||
|
||||
#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_EACK_MASK 0x3
|
||||
|
||||
#define MC_TIMING_UPDATE BIT(0)
|
||||
|
||||
static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
|
||||
{
|
||||
|
@@ -909,16 +909,18 @@ static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
|
||||
{ .name = "tsec", .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra114_group_display[] = {
|
||||
static const unsigned int tegra114_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_G2,
|
||||
TEGRA_SWGROUP_NV,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra114_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra114_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra114_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra114_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -10,26 +10,6 @@
|
||||
|
||||
#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_MISC1 0xdc
|
||||
#define MC_EMEM_ARB_RING1_THROTTLE 0xe0
|
||||
|
||||
static const struct tegra_mc_client tegra124_mc_clients[] = {
|
||||
{
|
||||
.id = 0x00,
|
||||
@@ -974,16 +954,18 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
|
||||
{ .name = "vi", .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra124_group_display[] = {
|
||||
static const unsigned int tegra124_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_GPU,
|
||||
TEGRA_SWGROUP_VIC,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra124_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra124_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra124_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra124_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -6,10 +6,11 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/tegra.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
#define EMC_INTSTATUS 0x000
|
||||
#define EMC_INTMASK 0x004
|
||||
#define EMC_DBG 0x008
|
||||
#define EMC_TIMING_CONTROL 0x028
|
||||
#define EMC_RC 0x02c
|
||||
#define EMC_RFC 0x030
|
||||
@@ -79,6 +81,12 @@
|
||||
#define EMC_REFRESH_OVERFLOW_INT BIT(3)
|
||||
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
|
||||
|
||||
#define EMC_DBG_READ_MUX_ASSEMBLY BIT(0)
|
||||
#define EMC_DBG_WRITE_MUX_ACTIVE BIT(1)
|
||||
#define EMC_DBG_FORCE_UPDATE BIT(2)
|
||||
#define EMC_DBG_READ_DQM_CTRL BIT(9)
|
||||
#define EMC_DBG_CFG_PRIORITY BIT(24)
|
||||
|
||||
static const u16 emc_timing_registers[] = {
|
||||
EMC_RC,
|
||||
EMC_RFC,
|
||||
@@ -137,9 +145,6 @@ struct tegra_emc {
|
||||
struct device *dev;
|
||||
struct completion clk_handshake_complete;
|
||||
struct notifier_block clk_nb;
|
||||
struct clk *backup_clk;
|
||||
struct clk *emc_mux;
|
||||
struct clk *pll_m;
|
||||
struct clk *clk;
|
||||
void __iomem *regs;
|
||||
|
||||
@@ -219,7 +224,7 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate)
|
||||
|
||||
static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
|
||||
{
|
||||
long timeout;
|
||||
unsigned long timeout;
|
||||
|
||||
dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush);
|
||||
|
||||
@@ -231,14 +236,10 @@ static int emc_complete_timing_change(struct tegra_emc *emc, bool flush)
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&emc->clk_handshake_complete,
|
||||
usecs_to_jiffies(100));
|
||||
msecs_to_jiffies(100));
|
||||
if (timeout == 0) {
|
||||
dev_err(emc->dev, "EMC-CAR handshake failed\n");
|
||||
return -EIO;
|
||||
} else if (timeout < 0) {
|
||||
dev_err(emc->dev, "failed to wait for EMC-CAR handshake: %ld\n",
|
||||
timeout);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -363,6 +364,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,
|
||||
sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,
|
||||
NULL);
|
||||
|
||||
dev_info(emc->dev,
|
||||
"got %u timings for RAM code %u (min %luMHz max %luMHz)\n",
|
||||
emc->num_timings,
|
||||
tegra_read_ram_code(),
|
||||
emc->timings[0].rate / 1000000,
|
||||
emc->timings[emc->num_timings - 1].rate / 1000000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -398,7 +406,7 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
|
||||
static int emc_setup_hw(struct tegra_emc *emc)
|
||||
{
|
||||
u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT;
|
||||
u32 emc_cfg;
|
||||
u32 emc_cfg, emc_dbg;
|
||||
|
||||
emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);
|
||||
|
||||
@@ -421,42 +429,53 @@ static int emc_setup_hw(struct tegra_emc *emc)
|
||||
writel_relaxed(intmask, emc->regs + EMC_INTMASK);
|
||||
writel_relaxed(intmask, emc->regs + EMC_INTSTATUS);
|
||||
|
||||
/* ensure that unwanted debug features are disabled */
|
||||
emc_dbg = readl_relaxed(emc->regs + EMC_DBG);
|
||||
emc_dbg |= EMC_DBG_CFG_PRIORITY;
|
||||
emc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY;
|
||||
emc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE;
|
||||
emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
|
||||
writel_relaxed(emc_dbg, emc->regs + EMC_DBG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emc_init(struct tegra_emc *emc, unsigned long rate)
|
||||
static long emc_round_rate(unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
void *arg)
|
||||
{
|
||||
int err;
|
||||
struct emc_timing *timing = NULL;
|
||||
struct tegra_emc *emc = arg;
|
||||
unsigned int i;
|
||||
|
||||
err = clk_set_parent(emc->emc_mux, emc->backup_clk);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to reparent to backup source: %d\n", err);
|
||||
return err;
|
||||
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
|
||||
|
||||
for (i = 0; i < emc->num_timings; i++) {
|
||||
if (emc->timings[i].rate < rate && i != emc->num_timings - 1)
|
||||
continue;
|
||||
|
||||
if (emc->timings[i].rate > max_rate) {
|
||||
i = max(i, 1u) - 1;
|
||||
|
||||
if (emc->timings[i].rate < min_rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (emc->timings[i].rate < min_rate)
|
||||
continue;
|
||||
|
||||
timing = &emc->timings[i];
|
||||
break;
|
||||
}
|
||||
|
||||
err = clk_set_rate(emc->pll_m, rate);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to change pll_m rate: %d\n", err);
|
||||
return err;
|
||||
if (!timing) {
|
||||
dev_err(emc->dev, "no timing for rate %lu min %lu max %lu\n",
|
||||
rate, min_rate, max_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = clk_set_parent(emc->emc_mux, emc->pll_m);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to reparent to pll_m: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_set_rate(emc->clk, rate);
|
||||
if (err) {
|
||||
dev_err(emc->dev,
|
||||
"failed to change emc rate: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return timing->rate;
|
||||
}
|
||||
|
||||
static int tegra_emc_probe(struct platform_device *pdev)
|
||||
@@ -515,57 +534,26 @@ static int tegra_emc_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
|
||||
|
||||
emc->clk = devm_clk_get(&pdev->dev, "emc");
|
||||
if (IS_ERR(emc->clk)) {
|
||||
err = PTR_ERR(emc->clk);
|
||||
dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->pll_m = clk_get_sys(NULL, "pll_m");
|
||||
if (IS_ERR(emc->pll_m)) {
|
||||
err = PTR_ERR(emc->pll_m);
|
||||
dev_err(&pdev->dev, "failed to get pll_m clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
emc->backup_clk = clk_get_sys(NULL, "pll_p");
|
||||
if (IS_ERR(emc->backup_clk)) {
|
||||
err = PTR_ERR(emc->backup_clk);
|
||||
dev_err(&pdev->dev, "failed to get pll_p clock: %d\n", err);
|
||||
goto put_pll_m;
|
||||
}
|
||||
|
||||
emc->emc_mux = clk_get_parent(emc->clk);
|
||||
if (IS_ERR(emc->emc_mux)) {
|
||||
err = PTR_ERR(emc->emc_mux);
|
||||
dev_err(&pdev->dev, "failed to get emc_mux clock: %d\n", err);
|
||||
goto put_backup;
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
err = clk_notifier_register(emc->clk, &emc->clk_nb);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to register clk notifier: %d\n",
|
||||
err);
|
||||
goto put_backup;
|
||||
}
|
||||
|
||||
/* set DRAM clock rate to maximum */
|
||||
err = emc_init(emc, emc->timings[emc->num_timings - 1].rate);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n",
|
||||
err);
|
||||
goto unreg_notifier;
|
||||
goto unset_cb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unreg_notifier:
|
||||
clk_notifier_unregister(emc->clk, &emc->clk_nb);
|
||||
put_backup:
|
||||
clk_put(emc->backup_clk);
|
||||
put_pll_m:
|
||||
clk_put(emc->pll_m);
|
||||
unset_cb:
|
||||
tegra20_clk_set_emc_round_callback(NULL, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
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,27 @@
|
||||
|
||||
#include "mc.h"
|
||||
|
||||
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[] = {
|
||||
{
|
||||
.id = 0x00,
|
||||
@@ -931,16 +952,19 @@ static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
|
||||
{ .name = "isp", .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
|
||||
};
|
||||
|
||||
static const unsigned int tegra30_group_display[] = {
|
||||
static const unsigned int tegra30_group_drm[] = {
|
||||
TEGRA_SWGROUP_DC,
|
||||
TEGRA_SWGROUP_DCB,
|
||||
TEGRA_SWGROUP_G2,
|
||||
TEGRA_SWGROUP_NV,
|
||||
TEGRA_SWGROUP_NV2,
|
||||
};
|
||||
|
||||
static const struct tegra_smmu_group_soc tegra30_groups[] = {
|
||||
{
|
||||
.name = "display",
|
||||
.swgroups = tegra30_group_display,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_group_display),
|
||||
.name = "drm",
|
||||
.swgroups = tegra30_group_drm,
|
||||
.num_swgroups = ARRAY_SIZE(tegra30_group_drm),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -994,6 +1018,8 @@ const struct tegra_mc_soc tegra30_mc_soc = {
|
||||
.atom_size = 16,
|
||||
.client_id_mask = 0x7f,
|
||||
.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 |
|
||||
MC_INT_DECERR_EMEM,
|
||||
.reset_ops = &tegra_mc_reset_ops_common,
|
||||
|
Reference in New Issue
Block a user