Memory controller drivers for v5.18 - Tegra SoC

1. Correct Tegra20 EMC memory device mask.
 2. Minor improvements.
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmIc+xkQHGtyemtAa2Vy
 bmVsLm9yZwAKCRDBN2bmhouD1zROD/9J0QlxhDaJv3B0dpJsAzq1/4YptmdjGC9m
 6HJY7wuf1+LR0fJ7ry5KeHU+iYNALuEicZgQErum5+opLJ8kGcZqBA7vtqd40sbz
 xHDad9keIElZYVdt+mEO3eq4Mi2h/i6zU+3E9pYXNYwqp/bB27GhIX6mHo0wXe2r
 8QmFpSlwuhPQSeyx2l01pbPlvnb/bxe0hXUY2hXQ0V849bOAFHxBCoNKoHmKS19w
 VXZBpUX+LXTQDEaJX7x32Apgi3tXAqHNI6hIRif48v6E3mE243hIkaBGQ6DhdArQ
 AdDub9pxqEJ8xR/OaEW0063Y1SsxY6Ac+PnszOfKPnufzAnmzwaVO8aohOTosZyg
 uZcjav4l1+8zHKGG3zdFSDdKXM97jp5S48uq/uZy/GDHmKw32IUZqHFwPxLXt5Gn
 0Vq0naiHXXiK1ax/ook01N5ex+sg5NunpQ09OQzIu62BbOBn2yB5TTy+rE1TBwsW
 fI8/s99X/T/+Mkv9enlLkKk2HqSXbxCRnvAZf4Gc6mZgM/nJlrbWvzGi2oiMYckd
 c7V3E7q2DCqfOsy1bl7j2Yi1JrAL7bSVtiP2V4K6wq7oI+NwTwmDEATw4eHiPgeL
 MGH9ehWrjjhFuVER7CVU1YQLMxcaWTKtYpfw06unR0NAwlhrrqxN63Tpl7oPlcE5
 hs7tYy+YOw==
 =vszm
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmId7okACgkQmmx57+YA
 GNkPlQ/6AuiYn1E5T3ELdAWsTJhByu7T7Hcj0+f4JqdWwn3t+UWngLgCBKW8dMuB
 nHKNBiEUXgsF3ts7+EK5HCHef+DjCPozmb/W6Lj3EK7L/cChigB13XPWJi5DBA2t
 80+R3T2CemYaDUXlRri1myPT6m7YEvkPzvC8sESTYJOv21kbmG8o895LgmJf9czG
 k6+adkG18xI0Z40GKoQWTzh8R86FIy5JZZ+7VjEPsngy7rTanLr5hxzBL1i60vtd
 luamZ6uPG8LkSgX8TEh0/wpznqEZDmr0XrbDK1xmd/USAkVxc79QTL1hUNel8SU6
 RYmL738NliGQQhnbxxSZYfW4BhqdGKjM6xjt+g3nSFQYkL3RChxBFa25xX9Zd68Q
 FodRTAqZc8p8K0LTSbeQV7qL/ziZRcoaGi1L76R3l5Zm3pnx4XT/YVc5wh6tf3UJ
 T9uRWAb0DPuLFW+cxwf0JRVsGVdhxWVFxCQK22vSlTK0fkwGtN1iKBc3Fnf2SYJ/
 U0lvwqRBH6MZT8J7RS05a/HI2H7CVQJK99vgj7MLmxWB1rh6Q6uuJR9eutdccyu5
 A2rFseuEE7gpV++xLqNAPRbrVYm1hnQdL98868j62WKeMQDU4caUzCE5uOwmut+R
 EpmfhTWaB9k+xhepu26BWcVcCfu7St0By4Gs8G7mjyTJdOL0tAs=
 =fMbE
 -----END PGP SIGNATURE-----

Merge tag 'memory-controller-drv-tegra-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers

Memory controller drivers for v5.18 - Tegra SoC

1. Correct Tegra20 EMC memory device mask.
2. Minor improvements.

* tag 'memory-controller-drv-tegra-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: tegra: Constify struct thermal_cooling_device_ops
  memory: tegra20-emc: Correct memory device mask
  memory: tegra30-emc: Print additional memory info

Link: https://lore.kernel.org/r/20220228164313.52931-3-krzysztof.kozlowski@canonical.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2022-03-01 10:59:36 +01:00
commit 42ba417307
4 changed files with 124 additions and 12 deletions

View File

@ -28,6 +28,7 @@ config TEGRA30_EMC
default y default y
depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
select PM_OPP select PM_OPP
select DDR
help help
This driver is for the External Memory Controller (EMC) found on This driver is for the External Memory Controller (EMC) found on
Tegra30 chips. The EMC controls the external DRAM on the board. Tegra30 chips. The EMC controls the external DRAM on the board.

View File

@ -540,7 +540,7 @@ static int emc_read_lpddr_mode_register(struct tegra_emc *emc,
unsigned int register_addr, unsigned int register_addr,
unsigned int *register_data) unsigned int *register_data)
{ {
u32 memory_dev = emem_dev + 1; u32 memory_dev = emem_dev ? 1 : 2;
u32 val, mr_mask = 0xff; u32 val, mr_mask = 0xff;
int err; int err;

View File

@ -711,7 +711,7 @@ static int tegra210_emc_cd_set_state(struct thermal_cooling_device *cd,
return 0; return 0;
} }
static struct thermal_cooling_device_ops tegra210_emc_cd_ops = { static const struct thermal_cooling_device_ops tegra210_emc_cd_ops = {
.get_max_state = tegra210_emc_cd_max_state, .get_max_state = tegra210_emc_cd_max_state,
.get_cur_state = tegra210_emc_cd_get_state, .get_cur_state = tegra210_emc_cd_get_state,
.set_cur_state = tegra210_emc_cd_set_state, .set_cur_state = tegra210_emc_cd_set_state,

View File

@ -9,6 +9,7 @@
* Copyright (C) 2019 GRATE-DRIVER project * Copyright (C) 2019 GRATE-DRIVER project
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/tegra.h> #include <linux/clk/tegra.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
@ -31,11 +32,15 @@
#include <soc/tegra/common.h> #include <soc/tegra/common.h>
#include <soc/tegra/fuse.h> #include <soc/tegra/fuse.h>
#include "../jedec_ddr.h"
#include "../of_memory.h"
#include "mc.h" #include "mc.h"
#define EMC_INTSTATUS 0x000 #define EMC_INTSTATUS 0x000
#define EMC_INTMASK 0x004 #define EMC_INTMASK 0x004
#define EMC_DBG 0x008 #define EMC_DBG 0x008
#define EMC_ADR_CFG 0x010
#define EMC_CFG 0x00c #define EMC_CFG 0x00c
#define EMC_REFCTRL 0x020 #define EMC_REFCTRL 0x020
#define EMC_TIMING_CONTROL 0x028 #define EMC_TIMING_CONTROL 0x028
@ -81,6 +86,7 @@
#define EMC_EMRS 0x0d0 #define EMC_EMRS 0x0d0
#define EMC_SELF_REF 0x0e0 #define EMC_SELF_REF 0x0e0
#define EMC_MRW 0x0e8 #define EMC_MRW 0x0e8
#define EMC_MRR 0x0ec
#define EMC_XM2DQSPADCTRL3 0x0f8 #define EMC_XM2DQSPADCTRL3 0x0f8
#define EMC_FBIO_SPARE 0x100 #define EMC_FBIO_SPARE 0x100
#define EMC_FBIO_CFG5 0x104 #define EMC_FBIO_CFG5 0x104
@ -208,6 +214,13 @@
#define EMC_REFRESH_OVERFLOW_INT BIT(3) #define EMC_REFRESH_OVERFLOW_INT BIT(3)
#define EMC_CLKCHANGE_COMPLETE_INT BIT(4) #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 { enum emc_dram_type {
DRAM_TYPE_DDR3, DRAM_TYPE_DDR3,
@ -378,6 +391,8 @@ struct tegra_emc {
/* protect shared rate-change code path */ /* protect shared rate-change code path */
struct mutex rate_lock; struct mutex rate_lock;
bool mrr_error;
}; };
static int emc_seq_update_timing(struct tegra_emc *emc) static int emc_seq_update_timing(struct tegra_emc *emc)
@ -1008,12 +1023,18 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc,
return 0; 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; struct device_node *np;
u32 value, ram_code; u32 value, ram_code;
int err; 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) { if (of_get_child_count(dev->of_node) == 0) {
dev_info_once(dev, "device-tree doesn't have memory timings\n"); dev_info_once(dev, "device-tree doesn't have memory timings\n");
return NULL; return NULL;
@ -1035,11 +1056,73 @@ static struct device_node *emc_find_node_by_ram_code(struct device *dev)
return NULL; 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 : 2;
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) 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 intmask = EMC_REFRESH_OVERFLOW_INT;
u32 fbio_cfg5, emc_cfg, emc_dbg; static bool print_sdram_info_once;
enum emc_dram_type dram_type; enum emc_dram_type dram_type;
const char *dram_type_str;
unsigned int emem_numdev;
fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5); fbio_cfg5 = readl_relaxed(emc->regs + EMC_FBIO_CFG5);
dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK; dram_type = fbio_cfg5 & EMC_FBIO_CFG5_DRAM_TYPE_MASK;
@ -1076,6 +1159,34 @@ static int emc_setup_hw(struct tegra_emc *emc)
emc_dbg &= ~EMC_DBG_FORCE_UPDATE; emc_dbg &= ~EMC_DBG_FORCE_UPDATE;
writel_relaxed(emc_dbg, emc->regs + EMC_DBG); 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; return 0;
} }
@ -1538,14 +1649,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
emc->clk_nb.notifier_call = emc_clk_change_notify; emc->clk_nb.notifier_call = emc_clk_change_notify;
emc->dev = &pdev->dev; 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); emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs)) if (IS_ERR(emc->regs))
return PTR_ERR(emc->regs); return PTR_ERR(emc->regs);
@ -1554,6 +1657,14 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err) if (err)
return 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); err = platform_get_irq(pdev, 0);
if (err < 0) if (err < 0)
return err; return err;