tegrakernel/kernel/nvidia/drivers/platform/tegra/mc/tegra21x_la.c

935 lines
30 KiB
C
Raw Permalink Normal View History

2022-02-16 09:13:02 -06:00
/*
* Copyright (C) 2014-2018, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/types.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <linux/platform/tegra/latency_allowance.h>
#include <linux/platform/tegra/mc-regs-t21x.h>
#include <linux/platform/tegra/mc.h>
#include <soc/tegra/chip-id.h>
#include "la_priv.h"
#define ON_LPDDR4() (tegra_emc_get_dram_type() == DRAM_TYPE_LPDDR4)
#define LA_ST_LA_MINUS_SNAP_ARB_TO_ROW_SRT_EMCCLKS_FP 70000
#define LA_DRAM_WIDTH_BITS 64
#define LA_DISP_CATCHUP_FACTOR_FP 1100
#define MC_MAX_FREQ_MHZ 533
#define MAX_GRANT_DEC 511
#define EXP_TIME_EMCCLKS_FP 88000
#define MAX_LA_NSEC 7650
#define DDA_BW_MARGIN_FP 1100
#define ONE_DDA_FRAC_FP 10
#define CPU_RD_BW_PERC 9
#define CPU_WR_BW_PERC 1
#define MIN_CYCLES_PER_GRANT 2
#define EMEM_PTSA_MINMAX_WIDTH 5
#define RING1_FEEDER_SISO_ALLOC_DIV 2
static struct la_client_info t21x_la_info_array[] = {
LA(0, 0, AFI_0, 23 : 16, AFIW, false, 128, 800),
LA(0, 0, AFI_0, 7 : 0, AFIR, false, 59, 400),
LA(0, 0, AVPC_0, 7 : 0, AVPC_ARM7R, false, 4, 0),
LA(0, 0, AVPC_0, 23 : 16, AVPC_ARM7W, false, 128, 800),
LA(0, 0, DC_0, 7 : 0, DISPLAY_0A, true, 80, 0),
LA(0, 0, DCB_0, 7 : 0, DISPLAY_0AB, true, 80, 0),
LA(0, 0, DC_0, 23 : 16, DISPLAY_0B, true, 80, 0),
LA(0, 0, DCB_0, 23 : 16, DISPLAY_0BB, true, 80, 0),
LA(0, 0, DC_1, 7 : 0, DISPLAY_0C, true, 80, 0),
LA(0, 0, DCB_1, 7 : 0, DISPLAY_0CB, true, 80, 0),
LA(0, 0, DC_3, 7 : 0, DISPLAYD, false, 80, 0),
LA(0, 0, DC_2, 7 : 0, DISPLAY_HC, false, 80, 0),
LA(0, 0, DCB_2, 7 : 0, DISPLAY_HCB, false, 80, 0),
LA(0, 0, DC_2, 23 : 16, DISPLAY_T, false, 80, 0),
LA(0, 0, GPU_0, 7 : 0, GPUSRD, false, 25, 800),
LA(0, 0, GPU_0, 23 : 16, GPUSWR, false, 128, 800),
LA(0, 0, HDA_0, 7 : 0, HDAR, false, 36, 0),
LA(0, 0, HDA_0, 23 : 16, HDAW, false, 128, 800),
LA(0, 0, TSEC_0, 7 : 0, TSECSRD, false, 157, 200),
LA(0, 0, TSEC_0, 23 : 16, TSECSWR, false, 128, 800),
LA(0, 0, TSECB_0, 7 : 0, TSECBSRD, false, 157, 200),
LA(0, 0, TSECB_0, 23 : 16, TSECBSWR, false, 128, 800),
LA(0, 0, HC_0, 7 : 0, HOST1X_DMAR, false, 28, 800),
LA(0, 0, HC_0, 23 : 16, HOST1XR, false, 80, 0),
LA(0, 0, HC_1, 7 : 0, HOST1XW, false, 128, 800),
LA(0, 0, ISP2_0, 7 : 0, ISP_RA, false, 51, 300),
LA(0, 0, ISP2_1, 7 : 0, ISP_WA, false, 128, 800),
LA(0, 0, ISP2_1, 23 : 16, ISP_WB, false, 128, 800),
LA(0, 0, ISP2B_0, 7 : 0, ISP_RAB, false, 54, 300),
LA(0, 0, ISP2B_1, 7 : 0, ISP_WAB, false, 128, 800),
LA(0, 0, ISP2B_1, 23 : 16, ISP_WBB, false, 128, 800),
LA(0, 0, MPCORE_0, 7 : 0, MPCORER, false, 4, 0),
LA(0, 0, MPCORE_0, 23 : 16, MPCOREW, false, 128, 800),
LA(0, 0, NVDEC_0, 7 : 0, NVDECR, false, 4, 0),
LA(0, 0, NVDEC_0, 23 : 16, NVDECW, false, 128, 800),
/* No entries for nvenc and nvjpg ?? */
/* LA(0, 0, PPCS_1, 7 : 0, PPCS_AHBDMAW, true, 128, 800), */
LA(0, 0, PPCS_0, 23 : 16, PPCS_AHBSLVR, false, 89, 408),
LA(0, 0, PPCS_1, 23 : 16, PPCS_AHBSLVW, false, 128, 800),
LA(0, 0, PTC_0, 7 : 0, PTCR, false, 0, 0),
LA(0, 0, SATA_0, 7 : 0, SATAR, false, 104, 400),
LA(0, 0, SATA_0, 23 : 16, SATAW, false, 128, 800),
LA(0, 0, SDMMC_0, 7 : 0, SDMMCR, false, 150, 248),
LA(0, 0, SDMMCA_0, 7 : 0, SDMMCRA, false, 150, 248),
LA(0, 0, SDMMCAA_0, 7 : 0, SDMMCRAA, false, 88, 248),
LA(0, 0, SDMMCAB_0, 7 : 0, SDMMCRAB, false, 88, 248),
LA(0, 0, SDMMC_0, 23 : 16, SDMMCW, false, 128, 800),
LA(0, 0, SDMMCA_0, 23 : 16, SDMMCWA, false, 128, 800),
LA(0, 0, SDMMCAA_0, 23 : 16, SDMMCWAA, false, 128, 800),
LA(0, 0, SDMMCAB_0, 23 : 16, SDMMCWAB, false, 128, 800),
LA(0, 0, VIC_0, 7 : 0, VICSRD, false, 29, 800),
LA(0, 0, VIC_0, 23 : 16, VICSWR, false, 128, 800),
LA(0, 0, VI2_0, 7 : 0, VI_W, false, 128, 800),
LA(0, 0, XUSB_1, 7 : 0, XUSB_DEVR, false, 59, 400),
LA(0, 0, XUSB_1, 23 : 16, XUSB_DEVW, false, 128, 800),
LA(0, 0, XUSB_0, 7 : 0, XUSB_HOSTR, false, 66, 400),
LA(0, 0, XUSB_0, 23 : 16, XUSB_HOSTW, false, 128, 800),
/* end of list */
LA(0, 0, DC_3, 0 : 0, MAX_ID, false, 0, 0)
};
static unsigned int emc_min_freq_mhz_fp;
static unsigned int emc_min_freq_mhz;
static unsigned int emc_max_freq_mhz;
static unsigned int hi_gd_fp;
static unsigned int lo_gd_fp;
static unsigned int hi_gd_fpa;
static unsigned int lo_gd_fpa;
static unsigned int low_freq_bw;
static unsigned int dda_div;
static struct la_chip_specific *cs;
const struct disp_client *tegra_la_disp_clients_info;
static unsigned int total_dc0_bw;
static unsigned int total_dc1_bw;
static DEFINE_MUTEX(disp_and_camera_ptsa_lock);
static void program_ptsa(void)
{
struct ptsa_info *p = &cs->ptsa_info;
mc_writel(p->ptsa_grant_dec, MC_PTSA_GRANT_DECREMENT);
mc_writel(1, MC_TIMING_CONTROL);
mc_writel(p->dis_extra_snap_level, MC_DIS_EXTRA_SNAP_LEVELS);
WRITE_PTSA_MIN_MAX_RATE(p, dis, DIS);
WRITE_PTSA_MIN_MAX_RATE(p, disb, DISB);
WRITE_PTSA_MIN_MAX_RATE(p, ve, VE);
WRITE_PTSA_MIN_MAX_RATE(p, ve2, VE2);
WRITE_PTSA_MIN_MAX_RATE(p, ring2, RING2);
WRITE_PTSA_MIN_MAX_RATE(p, mpcorer, MLL_MPCORER);
WRITE_PTSA_MIN_MAX_RATE(p, smmu, SMMU_SMMU);
WRITE_PTSA_MIN_MAX_RATE(p, ring1, RING1);
WRITE_PTSA_MIN_MAX_RATE(p, isp, ISP);
WRITE_PTSA_MIN_MAX(p, a9avppc, A9AVPPC);
WRITE_PTSA_MIN_MAX(p, avp, AVP);
WRITE_PTSA_MIN_MAX(p, mse, MSE);
WRITE_PTSA_MIN_MAX(p, gk, GK);
WRITE_PTSA_MIN_MAX(p, vicpc, VICPC);
WRITE_PTSA_MIN_MAX(p, apb, APB);
WRITE_PTSA_MIN_MAX(p, pcx, PCX);
WRITE_PTSA_MIN_MAX(p, host, HOST);
WRITE_PTSA_MIN_MAX(p, ahb, AHB);
WRITE_PTSA_MIN_MAX(p, sax, SAX);
WRITE_PTSA_MIN_MAX(p, aud, AUD);
WRITE_PTSA_MIN_MAX(p, sd, SD);
WRITE_PTSA_MIN_MAX(p, usbx, USBX);
WRITE_PTSA_MIN_MAX(p, usbd, USBD);
WRITE_PTSA_MIN_MAX(p, ftop, FTOP);
}
static void save_ptsa(void)
{
struct ptsa_info *p = &cs->ptsa_info;
p->ptsa_grant_dec = mc_readl(MC_PTSA_GRANT_DECREMENT);
p->dis_extra_snap_level = mc_readl(MC_DIS_EXTRA_SNAP_LEVELS);
READ_PTSA_MIN_MAX_RATE(p, dis, DIS);
READ_PTSA_MIN_MAX_RATE(p, disb, DISB);
READ_PTSA_MIN_MAX_RATE(p, ve, VE);
READ_PTSA_MIN_MAX_RATE(p, ve2, VE2);
READ_PTSA_MIN_MAX_RATE(p, ring2, RING2);
READ_PTSA_MIN_MAX_RATE(p, mpcorer, MLL_MPCORER);
READ_PTSA_MIN_MAX_RATE(p, smmu, SMMU_SMMU);
READ_PTSA_MIN_MAX_RATE(p, ring1, RING1);
READ_PTSA_MIN_MAX_RATE(p, isp, ISP);
READ_PTSA_MIN_MAX(p, a9avppc, A9AVPPC);
READ_PTSA_MIN_MAX(p, avp, AVP);
READ_PTSA_MIN_MAX(p, mse, MSE);
READ_PTSA_MIN_MAX(p, gk, GK);
READ_PTSA_MIN_MAX(p, vicpc, VICPC);
READ_PTSA_MIN_MAX(p, apb, APB);
READ_PTSA_MIN_MAX(p, apb, APB);
READ_PTSA_MIN_MAX(p, host, HOST);
READ_PTSA_MIN_MAX(p, ahb, AHB);
READ_PTSA_MIN_MAX(p, sax, SAX);
READ_PTSA_MIN_MAX(p, aud, AUD);
READ_PTSA_MIN_MAX(p, sd, SD);
READ_PTSA_MIN_MAX(p, usbx, USBX);
READ_PTSA_MIN_MAX(p, usbd, USBD);
READ_PTSA_MIN_MAX(p, ftop, FTOP);
}
/*
* Gets the memory BW in MBps. @emc_freq should be in MHz.
*/
static u32 get_mem_bw_mbps(u32 dram_freq)
{
return dram_freq * 16;
}
static bool is_t210b01_soc(void)
{
u32 chipid, major;
chipid = tegra_hidrev_get_chipid(tegra_read_chipid());
major = tegra_hidrev_get_majorrev(tegra_read_chipid());
if (chipid == TEGRA210B01 && major >= 2)
return true;
return false;
}
/*
* EMC frequency is actually DRAM frequency. Normally they are one in the same;
* however, with LPDDR4 DRAM, the DRAM clock goes to 1600MHz which the EMC clock
* cannot. Thus the EMC is actually running at DRAM clk / 2.
*/
static void t21x_init_ptsa(void)
{
struct clk *emc_clk;
unsigned int emc_freq_mhz;
unsigned int mc_freq_mhz;
unsigned int same_freq;
struct ptsa_info *p = &cs->ptsa_info;
unsigned int cpu_rd_bw, cpu_wr_bw;
unsigned int gd_int, gd_frac_fp;
int gd_fpa;
/* get emc frequency */
emc_clk = clk_get_sys("tegra_emc", "emc");
if (IS_ERR(emc_clk))
return;
emc_freq_mhz = clk_get_rate(emc_clk) /
LA_HZ_TO_MHZ_FACTOR;
la_debug("emc clk_rate = %u MHz", emc_freq_mhz);
/* get mc frequency */
same_freq = mc_readl(MC_EMEM_ARB_MISC0) &
MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_BIT;
mc_freq_mhz = same_freq ? emc_freq_mhz : emc_freq_mhz / 2;
la_debug("mc clk_rate = %u MHz", mc_freq_mhz);
/* compute initial value for grant dec */
gd_fpa = (LA_FP_TO_FPA(lo_gd_fp) * emc_freq_mhz) / emc_min_freq_mhz;
if (gd_fpa >= LA_REAL_TO_FPA(1)) {
gd_int = 1;
gd_fpa -= LA_REAL_TO_FPA(1);
} else {
gd_int = 0;
}
gd_frac_fp = __fraction2dda_fp(gd_fpa, 1,
MC_PTSA_RATE_DEFAULT_MASK);
p->ptsa_grant_dec = (gd_int << 12) | gd_frac_fp;
/* initialize PTSA reg values */
MC_SET_INIT_PTSA(p, ve, -5, 31);
MC_SET_INIT_PTSA(p, isp, -5, 31); /* Same for T210 and T210b01 */
if (is_t210b01_soc())
MC_SET_INIT_PTSA(p, ve2, -2, 0);
else
MC_SET_INIT_PTSA(p, ve2, -5, 31);
MC_SET_INIT_PTSA(p, a9avppc, -5, 16);
MC_SET_INIT_PTSA(p, ring2, -2, 0);
MC_SET_INIT_PTSA(p, dis, -5, 31);
MC_SET_INIT_PTSA(p, disb, -5, 31);
MC_SET_INIT_PTSA(p, ring1, -5, 31);
MC_SET_INIT_PTSA(p, mpcorer, -4, 4);
MC_SET_INIT_PTSA(p, smmu, 1, 1);
MC_SET_INIT_PTSA(p, mse, -2, 0);
MC_SET_INIT_PTSA(p, gk, -2, 0);
MC_SET_INIT_PTSA(p, vicpc, -2, 0);
MC_SET_INIT_PTSA(p, apb, -2, 0);
MC_SET_INIT_PTSA(p, pcx, -2, 0);
MC_SET_INIT_PTSA(p, host, -2, 0);
MC_SET_INIT_PTSA(p, ahb, -2, 0);
MC_SET_INIT_PTSA(p, sax, -2, 0);
MC_SET_INIT_PTSA(p, sd, -2, 0);
MC_SET_INIT_PTSA(p, usbx, -2, 0);
MC_SET_INIT_PTSA(p, usbd, -2, 0);
MC_SET_INIT_PTSA(p, ftop, -2, 0);
MC_SET_INIT_PTSA(p, avp, -2, 0);
MC_SET_INIT_PTSA(p, aud, -5, 31);
MC_SET_INIT_PTSA(p, jpg, -2, 0);
MC_SET_INIT_PTSA(p, gk2, -2, 0);
p->ring2_ptsa_rate = (unsigned int)(12) & MC_PTSA_RATE_DEFAULT_MASK;
/* mpcorer */
cpu_rd_bw = (get_mem_bw_mbps(emc_freq_mhz) * CPU_RD_BW_PERC) / 100;
if (ON_LPDDR4())
cpu_rd_bw /= 2;
p->mpcorer_ptsa_rate = __fraction2dda_fp(lo_gd_fpa * cpu_rd_bw /
low_freq_bw,
dda_div,
MC_PTSA_RATE_DEFAULT_MASK);
/* FTOP (mpcorew it seems)*/
cpu_wr_bw = (get_mem_bw_mbps(emc_freq_mhz) * CPU_WR_BW_PERC) / 100;
if (ON_LPDDR4())
cpu_rd_bw /= 2;
p->ftop_ptsa_rate = __fraction2dda_fp(lo_gd_fpa * cpu_wr_bw /
low_freq_bw,
dda_div,
MC_PTSA_RATE_DEFAULT_MASK);
/* Ring1 */
p->ring1_ptsa_rate = p->mpcorer_ptsa_rate + p->ftop_ptsa_rate;
p->ring1_ptsa_rate += p->dis_ptsa_rate + p->disb_ptsa_rate;
p->ring1_ptsa_rate += p->ve_ptsa_rate + p->ring2_ptsa_rate;
program_ptsa();
}
/*
* This now also includes ring1 since that needs to have its PTSA updated
* based on freq and usecase.
*/
static void t21x_calc_disp_and_camera_ptsa(void)
{
struct ptsa_info *p = &cs->ptsa_info;
unsigned int ve_bw_fp = cs->camera_bw_array[CAMERA_IDX(VI_W)] *
DDA_BW_MARGIN_FP;
unsigned int ve2_bw_fp = 0;
unsigned int isp_bw_fp = 0;
unsigned int total_dc0_bw_fp = total_dc0_bw * DDA_BW_MARGIN_FP;
unsigned int total_dc1_bw_fp = total_dc1_bw * DDA_BW_MARGIN_FP;
unsigned int low_freq_bw_fp = la_real_to_fp(low_freq_bw);
unsigned int dis_frac_fp = LA_FPA_TO_FP(lo_gd_fpa * total_dc0_bw_fp /
low_freq_bw_fp);
unsigned int disb_frac_fp = LA_FPA_TO_FP(lo_gd_fpa * total_dc1_bw_fp /
low_freq_bw_fp);
unsigned int total_iso_bw_fp = total_dc0_bw_fp + total_dc1_bw_fp;
int max_max = (1 << EMEM_PTSA_MINMAX_WIDTH) - 1;
int i = 0;
if (cs->agg_camera_array[AGG_CAMERA_ID(VE2)].is_hiso) {
ve2_bw_fp = (cs->camera_bw_array[CAMERA_IDX(ISP_RAB)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WAB)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WBB)]) *
DDA_BW_MARGIN_FP;
} else {
ve2_bw_fp = LA_REAL_TO_FP(
cs->camera_bw_array[CAMERA_IDX(ISP_RAB)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WAB)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WBB)]);
}
if (cs->agg_camera_array[AGG_CAMERA_ID(ISP)].is_hiso) {
isp_bw_fp = (cs->camera_bw_array[CAMERA_IDX(ISP_RA)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WA)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WB)]) *
DDA_BW_MARGIN_FP;
} else {
isp_bw_fp = LA_REAL_TO_FP(
cs->camera_bw_array[CAMERA_IDX(ISP_RA)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WA)] +
cs->camera_bw_array[CAMERA_IDX(ISP_WB)]);
}
cs->agg_camera_array[AGG_CAMERA_ID(VE)].bw_fp = ve_bw_fp;
cs->agg_camera_array[AGG_CAMERA_ID(VE2)].bw_fp = ve2_bw_fp;
cs->agg_camera_array[AGG_CAMERA_ID(ISP)].bw_fp = isp_bw_fp;
for (i = 0; i < TEGRA_LA_AGG_CAMERA_NUM_CLIENTS; i++) {
struct agg_camera_client_info *agg_client =
&cs->agg_camera_array[i];
if (agg_client->is_hiso) {
agg_client->frac_fp = LA_FPA_TO_FP(
lo_gd_fpa * agg_client->bw_fp /
low_freq_bw_fp);
agg_client->ptsa_min = (unsigned int)(-5) &
MC_PTSA_MIN_DEFAULT_MASK;
agg_client->ptsa_max = (unsigned int)(max_max) &
MC_PTSA_MAX_DEFAULT_MASK;
total_iso_bw_fp += agg_client->bw_fp;
} else {
agg_client->frac_fp = ONE_DDA_FRAC_FP;
agg_client->ptsa_min = (unsigned int)(-2) &
MC_PTSA_MIN_DEFAULT_MASK;
agg_client->ptsa_max = (unsigned int)(0) &
MC_PTSA_MAX_DEFAULT_MASK;
}
}
MC_SET_INIT_PTSA(p, dis, -5, max_max);
p->dis_ptsa_rate = fraction2dda_fp(
dis_frac_fp,
4,
MC_PTSA_RATE_DEFAULT_MASK) &
MC_PTSA_RATE_DEFAULT_MASK;
MC_SET_INIT_PTSA(p, disb, -5, max_max);
p->disb_ptsa_rate = fraction2dda_fp(
disb_frac_fp,
4,
MC_PTSA_RATE_DEFAULT_MASK) &
MC_PTSA_RATE_DEFAULT_MASK;
p->ve_ptsa_min = cs->agg_camera_array[AGG_CAMERA_ID(VE)].ptsa_min &
MC_PTSA_MIN_DEFAULT_MASK;
p->ve_ptsa_max = cs->agg_camera_array[AGG_CAMERA_ID(VE)].ptsa_max &
MC_PTSA_MAX_DEFAULT_MASK;
p->ve_ptsa_rate = fraction2dda_fp(
cs->agg_camera_array[AGG_CAMERA_ID(VE)].frac_fp,
4,
MC_PTSA_RATE_DEFAULT_MASK) &
MC_PTSA_RATE_DEFAULT_MASK;
p->ve2_ptsa_min = cs->agg_camera_array[AGG_CAMERA_ID(VE2)].ptsa_min &
MC_PTSA_MIN_DEFAULT_MASK;
p->ve2_ptsa_max = cs->agg_camera_array[AGG_CAMERA_ID(VE2)].ptsa_max &
MC_PTSA_MAX_DEFAULT_MASK;
if (is_t210b01_soc())
p->ve2_ptsa_rate = 1;
else
p->ve2_ptsa_rate = fraction2dda_fp(
cs->agg_camera_array[AGG_CAMERA_ID(VE2)].frac_fp,
4,
MC_PTSA_RATE_DEFAULT_MASK) &
MC_PTSA_RATE_DEFAULT_MASK;
p->isp_ptsa_min = cs->agg_camera_array[AGG_CAMERA_ID(ISP)].ptsa_min &
MC_PTSA_MIN_DEFAULT_MASK;
p->isp_ptsa_max = cs->agg_camera_array[AGG_CAMERA_ID(ISP)].ptsa_max &
MC_PTSA_MAX_DEFAULT_MASK;
if (is_t210b01_soc())
p->isp_ptsa_rate = 50;
else
p->isp_ptsa_rate = fraction2dda_fp(
cs->agg_camera_array[AGG_CAMERA_ID(ISP)].frac_fp,
4,
MC_PTSA_RATE_DEFAULT_MASK) &
MC_PTSA_RATE_DEFAULT_MASK;
MC_SET_INIT_PTSA(p, ring1, -5, max_max);
p->ring1_ptsa_rate = p->dis_ptsa_rate + p->disb_ptsa_rate +
p->ve_ptsa_rate;
p->ring1_ptsa_rate += cs->agg_camera_array[AGG_CAMERA_ID(VE2)].is_hiso ?
p->ve2_ptsa_rate : 0;
p->ring1_ptsa_rate += cs->agg_camera_array[AGG_CAMERA_ID(ISP)].is_hiso ?
p->isp_ptsa_rate : 0;
if (ON_LPDDR4())
p->ring1_ptsa_rate /= 2;
/* These need to be read from the registers since the MC/EMC clock may
be different than last time these were read into *p. */
p->ring1_ptsa_rate += mc_readl(MC_MLL_MPCORER_PTSA_RATE) +
mc_readl(MC_FTOP_PTSA_RATE);
if (p->ring1_ptsa_rate == 0)
p->ring1_ptsa_rate = 0x1;
}
static void t21x_update_display_ptsa_rate(unsigned int *disp_bw_array)
{
struct ptsa_info *p = &cs->ptsa_info;
t21x_calc_disp_and_camera_ptsa();
mc_writel(p->ring1_ptsa_min, MC_RING1_PTSA_MIN);
mc_writel(p->ring1_ptsa_max, MC_RING1_PTSA_MAX);
mc_writel(p->ring1_ptsa_rate, MC_RING1_PTSA_RATE);
mc_writel(p->dis_ptsa_min, MC_DIS_PTSA_MIN);
mc_writel(p->dis_ptsa_max, MC_DIS_PTSA_MAX);
mc_writel(p->dis_ptsa_rate, MC_DIS_PTSA_RATE);
mc_writel(p->disb_ptsa_min, MC_DISB_PTSA_MIN);
mc_writel(p->disb_ptsa_max, MC_DISB_PTSA_MAX);
mc_writel(p->disb_ptsa_rate, MC_DISB_PTSA_RATE);
}
static int t21x_update_camera_ptsa_rate(enum tegra_la_id id,
unsigned int bw_mbps,
int is_hiso)
{
struct ptsa_info *p = NULL;
int ret_code = 0;
mutex_lock(&disp_and_camera_ptsa_lock);
if (!is_camera_client(id)) {
/* Non-camera clients should be handled by t21x_set_la(...) or
t21x_set_disp_la(...). */
pr_err("%s: Ignoring request from a non-camera client.\n",
__func__);
pr_err("%s: Non-camera clients should be handled by "
"t21x_set_la(...) or t21x_set_disp_la(...).\n",
__func__);
ret_code = -1;
goto exit;
}
if ((id == ID(VI_W)) &&
(!is_hiso)) {
pr_err("%s: VI is stating that its not HISO.\n", __func__);
pr_err("%s: Ignoring and assuming that VI is HISO because VI "
"is always supposed to be HISO.\n",
__func__);
is_hiso = 1;
}
p = &cs->ptsa_info;
if (id == ID(VI_W)) {
cs->agg_camera_array[AGG_CAMERA_ID(VE)].is_hiso = is_hiso;
} else if ((id == ID(ISP_RAB)) ||
(id == ID(ISP_WAB)) ||
(id == ID(ISP_WBB))) {
cs->agg_camera_array[AGG_CAMERA_ID(VE2)].is_hiso = is_hiso;
} else {
cs->agg_camera_array[AGG_CAMERA_ID(ISP)].is_hiso = is_hiso;
}
cs->camera_bw_array[CAMERA_LA_IDX(id)] = bw_mbps;
t21x_calc_disp_and_camera_ptsa();
mc_writel(p->ring1_ptsa_min, MC_RING1_PTSA_MIN);
mc_writel(p->ring1_ptsa_max, MC_RING1_PTSA_MAX);
mc_writel(p->ring1_ptsa_rate, MC_RING1_PTSA_RATE);
mc_writel(p->ve_ptsa_min, MC_VE_PTSA_MIN);
mc_writel(p->ve_ptsa_max, MC_VE_PTSA_MAX);
mc_writel(p->ve_ptsa_rate, MC_VE_PTSA_RATE);
mc_writel(p->ve2_ptsa_min, MC_VE2_PTSA_MIN);
mc_writel(p->ve2_ptsa_max, MC_VE2_PTSA_MAX);
mc_writel(p->ve2_ptsa_rate, MC_VE2_PTSA_RATE);
mc_writel(p->isp_ptsa_min, MC_ISP_PTSA_MIN);
mc_writel(p->isp_ptsa_max, MC_ISP_PTSA_MAX);
mc_writel(p->isp_ptsa_rate, MC_ISP_PTSA_RATE);
exit:
mutex_unlock(&disp_and_camera_ptsa_lock);
return ret_code;
}
static int t21x_set_la(enum tegra_la_id id,
unsigned int bw_mbps)
{
int idx = cs->id_to_index[id];
struct la_client_info *ci = &cs->la_info_array[idx];
unsigned int la_to_set = 0;
if (is_display_client(id)) {
/* Display clients should be handled by
t21x_set_disp_la(...). */
return -1;
} else if (id == ID(MSENCSRD)) {
/* This is a special case. */
struct clk *emc_clk = clk_get_sys("tegra_emc", "emc");
unsigned int emc_freq_mhz;
unsigned int val_1 = 53;
unsigned int val_2 = 24;
if (IS_ERR(emc_clk))
return 0;
emc_freq_mhz = clk_get_rate(emc_clk) /
LA_HZ_TO_MHZ_FACTOR;
if (!emc_freq_mhz)
return 0;
if (210 > emc_freq_mhz)
val_1 = val_1 * 210 / emc_freq_mhz;
if (574 > emc_freq_mhz)
val_2 = val_2 * 574 / emc_freq_mhz;
la_to_set = min3((unsigned int)MC_LA_MAX_VALUE,
val_1,
val_2);
} else if (ci->la_ref_clk_mhz != 0) {
/* In this case we need to scale LA with emc frequency. */
struct clk *emc_clk = clk_get_sys("tegra_emc", "emc");
unsigned long emc_freq_mhz;
if (IS_ERR(emc_clk))
return 0;
emc_freq_mhz = clk_get_rate(emc_clk) /
(unsigned long)LA_HZ_TO_MHZ_FACTOR;
if (!emc_freq_mhz) {
pr_err("emc_freq_mhz is zero!!\n");
return 0;
}
if (ci->la_ref_clk_mhz <= emc_freq_mhz) {
la_to_set = min(ci->init_la,
(unsigned int)MC_LA_MAX_VALUE);
} else {
la_to_set = min((unsigned int)(ci->init_la *
ci->la_ref_clk_mhz / emc_freq_mhz),
(unsigned int)MC_LA_MAX_VALUE);
}
} else {
/* In this case we have a client with a static LA value. */
la_to_set = ci->init_la;
}
program_la(ci, la_to_set);
return 0;
}
static unsigned int t21x_min_la(struct dc_to_la_params *disp_params)
{
unsigned int min_la_fp = disp_params->drain_time_usec_fp *
1000 /
cs->ns_per_tick;
/* round up */
if (min_la_fp % LA_FP_FACTOR != 0)
min_la_fp += LA_FP_FACTOR;
return LA_FP_TO_REAL(min_la_fp);
}
static int t21x_handle_disp_la(enum tegra_la_id id,
unsigned long emc_freq_hz,
unsigned int bw_mbps,
struct dc_to_la_params disp_params,
int write_la)
{
int idx = 0;
struct la_client_info *ci = NULL;
long long la_to_set = 0;
unsigned int dvfs_time_nsec = 0;
unsigned int dvfs_buffering_reqd_bytes = 0;
unsigned int thresh_dvfs_bytes = 0;
unsigned int total_buf_sz_bytes = 0;
int effective_mccif_buf_sz = 0;
long long la_bw_upper_bound_nsec_fp = 0;
long long la_bw_upper_bound_nsec = 0;
long long la_nsec = 0;
if (!is_display_client(id)) {
/* Non-display clients should be handled by t21x_set_la(...). */
return -1;
}
mutex_lock(&disp_and_camera_ptsa_lock);
total_dc0_bw = disp_params.total_dc0_bw;
total_dc1_bw = disp_params.total_dc1_bw;
cs->update_display_ptsa_rate(cs->disp_bw_array);
mutex_unlock(&disp_and_camera_ptsa_lock);
idx = cs->id_to_index[id];
ci = &cs->la_info_array[idx];
la_to_set = 0;
dvfs_time_nsec =
tegra_get_dvfs_clk_change_latency_nsec(emc_freq_hz / 1000);
dvfs_buffering_reqd_bytes = bw_mbps *
dvfs_time_nsec /
LA_USEC_TO_NSEC_FACTOR;
thresh_dvfs_bytes =
disp_params.thresh_lwm_bytes +
dvfs_buffering_reqd_bytes +
disp_params.spool_up_buffering_adj_bytes;
total_buf_sz_bytes =
cs->disp_clients[DISP_CLIENT_LA_ID(id)].line_buf_sz_bytes +
cs->disp_clients[DISP_CLIENT_LA_ID(id)].mccif_size_bytes;
effective_mccif_buf_sz =
(cs->disp_clients[DISP_CLIENT_LA_ID(id)].line_buf_sz_bytes >
thresh_dvfs_bytes) ?
cs->disp_clients[DISP_CLIENT_LA_ID(id)].mccif_size_bytes :
total_buf_sz_bytes - thresh_dvfs_bytes;
if (effective_mccif_buf_sz < 0)
return -1;
la_bw_upper_bound_nsec_fp = (long long)effective_mccif_buf_sz *
LA_FP_FACTOR /
bw_mbps;
la_bw_upper_bound_nsec_fp = la_bw_upper_bound_nsec_fp *
LA_FP_FACTOR /
LA_DISP_CATCHUP_FACTOR_FP;
la_bw_upper_bound_nsec_fp =
la_bw_upper_bound_nsec_fp -
(LA_ST_LA_MINUS_SNAP_ARB_TO_ROW_SRT_EMCCLKS_FP +
EXP_TIME_EMCCLKS_FP) /
(emc_freq_hz / LA_HZ_TO_MHZ_FACTOR);
la_bw_upper_bound_nsec_fp *= LA_USEC_TO_NSEC_FACTOR;
la_bw_upper_bound_nsec = LA_FP_TO_REAL(la_bw_upper_bound_nsec_fp);
la_nsec = min(la_bw_upper_bound_nsec,
(long long)MAX_LA_NSEC);
la_to_set = min((long long)(la_nsec/cs->ns_per_tick),
(long long)MC_LA_MAX_VALUE);
if ((la_to_set < t21x_min_la(&disp_params))
|| (la_to_set > MC_LA_MAX_VALUE))
return -1;
if (write_la)
program_la(ci, la_to_set);
return 0;
}
static int t21x_set_disp_la(enum tegra_la_id id,
unsigned long emc_freq_hz,
unsigned int bw_mbps,
struct dc_to_la_params disp_params)
{
return t21x_handle_disp_la(id, emc_freq_hz, bw_mbps, disp_params, 1);
}
static int t21x_check_disp_la(enum tegra_la_id id,
unsigned long emc_freq_hz,
unsigned int bw_mbps,
struct dc_to_la_params disp_params)
{
return t21x_handle_disp_la(id, emc_freq_hz, bw_mbps, disp_params, 0);
}
void program_scaled_la_t21x(struct la_client_info *ci, int la)
{
unsigned long reg_write;
if (ci->id == ID(DISPLAY_0A)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0A,
(u32)reg_write);
} else if (ci->id == ID(DISPLAY_0AB)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0AB,
(u32)reg_write);
} else if (ci->id == ID(DISPLAY_0B)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0B,
(u32)reg_write);
} else if (ci->id == ID(DISPLAY_0BB)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0BB,
(u32)reg_write);
} else if (ci->id == ID(DISPLAY_0C)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0C,
(u32)reg_write);
} else if (ci->id == ID(DISPLAY_0CB)) {
reg_write =
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB_LOW_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB_LOW_MASK) |
((la << MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB_HIGH_SHIFT) &
MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB_HIGH_MASK);
mc_writel(reg_write, MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB);
la_debug("reg_addr=0x%x, write=0x%x",
(u32)(uintptr_t)MC_SCALED_LATENCY_ALLOWANCE_DISPLAY0CB,
(u32)reg_write);
}
}
void tegra_la_get_t21x_specific(struct la_chip_specific *cs_la)
{
int i = 0;
if (is_t210b01_soc()) {
/* Fixup t21x_la_info_array for t210b01 */
for (i = 0; i < ARRAY_SIZE(t21x_la_info_array); i++) {
if (t21x_la_info_array[i].id == ID(ISP_RA))
t21x_la_info_array[i].la_ref_clk_mhz = 600;
else if (t21x_la_info_array[i].id == ID(ISP_RAB))
t21x_la_info_array[i].la_ref_clk_mhz = 248;
}
}
cs_la->ns_per_tick = 30;
cs_la->atom_size = 64;
cs_la->la_max_value = MC_LA_MAX_VALUE;
cs_la->la_info_array = t21x_la_info_array;
cs_la->la_info_array_size = ARRAY_SIZE(t21x_la_info_array);
cs_la->la_params.fp_factor = LA_FP_FACTOR;
cs_la->la_params.la_real_to_fp = la_real_to_fp;
cs_la->la_params.la_fp_to_real = la_fp_to_real;
cs_la->la_params.static_la_minus_snap_arb_to_row_srt_emcclks_fp =
LA_ST_LA_MINUS_SNAP_ARB_TO_ROW_SRT_EMCCLKS_FP;
cs_la->la_params.dram_width_bits = LA_DRAM_WIDTH_BITS;
cs_la->la_params.disp_catchup_factor_fp = LA_DISP_CATCHUP_FACTOR_FP;
cs_la->init_ptsa = t21x_init_ptsa;
cs_la->update_display_ptsa_rate = t21x_update_display_ptsa_rate;
cs_la->update_camera_ptsa_rate = t21x_update_camera_ptsa_rate;
cs_la->set_init_la = t21x_set_la;
cs_la->set_dynamic_la = t21x_set_la;
cs_la->set_disp_la = t21x_set_disp_la;
cs_la->check_disp_la = t21x_check_disp_la;
cs_la->save_ptsa = save_ptsa;
cs_la->program_ptsa = program_ptsa;
cs_la->suspend = la_suspend;
cs_la->resume = la_resume;
cs = cs_la;
if (ON_LPDDR4()) {
emc_min_freq_mhz_fp = 25000;
emc_min_freq_mhz = 25;
emc_max_freq_mhz = 2132;
hi_gd_fp = 1500;
lo_gd_fp = 18;
hi_gd_fpa = 14998;
lo_gd_fpa = 176;
dda_div = 1;
} else {
emc_min_freq_mhz_fp = 12500;
emc_min_freq_mhz = 12;
emc_max_freq_mhz = 1200;
hi_gd_fp = 2000;
lo_gd_fp = 21;
hi_gd_fpa = 19998;
lo_gd_fpa = 208;
dda_div = 2;
}
low_freq_bw = emc_min_freq_mhz_fp * 2 * LA_DRAM_WIDTH_BITS / 8;
low_freq_bw /= 1000;
tegra_la_disp_clients_info = cs_la->disp_clients;
/* set some entries to zero */
for (i = 0; i < NUM_CAMERA_CLIENTS; i++)
cs_la->camera_bw_array[i] = 0;
for (i = 0; i < TEGRA_LA_AGG_CAMERA_NUM_CLIENTS; i++) {
cs_la->agg_camera_array[i].bw_fp = 0;
cs_la->agg_camera_array[i].frac_fp = 0;
cs_la->agg_camera_array[i].ptsa_min = 0;
cs_la->agg_camera_array[i].ptsa_max = 0;
cs_la->agg_camera_array[i].is_hiso = false;
}
/* set mccif_size_bytes values */
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0A)].mccif_size_bytes = 6144;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0B)].mccif_size_bytes = 6144;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0C)].mccif_size_bytes =
11520;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAYD)].mccif_size_bytes = 4672;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_T)].mccif_size_bytes = 4672;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HC)].mccif_size_bytes = 4992;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0AB)].mccif_size_bytes =
11520;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0BB)].mccif_size_bytes =
6144;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0CB)].mccif_size_bytes =
6144;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HCB)].mccif_size_bytes =
4992;
/* set line_buf_sz_bytes values */
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0A)].line_buf_sz_bytes =
151552;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0B)].line_buf_sz_bytes =
112640;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0C)].line_buf_sz_bytes =
112640;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAYD)].line_buf_sz_bytes = 18432;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_T)].line_buf_sz_bytes =
18432;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HC)].line_buf_sz_bytes = 320;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0AB)].line_buf_sz_bytes =
112640;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0BB)].line_buf_sz_bytes =
112640;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0CB)].line_buf_sz_bytes =
112640;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HCB)].line_buf_sz_bytes =
320;
/* set win_type values */
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0A)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULL;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0B)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULLA;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0C)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULLA;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAYD)].win_type =
TEGRA_LA_DISP_WIN_TYPE_SIMPLE;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HC)].win_type =
TEGRA_LA_DISP_WIN_TYPE_CURSOR;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_T)].win_type =
TEGRA_LA_DISP_WIN_TYPE_SIMPLE;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0AB)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULLB;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0BB)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULLB;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_0CB)].win_type =
TEGRA_LA_DISP_WIN_TYPE_FULLB;
cs_la->disp_clients[DISP_CLIENT_ID(DISPLAY_HCB)].win_type =
TEGRA_LA_DISP_WIN_TYPE_CURSOR;
}