tegrakernel/kernel/nvidia/drivers/platform/tegra/mc/emc_bwmgr-t19x.c

883 lines
23 KiB
C

/**
* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/platform/tegra/bwmgr_mc.h>
#include <linux/platform/tegra/emc_bwmgr.h>
#include <linux/io.h>
#include <soc/tegra/bpmp_abi.h>
#include <soc/tegra/tegra_bpmp.h>
#include <soc/tegra/chip-id.h>
/* T194 dram freq table */
static u32 bwmgr_t194_dram_freq_table[] = { /* MHz */
68, 102, 204, 408, 600,
792, 924, 1056, 1200, 1600,
1866, 2133
};
/* ALL VALUES BELOW CORRESPOND TO FREQ in bwmgr_t194_dram_freq_table */
/* efficiency percentage 8ch ecc 4X 1-rank*/
static u32 bwmgr_t194_8ch_ecc_4X_1rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 4ch ecc 4X 1-rank*/
static u32 bwmgr_t194_4ch_ecc_4X_1rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 16ch ecc 4X 1-rank*/
static u32 bwmgr_t194_16ch_ecc_4X_1rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 8ch 4X 1-rank*/
static u32 bwmgr_t194_8ch_4X_1rank_eff[] = { /* % */
30, 30, 30, 30, 30,
30, 40, 40, 40, 70,
70, 70
};
/* efficiency percentage 4ch 4X 1-rank*/
static u32 bwmgr_t194_4ch_4X_1rank_eff[] = { /* % */
30, 30, 30, 30, 30,
30, 40, 40, 40, 70,
70, 70
};
/* efficiency percentage 16ch 4X 1-rank*/
static u32 bwmgr_t194_16ch_4X_1rank_eff[] = { /* % */
30, 30, 30, 30, 30,
30, 40, 40, 40, 70,
70, 70
};
/* efficiency percentage 8ch ecc 4X 2-rank*/
static u32 bwmgr_t194_8ch_ecc_4X_2rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 4ch ecc 4X 2-rank*/
static u32 bwmgr_t194_4ch_ecc_4X_2rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 16ch ecc 4X 2-rank*/
static u32 bwmgr_t194_16ch_ecc_4X_2rank_eff[] = { /* % */
20, 20, 20, 20, 20,
20, 30, 30, 30, 55,
55, 60
};
/* efficiency percentage 8ch 4X 2-rank*/
static u32 bwmgr_t194_8ch_4X_2rank_eff[] = { /* % */
25, 25, 25, 25, 25,
25, 40, 40, 40, 65,
65, 65
};
/* efficiency percentage 4ch 4X 2-rank*/
static u32 bwmgr_t194_4ch_4X_2rank_eff[] = { /* % */
25, 25, 25, 25, 25,
25, 40, 40, 40, 65,
65, 65
};
/* efficiency percentage 16ch 4X 2-rank*/
static u32 bwmgr_t194_16ch_4X_2rank_eff[] = { /* % */
30, 30, 30, 30, 30,
30, 35, 35, 35, 65,
65, 65
};
/* efficiency percentage 8ch ecc 1X 1-rank*/
static u32 bwmgr_t194_8ch_ecc_1X_1rank_eff[] = { /* % */
45, 45, 45, 45, 45,
45, 50, 50, 50, 65,
65, 70
};
/* efficiency percentage 4ch ecc 1X 1-rank*/
static u32 bwmgr_t194_4ch_ecc_1X_1rank_eff[] = { /* % */
45, 45, 45, 45, 45,
45, 50, 50, 50, 65,
65, 70
};
/* efficiency percentage 16ch ecc 1X 1-rank*/
static u32 bwmgr_t194_16ch_ecc_1X_1rank_eff[] = { /* % */
40, 40, 40, 40, 40,
40, 50, 50, 50, 65,
65, 70
};
/* efficiency percentage 8ch 1X 1-rank*/
static u32 bwmgr_t194_8ch_1X_1rank_eff[] = { /* % */
60, 60, 60, 60, 60,
60, 60, 60, 60, 80,
80, 80
};
/* efficiency percentage 4ch 1X 1-rank*/
static u32 bwmgr_t194_4ch_1X_1rank_eff[] = { /* % */
60, 60, 60, 60, 60,
60, 60, 60, 60, 80,
80, 80
};
/* efficiency percentage 16ch 1X 1-rank*/
static u32 bwmgr_t194_16ch_1X_1rank_eff[] = { /* % */
60, 60, 60, 60, 60,
60, 60, 60, 60, 80,
80, 80
};
/* efficiency percentage 8ch ecc 1X 2-rank*/
static u32 bwmgr_t194_8ch_ecc_1X_2rank_eff[] = { /* % */
40, 40, 40, 40, 40,
40, 45, 45, 45, 60,
55, 55
};
/* efficiency percentage 4ch ecc 1X 2-rank*/
static u32 bwmgr_t194_4ch_ecc_1X_2rank_eff[] = { /* % */
40, 40, 40, 40, 40,
40, 45, 45, 45, 60,
55, 55
};
/* efficiency percentage 16ch ecc 1X 2-rank*/
static u32 bwmgr_t194_16ch_ecc_1X_2rank_eff[] = { /* % */
40, 40, 40, 40, 40,
40, 50, 50, 50, 60,
55, 55
};
/* efficiency percentage 8ch 1X 2-rank*/
static u32 bwmgr_t194_8ch_1X_2rank_eff[] = { /* % */
55, 55, 55, 55, 55,
55, 55, 55, 55, 70,
70, 70
};
/* efficiency percentage 4ch 1X 2-rank*/
static u32 bwmgr_t194_4ch_1X_2rank_eff[] = { /* % */
55, 55, 55, 55, 55,
55, 55, 55, 55, 70,
70, 70
};
/* efficiency percentage 16ch 1X 2-rank*/
static u32 bwmgr_t194_16ch_1X_2rank_eff[] = { /* % */
55, 55, 55, 55, 55,
55, 55, 55, 55, 70,
70, 70
};
/* max nvdis bw req in MHz
* The value below reflects the maximum display bandwidth supported
* at the frequency corresponding to the same index in
* dram freq table.
*/
static u32 bwmgr_t194_lpddr4_8ch_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 22, 66, 107,
148, 177, 205, 237, 437,
656, 684
};
static u32 bwmgr_t194_lpddr4_4ch_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 22, 66, 107,
148, 177, 205, 237, 437,
656, 684
};
static u32 bwmgr_t194_lpddr4_16ch_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 11, 33, 53,
74, 88, 102, 167, 347,
361, 375
};
static u32 bwmgr_t194_lpddr4_8ch_ecc_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 26, 80, 131,
169, 196, 222, 251, 397,
494, 591
};
static u32 bwmgr_t194_lpddr4_4ch_ecc_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 26, 80, 131,
169, 196, 222, 251, 397,
494, 591
};
static u32 bwmgr_t194_lpddr4_16ch_ecc_iso_max_nvdis_bw_reqd[] = { /* MHz */
0, 0, 14, 43, 70,
98, 116, 135, 156, 250,
312, 375
};
/* max vi bw req in MHz
* The value below reflects the maximum vi bandwidth supported
* at the frequency corresponding to the same index in
* dram freq table.
*/
static u32 bwmgr_t194_lpddr4_8ch_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 14, 42, 68,
95, 113, 131, 151, 279,
279, 279
};
static u32 bwmgr_t194_lpddr4_4ch_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 14, 42, 68,
95, 113, 131, 151, 279,
279, 279
};
static u32 bwmgr_t194_lpddr4_16ch_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 8, 24, 40,
55, 66, 76, 88, 139,
139, 139
};
static u32 bwmgr_t194_lpddr4_8ch_ecc_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 11, 34, 56,
78, 93, 108, 124, 279,
279, 279
};
static u32 bwmgr_t194_lpddr4_4ch_ecc_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 11, 34, 56,
78, 93, 108, 124, 279,
279, 279
};
static u32 bwmgr_t194_lpddr4_16ch_ecc_iso_max_vi_bw_reqd[] = { /* MHz */
0, 0, 6, 19, 31,
43, 52, 60, 69, 139,
139, 139
};
/* slope for calculating eff
* The value below reflects the slope
* at the frequency corresponding to the same index in
* dram freq table.
*/
static int bwmgr_t194_lpddr4_8ch_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1
};
static int bwmgr_t194_lpddr4_4ch_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1
};
static int bwmgr_t194_lpddr4_16ch_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1
};
static int bwmgr_t194_lpddr4_8ch_ecc_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -2
};
static int bwmgr_t194_lpddr4_4ch_ecc_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -2
};
static int bwmgr_t194_lpddr4_16ch_ecc_iso_slope[] = {
-1, -1, -1, -1, -1,
-1, -1, -1, -1, -1,
-1, -1
};
/* vi offset bw req in MHz
* The value below reflects the vi offset
* at the frequency corresponding to the same index in
* dram freq table.
*/
static u32 bwmgr_t194_lpddr4_8ch_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
};
static u32 bwmgr_t194_lpddr4_4ch_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
};
static u32 bwmgr_t194_lpddr4_16ch_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 37
};
static u32 bwmgr_t194_lpddr4_8ch_ecc_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
};
static u32 bwmgr_t194_lpddr4_4ch_ecc_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0
};
static u32 bwmgr_t194_lpddr4_16ch_ecc_iso_vi_bw_reqd_offset[] = { /* MHz */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 37
};
static struct mrq_emc_dvfs_latency_response bwmgr_emc_dvfs;
static int dram_rank;
static int dram_freq_count;
#define MC_BASE 0x02c10000
#define EMC_BASE 0x02c60000
#define MC_EMEM_ADR_CFG_CHANNEL_ENABLE_0 0xdf8
#define MC_EMEM_ADR_CFG_0 0x54
#define MC_ECC_CONTROL_0 0x1880
#define EMC_FBIO_CFG5_0 0x104
#define CH_MASK 0xFFFF /* Change bit counting if this mask changes */
#define CH4 0xf
#define CH2 0x3
#define ECC_MASK 0x1 /* 1 = enabled, 0 = disabled */
#define RANK_MASK 0x1 /* 1 = 2-RANK, 0 = 1-RANK */
#define DRAM_MASK 0x3
#define DRAM_DDR3 0
#define DRAM_LPDDR4 1
#define DRAM_LPDDR3 2 /* On T186 this value is LPDDR3 */
#define DRAM_DDR2 3
#define DRAM_REFRESH_1X 0
#define DRAM_REFRESH_4X 1
static unsigned long get_best_iso_freq(long total_iso_bw, long iso_bw_nvdis,
long iso_bw_vi)
{
long max_nvdis_bw_reqd_mhz = 0;
long max_vi_bw_reqd_mhz = 0;
long slope = -1;
long vi_bw_reqd_offset_mhz = 0;
int i;
unsigned long dram_freq_mhz = 0;
if (!bwmgr_dram_config_supported)
return dram_freq_mhz;
/*Input is in Hz, converting into MHz*/
total_iso_bw /= 1000000;
iso_bw_nvdis /= 1000000;
iso_bw_vi /= 1000000;
for (i = 0; i < dram_freq_count; i++) {
max_nvdis_bw_reqd_mhz = bwmgr_max_nvdis_bw_reqd[i];
max_vi_bw_reqd_mhz = bwmgr_max_vi_bw_reqd[i];
slope = bwmgr_slope[i];
vi_bw_reqd_offset_mhz = bwmgr_vi_bw_reqd_offset[i];
if (!(iso_bw_nvdis <= max_nvdis_bw_reqd_mhz))
continue;
if (!(iso_bw_vi <= max_vi_bw_reqd_mhz))
continue;
if (!(iso_bw_vi <= (slope * (iso_bw_nvdis -
max_nvdis_bw_reqd_mhz) + vi_bw_reqd_offset_mhz)))
continue;
if (!(total_iso_bw <= (slope *
(iso_bw_nvdis - max_nvdis_bw_reqd_mhz)
+ vi_bw_reqd_offset_mhz + iso_bw_nvdis)))
continue;
dram_freq_mhz = bwmgr_t194_dram_freq_table[i] * 1000000;
break;
}
return dram_freq_mhz;
}
static unsigned long freq_to_bw(unsigned long freq)
{
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH_ECC ||
bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH)
return freq * 64;
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH_ECC ||
bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH)
return freq * 32;
/*4CH and 4CH_ECC*/
return freq * 16;
}
static unsigned long bw_to_freq(unsigned long bw)
{
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH_ECC ||
bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH)
return (bw + 64 - 1) / 64;
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH_ECC ||
bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH)
return (bw + 32 - 1) / 32;
/*4CH and 4CH_ECC*/
return (bw + 16 - 1) / 16;
}
static u32 dvfs_latency(u32 ufreq)
{
u32 lt = 80000; /* default value of 80000 nsec */
int i;
if (bwmgr_emc_dvfs.num_pairs <= 0)
return lt / 1000; /* convert nsec to usec, Bug 1697424 */
for (i = 0; i < bwmgr_emc_dvfs.num_pairs; i++) {
if (ufreq <= bwmgr_emc_dvfs.pairs[i].freq) {
lt = bwmgr_emc_dvfs.pairs[i].latency;
break;
}
}
if (i >= bwmgr_emc_dvfs.num_pairs)
lt =
bwmgr_emc_dvfs.pairs[bwmgr_emc_dvfs.num_pairs - 1].latency;
return lt / 1000; /* convert nsec to usec, Bug 1697424 */
}
static unsigned long t19x_bwmgr_apply_efficiency(
unsigned long total_bw, unsigned long iso_bw,
unsigned long max_rate, u64 usage_flags,
unsigned long *iso_bw_min, unsigned long iso_bw_nvdis,
unsigned long iso_bw_vi)
{
int i;
unsigned long total_bw_mhz, freq_after_eff_mhz;
u8 efficiency;
bool bw_req_satisfied = 1;
if (total_bw) {
total_bw_mhz = total_bw / 1000000;
/* loop over all dram freq and its corresponding
* efficiency and check if total bw request can
* satisfied at that freq
*/
for (i = 0; i < dram_freq_count; i++) {
efficiency = bwmgr_dram_noniso_eff_table[i];
freq_after_eff_mhz = bwmgr_t194_dram_freq_table[i] *
efficiency;
freq_after_eff_mhz /= 100;
if (total_bw_mhz < freq_after_eff_mhz) {
total_bw = bwmgr_t194_dram_freq_table[i] *
1000000;
bw_req_satisfied = 0;
break;
}
}
/*defaults to max emc rate if reqd rate is not satisfied*/
if (bw_req_satisfied)
total_bw = max_rate;
}
// This functions loops over the available dram freq and returns the
//lowest freq which can satisfy the *iso* bw requirement
iso_bw = get_best_iso_freq(iso_bw, iso_bw_nvdis, iso_bw_vi);
if (iso_bw_min)
*iso_bw_min = iso_bw;
return max(total_bw, iso_bw);
}
static void t19x_update_efficiency(unsigned long dram_refresh_rate)
{
if ((dram_refresh_rate != DRAM_REFRESH_4X) &&
(dram_refresh_rate != DRAM_REFRESH_1X)) {
pr_err("bwmgr:Unknown cooling state. Set 4X refresh co-eff\n");
dram_refresh_rate = DRAM_REFRESH_4X;
}
if (dram_refresh_rate == DRAM_REFRESH_4X) {
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_4X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_4X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_4CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_4X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_4X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_4X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_4CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_4X_1rank_eff;
}
} else if (dram_refresh_rate == DRAM_REFRESH_1X) {
if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_1X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_1X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_4CH_ECC) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_1X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_16CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_1X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_8CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_1X_1rank_eff;
} else if (bwmgr_dram_type == DRAM_TYPE_LPDDR4_4CH) {
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_1X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_1X_1rank_eff;
}
}
}
static int get_dram_freq_table_idx(unsigned long emc_rate)
{
int i = ARRAY_SIZE(bwmgr_t194_dram_freq_table) - 1;
/* emc_rate is in Hz, dram_freq table's unit is MHz */
emc_rate /= 1000000;
while (i > 0 && bwmgr_t194_dram_freq_table[i] > emc_rate)
i--;
return i;
}
static u32 t19x_get_max_iso_bw(enum tegra_iso_client client)
{
u8 idx = 0;
unsigned long emc_max_rate = tegra_bwmgr_get_max_emc_rate();
idx = get_dram_freq_table_idx(emc_max_rate);
if ((client == TEGRA_ISO_CLIENT_DISP_0) ||
(client == TEGRA_ISO_CLIENT_DISP_1) ||
(client == TEGRA_ISO_CLIENT_DISP_2))
return bwmgr_freq_to_bw(bwmgr_max_nvdis_bw_reqd[idx] * 1000);
else if (client == TEGRA_ISO_CLIENT_TEGRA_CAMERA)
return bwmgr_freq_to_bw(bwmgr_max_vi_bw_reqd[idx] * 1000);
else
return bwmgr_freq_to_bw((((bwmgr_slope[idx] *
bwmgr_max_nvdis_bw_reqd[idx]) +
bwmgr_vi_bw_reqd_offset[idx]) - 1) * 1000);
}
static struct bwmgr_ops bwmgr_ops_t19x = {
.get_best_iso_freq = get_best_iso_freq,
.freq_to_bw = freq_to_bw,
.bw_to_freq = bw_to_freq,
.dvfs_latency = dvfs_latency,
.bwmgr_apply_efficiency = t19x_bwmgr_apply_efficiency,
.update_efficiency = t19x_update_efficiency,
.get_max_iso_bw = t19x_get_max_iso_bw,
};
struct bwmgr_ops *bwmgr_eff_init_t19x(void)
{
int ch_num = 0;
u32 dram, ch, ecc;
void __iomem *mc_base, *emc_base;
mc_base = ioremap(MC_BASE, 0x00010000);
emc_base = ioremap(EMC_BASE, 0x00010000);
dram = readl(emc_base + EMC_FBIO_CFG5_0) & DRAM_MASK;
ch = readl(mc_base + MC_EMEM_ADR_CFG_CHANNEL_ENABLE_0) & CH_MASK;
ecc = readl(mc_base + MC_ECC_CONTROL_0) & ECC_MASK;
dram_rank = readl(mc_base + MC_EMEM_ADR_CFG_0) & RANK_MASK;
iounmap(emc_base);
iounmap(mc_base);
while (ch) {
if (ch & 1)
ch_num++;
ch >>= 1;
}
/* pre silicon use LPDDR4 16ch no ecc 1-rank config*/
if (tegra_platform_is_sim() || tegra_platform_is_fpga()) {
dram = DRAM_LPDDR4;
ch_num = 16;
}
bwmgr_dram_num_channels = ch_num;
/* T194 platforms should only have LPDDR4 */
switch (dram) {
case DRAM_LPDDR4:
if (ecc) {
if (ch_num == 16) {
bwmgr_dram_type =
DRAM_TYPE_LPDDR4_16CH_ECC;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_ecc_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_16ch_ecc_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_16ch_ecc_iso_max_vi_bw_reqd;
bwmgr_slope =
bwmgr_t194_lpddr4_16ch_ecc_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_16ch_ecc_iso_vi_bw_reqd_offset;
} else if (ch_num == 8) {
bwmgr_dram_type =
DRAM_TYPE_LPDDR4_8CH_ECC;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_ecc_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_8ch_ecc_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_8ch_ecc_iso_max_vi_bw_reqd;
bwmgr_slope =
bwmgr_t194_lpddr4_8ch_ecc_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_8ch_ecc_iso_vi_bw_reqd_offset;
} else if (ch_num == 4) {
bwmgr_dram_type =
DRAM_TYPE_LPDDR4_4CH_ECC;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_ecc_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_4ch_ecc_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_4ch_ecc_iso_max_vi_bw_reqd;
bwmgr_slope =
bwmgr_t194_lpddr4_4ch_ecc_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_4ch_ecc_iso_vi_bw_reqd_offset;
}
} else {
if (ch_num == 16) {
bwmgr_dram_type = DRAM_TYPE_LPDDR4_16CH;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_16ch_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_16ch_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_16ch_iso_max_vi_bw_reqd;
bwmgr_slope = bwmgr_t194_lpddr4_16ch_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_16ch_iso_vi_bw_reqd_offset;
} else if (ch_num == 8) {
bwmgr_dram_type = DRAM_TYPE_LPDDR4_8CH;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_8ch_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_8ch_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_8ch_iso_max_vi_bw_reqd;
bwmgr_slope = bwmgr_t194_lpddr4_8ch_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_8ch_iso_vi_bw_reqd_offset;
} else if (ch_num == 4) {
bwmgr_dram_type = DRAM_TYPE_LPDDR4_4CH;
if (dram_rank)
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_4X_2rank_eff;
else
bwmgr_dram_noniso_eff_table =
bwmgr_t194_4ch_4X_1rank_eff;
bwmgr_max_nvdis_bw_reqd =
bwmgr_t194_lpddr4_4ch_iso_max_nvdis_bw_reqd;
bwmgr_max_vi_bw_reqd =
bwmgr_t194_lpddr4_4ch_iso_max_vi_bw_reqd;
bwmgr_slope = bwmgr_t194_lpddr4_4ch_iso_slope;
bwmgr_vi_bw_reqd_offset =
bwmgr_t194_lpddr4_4ch_iso_vi_bw_reqd_offset;
}
}
if (ch_num < 4) {
pr_err("bwmgr: Unknown memory channel configuration\n");
pr_err("bwmgr: ddr config not supported\n");
WARN_ON(true);
} else {
emc_to_dram_freq_factor = 2;
/* valid ddr configuration */
bwmgr_dram_config_supported = 1;
}
break;
case DRAM_LPDDR3:
pr_err("bwmgr: ddr config not supported\n");
WARN_ON(true);
break;
case DRAM_DDR3:
pr_err("bwmgr: ddr config not supported\n");
WARN_ON(true);
break;
case DRAM_DDR2:
pr_err("bwmgr: ddr config not supported\n");
WARN_ON(true);
break;
default:
pr_err("bwmgr: ddr config not supported\n");
WARN_ON(true);
}
dram_freq_count = ARRAY_SIZE(bwmgr_t194_dram_freq_table);
tegra_bpmp_send_receive(MRQ_EMC_DVFS_LATENCY, NULL, 0,
&bwmgr_emc_dvfs, sizeof(bwmgr_emc_dvfs));
/* isomgr uses this value to calculate max_iso_bw.
* We need this until the isomgr framework changes are checked in.
*/
bwmgr_iso_bw_percentage = 28;
return &bwmgr_ops_t19x;
}