tegra210: mtc: support external tables (WIP)

This commit is contained in:
SwtcR 2018-02-17 06:21:12 +09:00 committed by Andre Heider
parent b581707d8e
commit 1684df7e58
7 changed files with 243 additions and 1 deletions

View file

@ -220,3 +220,8 @@ struct chip_operations mainboard_ops = {
.name = "switch",
.enable_dev = mainboard_enable,
};
void lb_board(struct lb_header *header)
{
soc_add_mtc(header);
}

View file

@ -30,7 +30,7 @@ static const struct sdram_params sdram_configs[] = {
#define FUSE_BASE ((void *)TEGRA_FUSE_BASE)
#define FUSE_RESERVED_ODM4 0x1d8
static uint32_t switch_sdram_get_id(void)
uint32_t switch_sdram_get_id(void)
{
return (read32(FUSE_BASE + FUSE_RESERVED_ODM4) & 0x38) >> 3;
}
@ -48,3 +48,8 @@ const struct sdram_params *get_sdram_config()
return &sdram_configs[id];
}
uint32_t ram_code(void)
{
return switch_sdram_get_id();
}

View file

@ -142,6 +142,24 @@ config MTC_ADDRESS
The DRAM location where MTC firmware to be loaded in. This location
needs to be consistent with the location defined in tegra_mtc.ld
config HAVE_MTC_TABLES
bool "Add external Memory controller Training Code tables"
default n
depends on USE_BLOBS
help
Select this option to add external emc training tables
if HAVE_MTC_TABLES
config MTC_TABLES_DIRECTORY
string "Directory where MTC table files are located"
default "mtc_tables"
help
Path to directory where MTC tables files are located. They should be
named tegra_mtc_table_<ram_code>.bin.
endif # HAVE_MTC_TABLES
endif # HAVE_MTC
endif # SOC_NVIDIA_TEGRA210

View file

@ -162,4 +162,18 @@ cbfs-files-$(CONFIG_HAVE_MTC) += $(MTC_FILE_CBFS)
$(MTC_FILE_CBFS)-file := $(MTC_FILE)
$(MTC_FILE_CBFS)-type := raw
ifeq ($(CONFIG_HAVE_MTC_TABLES),y)
MTC_TABLES_DIRECTORY = $(call strip_quotes,$(CONFIG_MTC_TABLES_DIRECTORY))
define MTC_CBFS_template =
cbfs-files-y += $(1)
$(1)-file := $(MTC_TABLES_DIRECTORY)/$(1)
$(1)-type := raw
endef
MTC_TABLE_NAMES = $(notdir $(wildcard $(MTC_TABLES_DIRECTORY)/tegra_mtc_table_*.bin))
$(foreach table,$(MTC_TABLE_NAMES),$(eval $(call MTC_CBFS_template,$(table))))
endif
endif

View file

@ -20,6 +20,89 @@
#if IS_ENABLED(CONFIG_HAVE_MTC)
typedef struct {
unsigned int rev;
char dvfs_ver[60];
unsigned int rate;
unsigned int min_volt;
unsigned int gpu_min_volt;
char clock_src[32];
unsigned int clk_src_emc;
unsigned int needs_training;
unsigned int training_pattern;
unsigned int trained;
unsigned int periodic_training;
unsigned int trained_dram_clktree_c0d0u0;
unsigned int trained_dram_clktree_c0d0u1;
unsigned int trained_dram_clktree_c0d1u0;
unsigned int trained_dram_clktree_c0d1u1;
unsigned int trained_dram_clktree_c1d0u0;
unsigned int trained_dram_clktree_c1d0u1;
unsigned int trained_dram_clktree_c1d1u0;
unsigned int trained_dram_clktree_c1d1u1;
unsigned int current_dram_clktree_c0d0u0;
unsigned int current_dram_clktree_c0d0u1;
unsigned int current_dram_clktree_c0d1u0;
unsigned int current_dram_clktree_c0d1u1;
unsigned int current_dram_clktree_c1d0u0;
unsigned int current_dram_clktree_c1d0u1;
unsigned int current_dram_clktree_c1d1u0;
unsigned int current_dram_clktree_c1d1u1;
unsigned int run_clocks;
unsigned int tree_margin;
unsigned int num_burst;
unsigned int num_burst_per_ch;
unsigned int num_trim;
unsigned int num_trim_per_ch;
unsigned int num_mc_regs;
unsigned int num_up_down;
unsigned int vref_num;
unsigned int training_mod_num;
unsigned int dram_timing_num;
unsigned int burst_regs[221];
unsigned int burst_reg_per_ch[8];
unsigned int shadow_regs_ca_train[221];
unsigned int shadow_regs_quse_train[221];
unsigned int shadow_regs_rdwr_train[221];
unsigned int trim_regs[138];
unsigned int trim_perch_regs[10];
/* Vref regs, impacted by training. */
unsigned int vref_perch_regs[4];
/* DRAM timing parameters are required in some calculations. */
unsigned int dram_timings[5];
unsigned int training_mod_regs[20];
unsigned int save_restore_mod_regs[12];
unsigned int burst_mc_regs[33];
unsigned int la_scale_regs[24];
unsigned int min_mrs_wait;
unsigned int emc_mrw;
unsigned int emc_mrw2;
unsigned int emc_mrw3;
unsigned int emc_mrw4;
unsigned int emc_mrw9;
unsigned int emc_mrs;
unsigned int emc_emrs;
unsigned int emc_emrs2;
unsigned int emc_auto_cal_config;
unsigned int emc_auto_cal_config2;
unsigned int emc_auto_cal_config3;
unsigned int emc_auto_cal_config4;
unsigned int emc_auto_cal_config5;
unsigned int emc_auto_cal_config6;
unsigned int emc_auto_cal_config7;
unsigned int emc_auto_cal_config8;
unsigned int emc_cfg_2;
unsigned int emc_sel_dpd_ctrl;
unsigned int emc_fdpd_ctrl_cmd_no_ramp;
unsigned int dll_clk_src;
unsigned int clk_out_enb_x_0_clk_enb_emc_dll;
unsigned int latency;
} tegra210_emc_table;
int tegra210_run_mtc(void);
void soc_add_mtc(struct lb_header *header);

View file

@ -13,10 +13,14 @@
* GNU General Public License for more details.
*/
#include <arch/io.h>
#include <cbfs.h>
#include <cbmem.h>
#include <console/console.h>
#include <soc/mtc.h>
#include <soc/addressmap.h>
#include <soc/clock.h>
#include <boardid.h>
#include <string.h>
static size_t mtc_table_size;
@ -25,6 +29,111 @@ static size_t mtc_table_size;
#define MTC_TABLE_ENTRY_SIZE 4880
#define MTC_TABLE_MAX_SIZE (MAX_MTC_TABLE_ENTRIES * MTC_TABLE_ENTRY_SIZE)
#define TRAIN_FUNC 0x5100
#define OP_SWITCH 0
#define OP_TRAIN 1
static int train_all(void *mtc)
{
void * const mtc_entry = (void *)(((uintptr_t)mtc) + TRAIN_FUNC);
int (*train_one)(int z, unsigned int to, unsigned int from,
void *table, int count, int mode) = (void *)(mtc_entry);
char filename[32];
int entries;
struct region_device fh;
struct cbfsf mtc_file;
int ret = 0;
snprintf(filename, sizeof(filename), "tegra_mtc_table_%d.bin", ram_code());
if (cbfs_boot_locate(&mtc_file, filename, NULL)) {
printk(BIOS_ERR, "MTC: Table file not found: %s\n", filename);
return -1;
}
cbfs_file_data(&fh, &mtc_file);
mtc_table_size = region_device_sz(&fh);
entries = mtc_table_size / sizeof(tegra210_emc_table);
printk(BIOS_ERR, "MTC: Using MTC table %s (size: 0x%lx / %d entries)\n",
filename, mtc_table_size, entries);
void *cbmem_tab = cbmem_add(CBMEM_ID_MTC, mtc_table_size);
if (cbmem_tab == NULL) {
printk(BIOS_ERR, "MTC table allocation in cbmem failed!\n");
return -1;
}
printk(BIOS_INFO, "MTC: table is at %p\n", cbmem_tab);
printk(BIOS_INFO, "MTC: entry is at %p\n", train_one);
ssize_t nread = rdev_readat(&fh, cbmem_tab, 0, mtc_table_size);
if (nread != region_device_sz(&fh)) {
printk(BIOS_ERR, "MTC bytes read (%zu) != file length(%zu)!\n",
nread, region_device_sz(&fh));
goto cleanup;
}
tegra210_emc_table *table = cbmem_tab;
int boot_index = 0;
u32 reg = read32(CLK_RST_REG(clk_src_emc));
printk(BIOS_INFO, "MTC: clk_src_emc=0x%08x\n", reg);
for (boot_index = 0; boot_index < entries; boot_index++) {
if (reg == table[boot_index].clk_src_emc)
break;
}
if (boot_index >= entries) {
printk(BIOS_ERR, "MTC: failed to find boot entry\n");
goto cleanup;
}
printk(BIOS_INFO, "MTC: booted using entry #%d (%d kHz): %s\n", boot_index,
table[boot_index].rate, table[boot_index].dvfs_ver);
printk(BIOS_INFO, "MTC: running training\n");
for (int i = 0; i < entries; i++) {
printk(BIOS_INFO, "MTC: Training %d kHz -> %d kHz\n",
table[boot_index].rate, table[i].rate);
ret = train_one(0, table[i].rate, table[boot_index].rate,
table, entries, OP_TRAIN);
if (ret) {
printk(BIOS_ERR, "MTC: Training failed (%d)\n", ret);
goto cleanup;
} else {
printk(BIOS_ERR, "MTC: Training OK\n");
}
}
printk(BIOS_INFO, "MTC: increasing memory clocks\n");
for (int i = boot_index + 1; i < entries; i++) {
if (table[i].periodic_training)
break;
printk(BIOS_INFO, "MTC: Switching %d kHz -> %d kHz\n",
table[i - 1].rate, table[i].rate);
ret = train_one(0, table[i].rate, table[i - 1].rate,
table, entries, OP_SWITCH);
if (ret) {
printk(BIOS_ERR, "MTC: Switch failed (%d)\n", ret);
goto cleanup;
}
}
printk(BIOS_INFO, "MTC: successful\n");
return 0;
cleanup:
cbmem_entry_remove(cbmem_entry_find(CBMEM_ID_MTC));
mtc_table_size = 0;
return -1;
}
int tegra210_run_mtc(void)
{
ssize_t nread;
@ -53,6 +162,7 @@ int tegra210_run_mtc(void)
printk(BIOS_INFO, "MTC: %zu bytes loaded @ %p\n", nread, mtc);
#if !IS_ENABLED(CONFIG_HAVE_MTC_TABLES)
mtc_table_size = (*mtc_fw)(&dvfs_table);
if ((mtc_table_size == 0) || (mtc_table_size > MTC_TABLE_MAX_SIZE)) {
@ -72,6 +182,9 @@ int tegra210_run_mtc(void)
memcpy(cbmem_tab, dvfs_table, mtc_table_size);
printk(BIOS_INFO, "MTC: Copied 0x%zx bytes from %p to %p\n",
mtc_table_size, dvfs_table, cbmem_tab);
#else
return train_all(mtc);
#endif
return 0;
}

View file

@ -16,6 +16,7 @@
#include <arch/clock.h>
#include <arch/cpu.h>
#include <arch/stages.h>
#include <cbmem.h>
#include <gic.h>
#include <soc/addressmap.h>
#include <soc/clock.h>
@ -68,6 +69,9 @@ void ramstage_entry(void)
clock_init_arm_generic_timer();
/* Needed to store MTC data */
cbmem_initialize();
if (tegra210_run_mtc() != 0)
printk(BIOS_ERR, "MTC: No training data.\n");