Skip to content

Commit

Permalink
memory: tegra30-emc: Print more memory info
Browse files Browse the repository at this point in the history
Print out additional info about Tegra30 memory hardware during driver
probe, making it similar to the info printed by Tegra20 driver. This info
is useful for debugging purposes.

Signed-off-by: Dmitry Osipenko <[email protected]>
  • Loading branch information
digetx committed Dec 12, 2021
1 parent 93cae38 commit ae1eb3b
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 10 deletions.
1 change: 1 addition & 0 deletions drivers/memory/tegra/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ config TEGRA30_EMC
default y
depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
select PM_OPP
select DDR
help
This driver is for the External Memory Controller (EMC) found on
Tegra30 chips. The EMC controls the external DRAM on the board.
Expand Down
131 changes: 121 additions & 10 deletions drivers/memory/tegra/tegra30-emc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Copyright (C) 2019 GRATE-DRIVER project
*/

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk/tegra.h>
#include <linux/debugfs.h>
Expand All @@ -31,11 +32,15 @@
#include <soc/tegra/common.h>
#include <soc/tegra/fuse.h>

#include "../jedec_ddr.h"
#include "../of_memory.h"

#include "mc.h"

#define EMC_INTSTATUS 0x000
#define EMC_INTMASK 0x004
#define EMC_DBG 0x008
#define EMC_ADR_CFG 0x010
#define EMC_CFG 0x00c
#define EMC_REFCTRL 0x020
#define EMC_TIMING_CONTROL 0x028
Expand Down Expand Up @@ -81,6 +86,7 @@
#define EMC_EMRS 0x0d0
#define EMC_SELF_REF 0x0e0
#define EMC_MRW 0x0e8
#define EMC_MRR 0x0ec
#define EMC_XM2DQSPADCTRL3 0x0f8
#define EMC_FBIO_SPARE 0x100
#define EMC_FBIO_CFG5 0x104
Expand Down Expand Up @@ -208,6 +214,13 @@

#define EMC_REFRESH_OVERFLOW_INT BIT(3)
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
#define EMC_MRR_DIVLD_INT BIT(5)

#define EMC_MRR_DEV_SELECTN GENMASK(31, 30)
#define EMC_MRR_MRR_MA GENMASK(23, 16)
#define EMC_MRR_MRR_DATA GENMASK(15, 0)

#define EMC_ADR_CFG_EMEM_NUMDEV BIT(0)

enum emc_dram_type {
DRAM_TYPE_DDR3,
Expand Down Expand Up @@ -378,6 +391,8 @@ struct tegra_emc {

/* protect shared rate-change code path */
struct mutex rate_lock;

bool mrr_error;
};

static int emc_seq_update_timing(struct tegra_emc *emc)
Expand Down Expand Up @@ -1008,12 +1023,18 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc,
return 0;
}

static struct device_node *emc_find_node_by_ram_code(struct device *dev)
static struct device_node *emc_find_node_by_ram_code(struct tegra_emc *emc)
{
struct device *dev = emc->dev;
struct device_node *np;
u32 value, ram_code;
int err;

if (emc->mrr_error) {
dev_warn(dev, "memory timings skipped due to MRR error\n");
return NULL;
}

if (of_get_child_count(dev->of_node) == 0) {
dev_info_once(dev, "device-tree doesn't have memory timings\n");
return NULL;
Expand All @@ -1035,11 +1056,73 @@ static struct device_node *emc_find_node_by_ram_code(struct device *dev)
return NULL;
}

static int emc_read_lpddr_mode_register(struct tegra_emc *emc,
unsigned int emem_dev,
unsigned int register_addr,
unsigned int *register_data)
{
u32 memory_dev = emem_dev + 1;
u32 val, mr_mask = 0xff;
int err;

/* clear data-valid interrupt status */
writel_relaxed(EMC_MRR_DIVLD_INT, emc->regs + EMC_INTSTATUS);

/* issue mode register read request */
val = FIELD_PREP(EMC_MRR_DEV_SELECTN, memory_dev);
val |= FIELD_PREP(EMC_MRR_MRR_MA, register_addr);

writel_relaxed(val, emc->regs + EMC_MRR);

/* wait for the LPDDR2 data-valid interrupt */
err = readl_relaxed_poll_timeout_atomic(emc->regs + EMC_INTSTATUS, val,
val & EMC_MRR_DIVLD_INT,
1, 100);
if (err) {
dev_err(emc->dev, "mode register %u read failed: %d\n",
register_addr, err);
emc->mrr_error = true;
return err;
}

/* read out mode register data */
val = readl_relaxed(emc->regs + EMC_MRR);
*register_data = FIELD_GET(EMC_MRR_MRR_DATA, val) & mr_mask;

return 0;
}

static void emc_read_lpddr_sdram_info(struct tegra_emc *emc,
unsigned int emem_dev)
{
union lpddr2_basic_config4 basic_conf4;
unsigned int manufacturer_id;
unsigned int revision_id1;
unsigned int revision_id2;

/* these registers are standard for all LPDDR JEDEC memory chips */
emc_read_lpddr_mode_register(emc, emem_dev, 5, &manufacturer_id);
emc_read_lpddr_mode_register(emc, emem_dev, 6, &revision_id1);
emc_read_lpddr_mode_register(emc, emem_dev, 7, &revision_id2);
emc_read_lpddr_mode_register(emc, emem_dev, 8, &basic_conf4.value);

dev_info(emc->dev, "SDRAM[dev%u]: manufacturer: 0x%x (%s) rev1: 0x%x rev2: 0x%x prefetch: S%u density: %uMbit iowidth: %ubit\n",
emem_dev, manufacturer_id,
lpddr2_jedec_manufacturer(manufacturer_id),
revision_id1, revision_id2,
4 >> basic_conf4.arch_type,
64 << basic_conf4.density,
32 >> basic_conf4.io_width);
}

static int emc_setup_hw(struct tegra_emc *emc)
{
u32 fbio_cfg5, emc_cfg, emc_dbg, emc_adr_cfg;
u32 intmask = EMC_REFRESH_OVERFLOW_INT;
u32 fbio_cfg5, emc_cfg, emc_dbg;
static bool print_sdram_info_once;
enum emc_dram_type dram_type;
const char *dram_type_str;
unsigned int emem_numdev;

fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
Expand Down Expand Up @@ -1076,6 +1159,34 @@ static int emc_setup_hw(struct tegra_emc *emc)
emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
writel_relaxed(emc_dbg, emc->regs + EMC_DBG);

switch (dram_type) {
case DRAM_TYPE_DDR1:
dram_type_str = "DDR1";
break;
case DRAM_TYPE_LPDDR2:
dram_type_str = "LPDDR2";
break;
case DRAM_TYPE_DDR2:
dram_type_str = "DDR2";
break;
case DRAM_TYPE_DDR3:
dram_type_str = "DDR3";
break;
}

emc_adr_cfg = readl_relaxed(emc->regs + EMC_ADR_CFG);
emem_numdev = FIELD_GET(EMC_ADR_CFG_EMEM_NUMDEV, emc_adr_cfg) + 1;

dev_info_once(emc->dev, "%u %s %s attached\n", emem_numdev,
dram_type_str, emem_numdev == 2 ? "devices" : "device");

if (dram_type == DRAM_TYPE_LPDDR2 && !print_sdram_info_once) {
while (emem_numdev--)
emc_read_lpddr_sdram_info(emc, emem_numdev);

print_sdram_info_once = true;
}

return 0;
}

Expand Down Expand Up @@ -1538,14 +1649,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
emc->clk_nb.notifier_call = emc_clk_change_notify;
emc->dev = &pdev->dev;

np = emc_find_node_by_ram_code(&pdev->dev);
if (np) {
err = emc_load_timings_from_dt(emc, np);
of_node_put(np);
if (err)
return err;
}

emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs))
return PTR_ERR(emc->regs);
Expand All @@ -1554,6 +1657,14 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err)
return err;

np = emc_find_node_by_ram_code(emc);
if (np) {
err = emc_load_timings_from_dt(emc, np);
of_node_put(np);
if (err)
return err;
}

err = platform_get_irq(pdev, 0);
if (err < 0)
return err;
Expand Down

0 comments on commit ae1eb3b

Please sign in to comment.