mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
tegra210: mtc: support external tables (WIP)
This commit is contained in:
parent
b581707d8e
commit
1684df7e58
7 changed files with 243 additions and 1 deletions
|
@ -220,3 +220,8 @@ struct chip_operations mainboard_ops = {
|
||||||
.name = "switch",
|
.name = "switch",
|
||||||
.enable_dev = mainboard_enable,
|
.enable_dev = mainboard_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void lb_board(struct lb_header *header)
|
||||||
|
{
|
||||||
|
soc_add_mtc(header);
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ static const struct sdram_params sdram_configs[] = {
|
||||||
#define FUSE_BASE ((void *)TEGRA_FUSE_BASE)
|
#define FUSE_BASE ((void *)TEGRA_FUSE_BASE)
|
||||||
#define FUSE_RESERVED_ODM4 0x1d8
|
#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;
|
return (read32(FUSE_BASE + FUSE_RESERVED_ODM4) & 0x38) >> 3;
|
||||||
}
|
}
|
||||||
|
@ -48,3 +48,8 @@ const struct sdram_params *get_sdram_config()
|
||||||
|
|
||||||
return &sdram_configs[id];
|
return &sdram_configs[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ram_code(void)
|
||||||
|
{
|
||||||
|
return switch_sdram_get_id();
|
||||||
|
}
|
||||||
|
|
|
@ -142,6 +142,24 @@ config MTC_ADDRESS
|
||||||
The DRAM location where MTC firmware to be loaded in. This location
|
The DRAM location where MTC firmware to be loaded in. This location
|
||||||
needs to be consistent with the location defined in tegra_mtc.ld
|
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 # HAVE_MTC
|
||||||
|
|
||||||
endif # SOC_NVIDIA_TEGRA210
|
endif # SOC_NVIDIA_TEGRA210
|
||||||
|
|
|
@ -162,4 +162,18 @@ cbfs-files-$(CONFIG_HAVE_MTC) += $(MTC_FILE_CBFS)
|
||||||
$(MTC_FILE_CBFS)-file := $(MTC_FILE)
|
$(MTC_FILE_CBFS)-file := $(MTC_FILE)
|
||||||
$(MTC_FILE_CBFS)-type := raw
|
$(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
|
endif
|
||||||
|
|
|
@ -20,6 +20,89 @@
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_HAVE_MTC)
|
#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);
|
int tegra210_run_mtc(void);
|
||||||
void soc_add_mtc(struct lb_header *header);
|
void soc_add_mtc(struct lb_header *header);
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,14 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <arch/io.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <cbmem.h>
|
#include <cbmem.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <soc/mtc.h>
|
#include <soc/mtc.h>
|
||||||
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/clock.h>
|
||||||
|
#include <boardid.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static size_t mtc_table_size;
|
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_ENTRY_SIZE 4880
|
||||||
#define MTC_TABLE_MAX_SIZE (MAX_MTC_TABLE_ENTRIES * MTC_TABLE_ENTRY_SIZE)
|
#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)
|
int tegra210_run_mtc(void)
|
||||||
{
|
{
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
|
@ -53,6 +162,7 @@ int tegra210_run_mtc(void)
|
||||||
|
|
||||||
printk(BIOS_INFO, "MTC: %zu bytes loaded @ %p\n", nread, mtc);
|
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);
|
mtc_table_size = (*mtc_fw)(&dvfs_table);
|
||||||
|
|
||||||
if ((mtc_table_size == 0) || (mtc_table_size > MTC_TABLE_MAX_SIZE)) {
|
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);
|
memcpy(cbmem_tab, dvfs_table, mtc_table_size);
|
||||||
printk(BIOS_INFO, "MTC: Copied 0x%zx bytes from %p to %p\n",
|
printk(BIOS_INFO, "MTC: Copied 0x%zx bytes from %p to %p\n",
|
||||||
mtc_table_size, dvfs_table, cbmem_tab);
|
mtc_table_size, dvfs_table, cbmem_tab);
|
||||||
|
#else
|
||||||
|
return train_all(mtc);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <arch/clock.h>
|
#include <arch/clock.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <arch/stages.h>
|
#include <arch/stages.h>
|
||||||
|
#include <cbmem.h>
|
||||||
#include <gic.h>
|
#include <gic.h>
|
||||||
#include <soc/addressmap.h>
|
#include <soc/addressmap.h>
|
||||||
#include <soc/clock.h>
|
#include <soc/clock.h>
|
||||||
|
@ -68,6 +69,9 @@ void ramstage_entry(void)
|
||||||
|
|
||||||
clock_init_arm_generic_timer();
|
clock_init_arm_generic_timer();
|
||||||
|
|
||||||
|
/* Needed to store MTC data */
|
||||||
|
cbmem_initialize();
|
||||||
|
|
||||||
if (tegra210_run_mtc() != 0)
|
if (tegra210_run_mtc() != 0)
|
||||||
printk(BIOS_ERR, "MTC: No training data.\n");
|
printk(BIOS_ERR, "MTC: No training data.\n");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue