drm/amd/display: Add DCCG DIO, HPO, OPP, and OPTC support for FRL

This adds support to HW block programming for the core blocks
for HDMI FRL:
- DIO
- HPO
- OPP
- OPTC

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Harry Wentland
2026-06-03 13:44:31 -04:00
committed by Alex Deucher
parent 8812fae129
commit d36771a034
38 changed files with 4948 additions and 4 deletions
@@ -42,8 +42,48 @@
#define DC_LOGGER \
dccg->ctx->logger
void dccg3_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
HDMICHARCLK0_EN, 1,
HDMICHARCLK0_SRC_SEL, phypll_inst);
/* Enable FORCE_EN for SYMCLK */
switch (phypll_inst) {
case 0:
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_FORCE_EN, 1,
PHYASYMCLK_FORCE_SRC_SEL, 1);
break;
case 1:
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_FORCE_EN, 1,
PHYBSYMCLK_FORCE_SRC_SEL, 1);
break;
case 2:
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_FORCE_EN, 1,
PHYCSYMCLK_FORCE_SRC_SEL, 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
void dccg3_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
}
static const struct dccg_funcs dccg3_funcs = {
.enable_hdmicharclk = dccg3_enable_hdmicharclk,
.disable_hdmicharclk = dccg3_disable_hdmicharclk,
.update_dpp_dto = dccg2_update_dpp_dto,
.get_dccg_ref_freq = dccg2_get_dccg_ref_freq,
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
@@ -63,4 +63,12 @@ struct dccg *dccg30_create(
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask);
void dccg3_enable_hdmicharclk(
struct dccg *dccg,
int hpo_inst,
int phypll_inst);
void dccg3_disable_hdmicharclk(
struct dccg *dccg,
int hpo_inst);
#endif //__DCN30_DCCG_H__
@@ -664,6 +664,87 @@ void dccg31_set_dispclk_change_mode(
change_mode == DISPCLK_CHANGE_MODE_RAMPING ? 2 : 0);
}
void dccg31_set_hdmistreamclk(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
(void)otg_inst;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (src == REFCLK) {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_SRC_SEL, 0, /* SEL_REFCLK0 */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
} else {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_SRC_SEL, 1, /* SEL_DTBCLK0 */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
}
}
static void dccg31_disable_hdmistreamclk(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream)
REG_UPDATE_2(HDMISTREAMCLK0_DTO_PARAM,
HDMISTREAMCLK0_DTO_PHASE, 0,
HDMISTREAMCLK0_DTO_MODULO, 1);
}
void dccg31_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 1);
}
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
HDMICHARCLK0_EN, 1,
HDMICHARCLK0_SRC_SEL, phypll_inst);
/* Enable FORCE_EN for SYMCLK */
switch (phypll_inst) {
case 0:
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_FORCE_EN, 1,
PHYASYMCLK_FORCE_SRC_SEL, 1);
break;
case 1:
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_FORCE_EN, 1,
PHYBSYMCLK_FORCE_SRC_SEL, 1);
break;
case 2:
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_FORCE_EN, 1,
PHYCSYMCLK_FORCE_SRC_SEL, 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
void dccg31_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
}
}
void dccg31_init(struct dccg *dccg)
{
/* Set HPO stream encoder to use refclk to avoid case where PHY is
@@ -692,6 +773,10 @@ void dccg31_init(struct dccg *dccg)
dccg31_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
dccg31_set_physymclk(dccg, 4, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
}
dccg31_disable_hdmistreamclk(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
dccg31_disable_hdmicharclk(dccg, 0);
}
void dccg31_otg_add_pixel(struct dccg *dccg,
@@ -835,6 +920,9 @@ void dccg31_read_reg_state(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_re
}
static const struct dccg_funcs dccg31_funcs = {
.enable_hdmicharclk = dccg31_enable_hdmicharclk,
.disable_hdmicharclk = dccg31_disable_hdmicharclk,
.set_hdmistreamclk = dccg31_set_hdmistreamclk,
.update_dpp_dto = dccg31_update_dpp_dto,
.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
.dccg_init = dccg31_init,
@@ -202,6 +202,19 @@ void dccg31_set_physymclk(
void dccg31_set_audio_dtbclk_dto(
struct dccg *dccg,
const struct dtbclk_dto_params *params);
void dccg31_enable_hdmicharclk(
struct dccg *dccg,
int hpo_inst,
int phypll_inst);
void dccg31_disable_hdmicharclk(
struct dccg *dccg,
int hpo_inst);
void dccg31_set_hdmistreamclk(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst);
void dccg31_update_dpp_dto(
struct dccg *dccg,
@@ -286,6 +286,28 @@ void dccg314_set_dpstreamclk(
}
}
static void dccg314_set_hdmistreamclk(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
/* set the dtbclk_p source */
dccg314_set_dtbclk_p_src(dccg, src, otg_inst);
if (src == REFCLK) {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0, /* SEL_REFCLK */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
} else {
REG_UPDATE_3(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 1, /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
HDMISTREAMCLK0_SRC_SEL, otg_inst, /* Selects dtbclk_p as source for hdmistreamclk */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
}
}
static void dccg314_init(struct dccg *dccg)
{
int otg_inst;
@@ -355,6 +377,9 @@ static void dccg314_dpp_root_clock_control(
}
static const struct dccg_funcs dccg314_funcs = {
.enable_hdmicharclk = dccg31_enable_hdmicharclk,
.disable_hdmicharclk = dccg31_disable_hdmicharclk,
.set_hdmistreamclk = dccg314_set_hdmistreamclk,
.update_dpp_dto = dccg31_update_dpp_dto,
.dpp_root_clock_control = dccg314_dpp_root_clock_control,
.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
@@ -329,7 +329,75 @@ static void dccg32_otg_drop_pixel(struct dccg *dccg,
OTG_DROP_PIXEL[otg_inst], 1);
}
static void dccg32_set_hdmistreamclk(struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
/* set the dtbclk_p source */
/* always program refclk as DTBCLK. No use-case expected to require DPREFCLK as refclk */
dccg32_set_dtbclk_p_src(dccg, DTBCLK0, otg_inst);
if (src == REFCLK) {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0, /* SEL_REFCLK */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
} else {
REG_UPDATE_3(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 1, /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
HDMISTREAMCLK0_SRC_SEL, otg_inst, /* Selects dtbclk_p as source for hdmistreamclk */
HDMISTREAMCLK0_DTO_FORCE_DIS, 1); /* DTO_FORCE_BYPASS */
}
}
static void dccg32_enable_hdmicharclk(struct dccg *dccg, int hpo_inst,
int phypll_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
HDMICHARCLK0_EN, 1,
HDMICHARCLK0_SRC_SEL, phypll_inst);
/* Enable FORCE_EN for SYMCLK */
switch (phypll_inst) {
case 0:
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_FORCE_EN, 1,
PHYASYMCLK_FORCE_SRC_SEL, 1);
break;
case 1:
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_FORCE_EN, 1,
PHYBSYMCLK_FORCE_SRC_SEL, 1);
break;
case 2:
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_FORCE_EN, 1,
PHYCSYMCLK_FORCE_SRC_SEL, 1);
break;
case 3:
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_FORCE_EN, 1,
PHYDSYMCLK_FORCE_SRC_SEL, 1);
break;
case 4:
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_FORCE_EN, 1,
PHYESYMCLK_FORCE_SRC_SEL, 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static const struct dccg_funcs dccg32_funcs = {
.enable_hdmicharclk = dccg32_enable_hdmicharclk,
.disable_hdmicharclk = dccg3_disable_hdmicharclk,
.set_hdmistreamclk = dccg32_set_hdmistreamclk,
.update_dpp_dto = dccg2_update_dpp_dto,
.get_dccg_ref_freq = dccg32_get_dccg_ref_freq,
.dccg_init = dccg31_init,
@@ -495,6 +495,92 @@ static void dccg35_set_smclk32_se_rcg(
}
}
static void dccg35_set_hdmistreamclk_rcg(
struct dccg *dccg,
int inst,
bool enable)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (!dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream && enable)
return;
switch (inst) {
case 0:
REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, enable ? 0 : 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg35_set_hdmi_char_clk_rcg(
struct dccg *dccg,
int inst,
bool enable)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
/* Only 1 HPO in DCN35 */
if (!dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar && enable)
return;
switch (inst) {
case 0:
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, enable ? 0 : 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg35_set_hdmi_char_clk_src_new(
struct dccg *dccg,
enum hdmi_char_clk src,
int inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
/* If DTBCLK_P#_EN is 0 refclock is selected as functional clock
* If DTBCLK_P#_EN is 1 functional clock is selected as DTBCLK_P#_SRC_SEL
*/
switch (inst) {
case 0:
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[0],
HDMICHARCLK0_SRC_SEL, (src == HDMI_CHAR_REFCLK) ? 0 : src,
HDMICHARCLK0_EN, (src == HDMI_CHAR_REFCLK) ? 0 : 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg35_set_hdmistreamclk_src_new(
struct dccg *dccg,
enum hdmi_stream_clk_source src,
int inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (inst) {
case 0:
REG_UPDATE_2(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN,
(src == HDMI_STREAM_REFCLK) ? 0 : 1,
DPSTREAMCLK0_SRC_SEL,
(src == HDMI_STREAM_REFCLK) ? 0 : src);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg35_set_dsc_clk_src_new(struct dccg *dccg, int inst, enum dsc_clk_source src)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
@@ -1107,6 +1193,35 @@ static void dccg35_enable_dpstreamclk_new(struct dccg *dccg,
dccg35_set_dpstreamclk_src_new(dccg, src, inst);
}
static void dccg35_disable_hdmistreamclk_new(
struct dccg *dccg,
int inst)
{
dccg35_set_hdmistreamclk_src_new(dccg, HDMI_STREAM_REFCLK, inst);
dccg35_set_hdmistreamclk_rcg(dccg, inst, true);
}
static void dccg35_enable_hdmistreamclk_new(struct dccg *dccg,
enum hdmi_stream_clk_source src,
int inst)
{
dccg35_set_hdmistreamclk_rcg(dccg, inst, false);
dccg35_set_hdmistreamclk_src_new(dccg, src, inst);
}
static void dccg35_enable_hdmicharclk_new(struct dccg *dccg, enum hdmi_char_clk src,
int inst)
{
dccg35_set_hdmi_char_clk_rcg(dccg, inst, false);
dccg35_set_hdmi_char_clk_src_new(dccg, src, inst);
}
static void dccg35_disable_hdmicharclk_new(struct dccg *dccg, int inst)
{
dccg35_set_hdmi_char_clk_src_new(dccg, HDMI_CHAR_REFCLK, inst);
dccg35_set_hdmi_char_clk_rcg(dccg, inst, true);
}
void dccg35_trigger_dio_fifo_resync(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
@@ -1539,6 +1654,88 @@ void dccg35_set_dpstreamclk_root_clock_gating(struct dccg *dccg, int dp_hpo_inst
static void dccg35_set_hdmistreamclk(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
/* set the dtbclk_p source */
dccg35_set_dtbclk_p_src(dccg, src, otg_inst);
if (src == REFCLK) {
REG_UPDATE(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0); /* SEL_REFCLK */
} else {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 1, /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
HDMISTREAMCLK0_SRC_SEL, otg_inst); /* Selects dtbclk_p as source for hdmistreamclk */
}
DC_LOG_DEBUG("%s: OTG%d HDMISTREAMCLK_EN = %d, HDMISTREAMCLK_SRC_SEL = %d\n",
__func__, otg_inst, (src == REFCLK) ? 0 : 1, otg_inst);
}
void dccg35_set_hdmistreamclk_root_clock_gating(struct dccg *dccg, bool enable)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream)
REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, enable ? 1 : 0);
DC_LOG_DEBUG("%s: HDMISTREAMCLK0_ROOT_GATE_DISABLE = %d\n", __func__, enable ? 1 : 0);
}
static void dccg35_enable_hdmicharclk(struct dccg *dccg, int hpo_inst,
int phypll_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 1);
}
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
HDMICHARCLK0_EN, 1,
HDMICHARCLK0_SRC_SEL, phypll_inst);
/* Enable FORCE_EN for SYMCLK */
switch (phypll_inst) {
case 0:
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_EN, 1,
PHYASYMCLK_SRC_SEL, 1);
break;
case 1:
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_EN, 1,
PHYBSYMCLK_SRC_SEL, 1);
break;
case 2:
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_EN, 1,
PHYCSYMCLK_SRC_SEL, 1);
break;
case 3:
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_EN, 1,
PHYDSYMCLK_SRC_SEL, 1);
break;
case 4:
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_EN, 1,
PHYESYMCLK_SRC_SEL, 1);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg35_set_physymclk_root_clock_gating(
struct dccg *dccg,
int phy_inst,
@@ -1756,6 +1953,33 @@ void dccg35_disable_symclk32_se(struct dccg *dccg, int hpo_se_inst)
}
static void dccg35_disable_hdmistreamclk(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream) {
// REG_UPDATE_2(HDMISTREAMCLK0_DTO_PARAM,
// HDMISTREAMCLK0_DTO_PHASE, 0,
// HDMISTREAMCLK0_DTO_MODULO, 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, 0);
}
}
static void dccg35_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
DC_LOG_DEBUG("%s: HDMICHARCLK0_ROOT_GATE_DISABLE = 0\n", __func__);
}
}
static void dccg35_init_cb(struct dccg *dccg)
{
(void)dccg;
@@ -1793,6 +2017,9 @@ void dccg35_init(struct dccg *dccg)
__func__, otg_inst);
}
dccg35_disable_hdmistreamclk(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
dccg35_disable_hdmicharclk(dccg, 0);
/*
dccg35_enable_global_fgcg_rep(
dccg, dccg->ctx->dc->debug.enable_fine_grain_clock_gating.bits
@@ -2088,6 +2315,92 @@ void dccg35_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint3
}
}
static void dccg35_enable_hdmicharclk_cb(struct dccg *dccg, int hpo_inst, int phypll_inst)
{
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
/* Note that this is now done in DMU as part of phy fsm enable sequence,
* this function does not get called on x86
*/
enum hdmi_char_clk src = (enum hdmi_char_clk) phypll_inst;
dccg35_enable_hdmicharclk_new(dccg, src, hpo_inst);
/* Select PHYD18 as final SYMCLK going to the PHY from DCCG */
dccg35_set_physymclk_src_new(dccg, phypll_inst, PHYSYMCLK_PHYD18CLK);
}
static void dccg35_disable_hdmicharclk_cb(struct dccg *dccg, int hpo_inst)
{
ASSERT(hpo_inst >= 0);
/* Note that this is now done in DMU as part of phy fsm disable sequence,
* this function does not get called on x86
*/
dccg35_disable_hdmicharclk_new(dccg, hpo_inst);
/* TBD Optionally check if SYMCLK is active and disable it */
}
static void dccg35_set_hdmistreamclk_cb(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
enum dtbclk_source dtb_clk_src;
enum hdmi_stream_clk_source hdmi_stream_clk_src;
switch (src) {
case REFCLK:
dtb_clk_src = DTBCLK_REFCLK;
hdmi_stream_clk_src = HDMI_STREAM_REFCLK;
break;
case DPREFCLK:
dtb_clk_src = DTBCLK_DPREFCLK;
hdmi_stream_clk_src = (enum hdmi_stream_clk_source)otg_inst;
break;
case DTBCLK0:
dtb_clk_src = DTBCLK_DTBCLK0;
hdmi_stream_clk_src = (enum hdmi_stream_clk_source)otg_inst;
break;
default:
BREAK_TO_DEBUGGER();
return;
}
if (dtb_clk_src == DTBCLK_REFCLK &&
hdmi_stream_clk_src == HDMI_STREAM_REFCLK) {
dccg35_disable_dtbclk_p_new(dccg, otg_inst);
dccg35_disable_hdmistreamclk_new(dccg, 0);
} else {
dccg35_enable_dtbclk_p_new(dccg, dtb_clk_src, otg_inst);
dccg35_enable_hdmistreamclk_new(dccg,
hdmi_stream_clk_src,
0);
}
}
static void dccg35_set_hdmistreamclk_root_clock_gating_cb(
struct dccg *dccg,
bool power_on)
{
/* power_on set indicates we need to ungate
* Currently called from optimize_bandwidth and prepare_bandwidth calls
* Since clock source is not passed restore to refclock on ungate
* Instance 0 is implied here since only one streamclock resource
* Redundant as gating when enabled is acheived through set_hdmistreamclk
*/
if (power_on) {
dccg35_enable_hdmicharclk_new(dccg, HDMI_CHAR_REFCLK, 0);
dccg35_enable_hdmistreamclk_new(dccg,
HDMI_STREAM_REFCLK,
0);
} else {
dccg35_disable_hdmistreamclk_new(dccg, 0);
dccg35_disable_hdmicharclk_new(dccg, 0);
}
}
static void dccg35_set_dpstreamclk_cb(
struct dccg *dccg,
enum streamclk_source src,
@@ -2386,6 +2699,10 @@ void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint
}
static const struct dccg_funcs dccg35_funcs_new = {
.enable_hdmicharclk = dccg35_enable_hdmicharclk_cb,
.disable_hdmicharclk = dccg35_disable_hdmicharclk_cb,
.set_hdmistreamclk = dccg35_set_hdmistreamclk_cb,
.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating_cb,
.update_dpp_dto = dccg35_update_dpp_dto_cb,
.dpp_root_clock_control = dccg35_dpp_root_clock_control_cb,
.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
@@ -2421,6 +2738,10 @@ static const struct dccg_funcs dccg35_funcs_new = {
};
static const struct dccg_funcs dccg35_funcs = {
.enable_hdmicharclk = dccg35_enable_hdmicharclk,
.disable_hdmicharclk = dccg35_disable_hdmicharclk,
.set_hdmistreamclk = dccg35_set_hdmistreamclk,
.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
.update_dpp_dto = dccg35_update_dpp_dto,
.dpp_root_clock_control = dccg35_dpp_root_clock_control,
.get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
@@ -381,6 +381,72 @@ static void dccg401_otg_drop_pixel(struct dccg *dccg,
OTG_DROP_PIXEL[otg_inst], 1);
}
void dccg401_set_hdmistreamclk(
struct dccg *dccg,
enum streamclk_source src,
uint32_t otg_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (src == REFCLK) {
REG_UPDATE(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0); /* SEL_REFCLK */
} else {
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 1, /* selects one of the dtbclk_p as per HDMISTREAMCLK0_SRC_SEL */
HDMISTREAMCLK0_SRC_SEL, otg_inst); /* Selects dtbclk_p as source for hdmistreamclk */
}
}
void dccg401_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0 && phypll_inst >= 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 1);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 1);
}
REG_UPDATE_2(HDMICHARCLK_CLOCK_CNTL[hpo_inst],
HDMICHARCLK0_EN, 1,
HDMICHARCLK0_SRC_SEL, phypll_inst);
/* Enable FORCE_EN for SYMCLK */
dccg401_set_physymclk(dccg, phypll_inst, PHYSYMCLK_FORCE_SRC_PHYD18CLK, true);
}
void dccg401_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
//int phypll_inst = 0;
ASSERT(hpo_inst >= 0);
//REG_GET(dccg, HDMICHARCLK_CLOCK_CNTL[hpo_inst], HDMICHARCLK0_SRC_SEL, &phypll_inst);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
/* TODO should we also disable physymclk? */
/* Disable FORCE_EN for SYMCLK */
//dccg401_set_physymclk(dccg, phypll_inst, PHYSYMCLK_FORCE_SRC_PHYD18CLK, true);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) {
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, 0);
}
}
static void dccg401_disable_hdmistreamclk(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0,
HDMISTREAMCLK0_SRC_SEL, 0);
}
void dccg401_enable_symclk32_le(
struct dccg *dccg,
int hpo_le_inst,
@@ -721,6 +787,10 @@ void dccg401_init(struct dccg *dccg)
dccg401_set_physymclk(dccg, 2, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
dccg401_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
}
dccg401_disable_hdmistreamclk(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
dccg401_disable_hdmicharclk(dccg, 0);
}
void dccg401_set_dto_dscclk(struct dccg *dccg, uint32_t inst, uint32_t num_slices_h)
@@ -881,6 +951,9 @@ void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint
}
static const struct dccg_funcs dccg401_funcs = {
.enable_hdmicharclk = dccg401_enable_hdmicharclk,
.disable_hdmicharclk = dccg401_disable_hdmicharclk,
.set_hdmistreamclk = dccg401_set_hdmistreamclk,
.update_dpp_dto = dccg401_update_dpp_dto,
.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
.dccg_init = dccg401_init,
@@ -246,4 +246,8 @@ void dccg401_set_physymclk(
enum physymclk_clock_source clk_src,
bool force_enable);
void dccg401_set_hdmistreamclk(struct dccg *dccg, enum streamclk_source src, uint32_t otg_inst);
void dccg401_enable_hdmicharclk(struct dccg *dccg, int hpo_inst, int phypll_inst);
void dccg401_disable_hdmicharclk(struct dccg *dccg, int hpo_inst);
#endif //__DCN401_DCCG_H__
@@ -181,6 +181,32 @@ void dccg42_set_physymclk(
}
}
static void dccg42_disable_hdmistreamclk(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
REG_UPDATE_2(HDMISTREAMCLK_CNTL,
HDMISTREAMCLK0_EN, 0,
HDMISTREAMCLK0_SRC_SEL, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL6,
HDMISTREAMCLK0_ROOT_GATE_DISABLE,
dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream ? 0 : 1);
}
static void dccg42_disable_hdmicharclk(struct dccg *dccg, int hpo_inst)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
ASSERT(hpo_inst >= 0);
REG_WRITE(HDMICHARCLK_CLOCK_CNTL[hpo_inst], 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
HDMICHARCLK0_GATE_DISABLE, 0);
REG_UPDATE(DCCG_GATE_DISABLE_CNTL4,
HDMICHARCLK0_ROOT_GATE_DISABLE, dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar ? 0 : 1);
}
void dccg42_set_pixel_rate_div(
struct dccg *dccg,
uint32_t otg_inst,
@@ -270,10 +296,17 @@ static void dccg42_init(struct dccg *dccg)
PHYDSYMCLK_ROOT_GATE_DISABLE, 1,
PHYESYMCLK_ROOT_GATE_DISABLE, 1);
}
dccg42_disable_hdmistreamclk(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar)
dccg42_disable_hdmicharclk(dccg, 0);
}
static const struct dccg_funcs dccg42_funcs = {
.enable_hdmicharclk = dccg401_enable_hdmicharclk,
.disable_hdmicharclk = dccg42_disable_hdmicharclk,
.set_hdmistreamclk = dccg401_set_hdmistreamclk,
.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
.update_dpp_dto = dccg35_update_dpp_dto,
.dpp_root_clock_control = dccg35_dpp_root_clock_control,
.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
@@ -1066,7 +1066,8 @@ void dcn10_link_encoder_disable_output(
struct bp_transmitter_control cntl = { 0 };
enum bp_result result;
if (enc->funcs->is_dig_enabled && !enc->funcs->is_dig_enabled(enc)) {
if (!dc_is_hdmi_frl_signal(signal) &&
(enc->funcs->is_dig_enabled && !enc->funcs->is_dig_enabled(enc))) {
/* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */
/*in DP_Alt_No_Connect case, we turn off the dig already,
after excuation the PHY w/a sequence, not allow touch PHY any more*/
@@ -291,6 +291,7 @@ struct dpcssys_phy_seq_cfg {
bool use_calibration_setting;
struct mpll_cfg mpll_cfg;
bool load_sram_fw;
bool tx_hdmi_frl_mode;
#if 0
bool hdmimode_enable;
@@ -48,11 +48,240 @@
(enc10->link_regs->index)
static bool dcn30_link_encoder_validate_hdmi_frl_output(
const struct dcn10_link_encoder *enc10,
const struct dc_crtc_timing *crtc_timing)
{
enum dc_color_depth max_deep_color =
enc10->base.features.max_hdmi_deep_color;
if (!enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE)
return false;
if (max_deep_color < crtc_timing->display_color_depth)
return false;
if (crtc_timing->display_color_depth < COLOR_DEPTH_888)
return false;
/* TODO: check if hdmi_charclk is above ASIC cap (10 GBS for DCN3AG) */
return true;
}
bool dcn30_link_encoder_validate_output_with_stream(
struct link_encoder *enc,
const struct dc_stream_state *stream)
{
if (dc_is_hdmi_frl_signal(stream->signal)) {
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
return dcn30_link_encoder_validate_hdmi_frl_output(enc10, &stream->timing);
} else {
return dcn10_link_encoder_validate_output_with_stream(enc, stream);
}
}
//---------------------------------------------------
// Task: Program EQ setting
// Note:
// EQ setting can be dont during P2 state or P0 state
// If set in P0 state, The values are latched in a single
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
// to be reflected on the output. During this period the
// analog serial lines might have a transitional behavior.
//---------------------------------------------------
void dpcs30_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings)
{
(void)link_settings;
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* EQ setting for DP lane0 */
uint32_t eq_main;
uint32_t eq_pre;
uint32_t eq_post;
if (enc10->base.ctx->dc->debug.ignore_ffe)
return;
if (FFE_Level < 0x5)
enc10->base.txffe_state = FFE_Level;
if (FFE_Level == 0xEE) {
enc10->base.txffe_state++;
if (enc10->base.txffe_state > 3)
enc10->base.txffe_state = 0;
}
switch (enc10->base.txffe_state) {
case 0:
eq_main = 0x31;
if (de_emphasis_only)
eq_main = 0x36;
if (pre_shoot_only)
eq_main = 0x39;
eq_pre = 0x5;
eq_post = 0x8;
break;
case 1:
eq_main = 0x2F;
if (de_emphasis_only)
eq_main = 0x34;
if (pre_shoot_only)
eq_main = 0x39;
eq_pre = 0x5;
eq_post = 0xA;
break;
case 2:
eq_main = 0x2C;
if (de_emphasis_only)
eq_main = 0x31;
if (pre_shoot_only)
eq_main = 0x39;
eq_pre = 0x5;
eq_post = 0xD;
break;
case 3:
eq_main = 0x29;
if (de_emphasis_only)
eq_main = 0x2E;
if (pre_shoot_only)
eq_main = 0x39;
eq_pre = 0x5;
eq_post = 0x10;
break;
default:
return;
}
eq_pre = de_emphasis_only ? 0 : eq_pre;
eq_post = pre_shoot_only ? 0 : eq_post;
if (no_ffe) {
eq_pre = 0;
eq_post = 0;
eq_main = 0x3E;
}
REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
}
void dpcs30_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* EQ setting for DP lane0 */
uint32_t eq_main;
uint32_t eq_pre;
uint32_t eq_post;
REG_GET_3(RDPCSTX_PHY_FUSE0,
RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
lane_settings->amplitude[0] = eq_main;
lane_settings->pre_emphasis[0] = eq_pre;
lane_settings->post_emphasis[0] = eq_post;
REG_GET_3(RDPCSTX_PHY_FUSE1,
RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
lane_settings->amplitude[1] = eq_main;
lane_settings->pre_emphasis[1] = eq_pre;
lane_settings->post_emphasis[1] = eq_post;
REG_GET_3(RDPCSTX_PHY_FUSE2,
RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
lane_settings->amplitude[2] = eq_main;
lane_settings->pre_emphasis[2] = eq_pre;
lane_settings->post_emphasis[2] = eq_post;
REG_GET_3(RDPCSTX_PHY_FUSE3,
RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
lane_settings->amplitude[3] = eq_main;
lane_settings->pre_emphasis[3] = eq_pre;
lane_settings->post_emphasis[3] = eq_post;
}
void dpcs30_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* EQ setting for DP lane0 */
uint32_t eq_main;
uint32_t eq_pre;
uint32_t eq_post;
eq_main = lane_settings->amplitude[0];
eq_pre = lane_settings->pre_emphasis[0];
eq_post = lane_settings->post_emphasis[0];
REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
eq_main = lane_settings->amplitude[1];
eq_pre = lane_settings->pre_emphasis[1];
eq_post = lane_settings->post_emphasis[1];
REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
eq_main = lane_settings->amplitude[2];
eq_pre = lane_settings->pre_emphasis[2];
eq_post = lane_settings->post_emphasis[2];
REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
eq_main = lane_settings->amplitude[3];
eq_pre = lane_settings->pre_emphasis[3];
eq_post = lane_settings->post_emphasis[3];
REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
}
static const struct link_encoder_funcs dcn30_link_enc_funcs = {
@@ -84,6 +313,15 @@ static const struct link_encoder_funcs dcn30_link_enc_funcs = {
.get_dig_mode = dcn10_get_dig_mode,
.is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs30_program_eq_setting,
.get_txffe = dpcs30_get_txffe,
.set_txffe = dpcs30_set_txffe,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
};
@@ -198,6 +436,12 @@ void dcn30_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.DP_IS_USB_C =
bp_cap_info.DP_IS_USB_C;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -206,6 +450,12 @@ void dcn30_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
#define AUX_REG(reg)\
@@ -60,6 +60,8 @@
#define DPCS_DCN3_MASK_SH_LIST(mask_sh)\
DPCS_DCN2_MASK_SH_LIST(mask_sh),\
LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_HDMI_FRL_MODE, mask_sh),\
LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_DATA_SWAP_10_BIT, mask_sh),\
LE_SF(DPCSTX0_DPCSTX_TX_CNTL, DPCS_TX_DATA_ORDER_INVERT_18_BIT, mask_sh),\
LE_SF(RDPCSTX0_RDPCSTX_PHY_CNTL0, RDPCS_PHY_TX_VBOOST_LVL, mask_sh),\
LE_SF(RDPCSTX0_RDPCSTX_CLOCK_CNTL, RDPCS_TX_CLK_EN, mask_sh),\
@@ -83,4 +85,19 @@ bool dcn30_link_encoder_validate_output_with_stream(
struct link_encoder *enc,
const struct dc_stream_state *stream);
void dpcs30_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings);
void dpcs30_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
void dpcs30_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
#endif /* __DC_LINK_ENCODER__DCN30_H__ */
@@ -73,6 +73,13 @@ static const struct link_encoder_funcs dcn301_link_enc_funcs = {
.get_dig_mode = dcn10_get_dig_mode,
.is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = NULL,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
};
@@ -183,6 +190,11 @@ void dcn301_link_encoder_construct(
enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
enc10->base.features.flags.bits.DP_IS_USB_C =
bp_cap_info.DP_IS_USB_C;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -191,4 +203,10 @@ void dcn301_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -67,6 +67,17 @@
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
// HDMI FRL EQ Setting masks/shifts
// EQ level 0-32 bits[0:1]
#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
#define HDMI_FRL_EQ__LEVEL__MASK 0x3
// Enable no preshoot bit[5]
#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
// Enable no demphasis bit[6]
#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
// Enable no FFE bit[4]
#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
static uint8_t phy_id_from_transmitter(enum transmitter t)
{
uint8_t phy_id;
@@ -246,6 +257,89 @@ void enc31_hw_init(struct link_encoder *enc)
dcn10_aux_initialize(enc10);
}
static enum bp_result link_transmitter_control(
struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
enum bp_result result;
struct dc_bios *bp = enc10->base.ctx->dc_bios;
result = bp->funcs->transmitter_control(bp, cntl);
return result;
}
//---------------------------------------------------
// Task: Program EQ setting in HDMI FRL mode
// Note:
// EQ setting can be dont during P2 state or P0 state
// If set in P0 state, The values are latched in a single
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
// to be reflected on the output. During this period the
// analog serial lines might have a transitional behavior.
//---------------------------------------------------
void dpcs31_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
/* EQ setting for DP lane0 */
if (enc10->base.ctx->dc->debug.ignore_ffe)
return;
if (FFE_Level < 0x5)
enc10->base.txffe_state = FFE_Level;
if (FFE_Level == 0xEE) {
enc10->base.txffe_state++;
if (enc10->base.txffe_state > 3)
enc10->base.txffe_state = 0;
}
if (no_ffe) {
de_emphasis_only = true;
pre_shoot_only = true;
}
/* Pass on the input params to DMCUB for proper calc of eq settings */
cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
<< HDMI_FRL_EQ__LEVEL__SHIFT);
cntl.lane_select = 0;
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc10->base.transmitter;
cntl.connector_obj_id = enc10->base.connector;
cntl.lanes_number = link_settings->frl_num_lanes;
cntl.hpd_sel = enc10->base.hpd_source;
/* Use below or dc_link_frl_bandwidth_kbps()? */
switch (link_settings->frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667 / 10;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333 / 10;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444 / 10;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555 / 10;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
default:
cntl.pixel_clock = 666667 / 10;
break;
}
/* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
link_transmitter_control(enc10, &cntl);
}
static const struct link_encoder_funcs dcn31_link_enc_funcs = {
.read_state = link_enc2_read_state,
.validate_output_with_stream =
@@ -275,6 +369,15 @@ static const struct link_encoder_funcs dcn31_link_enc_funcs = {
.get_dig_mode = dcn10_get_dig_mode,
.is_in_alt_mode = dcn31_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn31_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs31_program_eq_setting,
.get_txffe = dpcs30_get_txffe,
.set_txffe = dpcs30_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
@@ -387,6 +490,11 @@ void dcn31_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.DP_IS_USB_C =
bp_cap_info.DP_IS_USB_C;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = bp_cap_info.IS_HDMI_FRL_CAPABLE;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -395,6 +503,12 @@ void dcn31_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
void dcn31_link_encoder_construct_minimal(
@@ -285,6 +285,14 @@ bool dcn31_link_encoder_is_in_alt_mode(
void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc,
struct dc_link_settings *link_settings);
void dpcs31_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings);
void enc31_hw_init(struct link_encoder *enc);
#endif /* __DC_LINK_ENCODER__DCN31_H__ */
@@ -62,6 +62,17 @@
#define AUX_REG_WRITE(reg_name, val) \
dm_write_reg(CTX, AUX_REG(reg_name), val)
// HDMI FRL EQ Setting masks/shifts
// EQ level 0-32 bits[0:1]
#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
#define HDMI_FRL_EQ__LEVEL__MASK 0x3
// Enable no preshoot bit[5]
#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
// Enable no demphasis bit[6]
#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
// Enable no FFE bit[4]
#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
static uint8_t phy_id_from_transmitter(enum transmitter t)
{
uint8_t phy_id;
@@ -203,6 +214,188 @@ void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
}
static enum bp_result link_transmitter_control(
struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
enum bp_result result;
struct dc_bios *bp = enc10->base.ctx->dc_bios;
result = bp->funcs->transmitter_control(bp, cntl);
return result;
}
//---------------------------------------------------
// Task: Program EQ setting
// Note:
// EQ setting can be dont during P2 state or P0 state
// If set in P0 state, The values are latched in a single
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
// to be reflected on the output. During this period the
// analog serial lines might have a transitional behavior.
//---------------------------------------------------
void dpcs32_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
/* EQ setting for DP lane0 */
if (enc10->base.ctx->dc->debug.ignore_ffe)
return;
if (FFE_Level < 0x5)
enc10->base.txffe_state = FFE_Level;
if (FFE_Level == 0xEE) {
enc10->base.txffe_state++;
if (enc10->base.txffe_state > 3)
enc10->base.txffe_state = 0;
}
if (no_ffe) {
de_emphasis_only = true;
pre_shoot_only = true;
}
/* Pass on the input params to DMCUB for proper calc of eq settings */
cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
<< HDMI_FRL_EQ__LEVEL__SHIFT);
cntl.lane_select = 0;
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc10->base.transmitter;
cntl.connector_obj_id = enc10->base.connector;
cntl.lanes_number = link_settings->frl_num_lanes;
cntl.hpd_sel = enc10->base.hpd_source;
/* Use below or dc_link_frl_bandwidth_kbps()? */
switch (link_settings->frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667 / 10;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333 / 10;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444 / 10;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555 / 10;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
default:
cntl.pixel_clock = 666667 / 10;
break;
}
/* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
link_transmitter_control(enc10, &cntl);
}
void dpcs32_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
(void)enc;
/* EQ setting for DP lane0 */
uint32_t eq_main = 0;
uint32_t eq_pre = 0;
uint32_t eq_post = 0;
/* TODO */
//REG_GET_3(RDPCSTX_PHY_FUSE0,
// RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
lane_settings->amplitude[0] = eq_main;
lane_settings->pre_emphasis[0] = eq_pre;
lane_settings->post_emphasis[0] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE1,
// RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
lane_settings->amplitude[1] = eq_main;
lane_settings->pre_emphasis[1] = eq_pre;
lane_settings->post_emphasis[1] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE2,
// RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
lane_settings->amplitude[2] = eq_main;
lane_settings->pre_emphasis[2] = eq_pre;
lane_settings->post_emphasis[2] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE3,
// RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
lane_settings->amplitude[3] = eq_main;
lane_settings->pre_emphasis[3] = eq_pre;
lane_settings->post_emphasis[3] = eq_post;
}
void dpcs32_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
(void)enc;
(void)lane_settings;
/* EQ setting for DP lane0 */
//uint32_t eq_main;
//uint32_t eq_pre;
//uint32_t eq_post;
//eq_main = lane_settings->amplitude[0];
//eq_pre = lane_settings->pre_emphasis[0];
//eq_post = lane_settings->post_emphasis[0];
/* TODO */
//REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
// RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
//eq_main = lane_settings->amplitude[1];
//eq_pre = lane_settings->pre_emphasis[1];
//eq_post = lane_settings->post_emphasis[1];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
// RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
//eq_main = lane_settings->amplitude[2];
//eq_pre = lane_settings->pre_emphasis[2];
//eq_post = lane_settings->post_emphasis[2];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
// RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
//1eq_main = lane_settings->amplitude[3];
//eq_pre = lane_settings->pre_emphasis[3];
//eq_post = lane_settings->post_emphasis[3];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
// RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
}
static const struct link_encoder_funcs dcn32_link_enc_funcs = {
.read_state = link_enc2_read_state,
.validate_output_with_stream =
@@ -232,6 +425,15 @@ static const struct link_encoder_funcs dcn32_link_enc_funcs = {
.get_dig_mode = dcn10_get_dig_mode,
.is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs32_program_eq_setting,
.get_txffe = dpcs32_get_txffe,
.set_txffe = dpcs32_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
@@ -329,6 +531,12 @@ void dcn32_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -337,4 +545,10 @@ void dcn32_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -50,4 +50,20 @@ bool dcn32_link_encoder_is_in_alt_mode(struct link_encoder *enc);
void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
struct dc_link_settings *link_settings);
void dpcs32_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings);
void dpcs32_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
void dpcs32_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
#endif /* __DC_LINK_ENCODER__DCN32_H__ */
@@ -88,6 +88,15 @@ static const struct link_encoder_funcs dcn321_link_enc_funcs = {
.get_dig_mode = dcn10_get_dig_mode,
.is_in_alt_mode = dcn20_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn20_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs32_program_eq_setting,
.get_txffe = dpcs32_get_txffe,
.set_txffe = dpcs32_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
@@ -183,6 +192,11 @@ void dcn321_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -190,4 +204,10 @@ void dcn321_link_encoder_construct(
}
if (enc10->base.ctx->dc->debug.hdmi20_disable)
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -158,6 +158,15 @@ static const struct link_encoder_funcs dcn35_link_enc_funcs = {
.get_dig_mode = dcn35_get_dig_mode,
.is_in_alt_mode = dcn31_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn31_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs32_program_eq_setting,
.get_txffe = dpcs32_get_txffe,
.set_txffe = dpcs32_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.enable_dpia_output = dcn35_link_encoder_enable_dpia_output,
.disable_dpia_output = dcn35_link_encoder_disable_dpia_output,
@@ -261,6 +270,12 @@ void dcn35_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -268,6 +283,12 @@ void dcn35_link_encoder_construct(
}
if (enc10->base.ctx->dc->debug.hdmi20_disable)
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -65,6 +65,17 @@
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
// HDMI FRL EQ Setting masks/shifts
// EQ level 0-32 bits[0:1]
#define HDMI_FRL_EQ__LEVEL__SHIFT 0x0
#define HDMI_FRL_EQ__LEVEL__MASK 0x3
// Enable no preshoot bit[5]
#define HDMI_FRL_EQ__NO_PRE__SHIFT 0x5
// Enable no demphasis bit[6]
#define HDMI_FRL_EQ__NO_DEMPH__SHIFT 0x6
// Enable no FFE bit[4]
#define HDMI_FRL_EQ__NO_FFE__SHIFT 0x4
void enc401_hw_init(struct link_encoder *enc)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
@@ -120,6 +131,194 @@ void dcn401_link_encoder_enable_dp_output(
}
}
static enum bp_result link_transmitter_control(
struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
enum bp_result result;
struct dc_bios *bp = enc10->base.ctx->dc_bios;
result = bp->funcs->transmitter_control(bp, cntl);
return result;
}
//---------------------------------------------------
// Task: Program EQ setting
// Note:
// EQ setting can be dont during P2 state or P0 state
// If set in P0 state, The values are latched in a single
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
// to be reflected on the output. During this period the
// analog serial lines might have a transitional behavior.
//---------------------------------------------------
void dpcs401_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
if (enc10->base.ctx->dc->debug.ignore_ffe)
return;
if (FFE_Level < 0x5)
enc10->base.txffe_state = FFE_Level;
if (enc10->base.ctx->dc->debug.select_ffe)
enc10->base.txffe_state =
(uint8_t)enc10->base.ctx->dc->debug.select_ffe;
if (FFE_Level == 0xEE) {
enc10->base.txffe_state++;
if (enc10->base.txffe_state > 3)
enc10->base.txffe_state = 0;
}
if (no_ffe) {
de_emphasis_only = true;
pre_shoot_only = true;
}
/* Pass on the input params to DMCUB for proper calc of eq settings */
cntl.lane_settings = ((de_emphasis_only ? 1 : 0) << HDMI_FRL_EQ__NO_PRE__SHIFT) |
((pre_shoot_only ? 1 : 0) << HDMI_FRL_EQ__NO_DEMPH__SHIFT) |
((enc10->base.txffe_state & HDMI_FRL_EQ__LEVEL__MASK)
<< HDMI_FRL_EQ__LEVEL__SHIFT);
cntl.lane_select = 0;
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc10->base.transmitter;
cntl.connector_obj_id = enc10->base.connector;
cntl.lanes_number = link_settings->frl_num_lanes;
cntl.hpd_sel = enc10->base.hpd_source;
/* Use below or dc_link_frl_bandwidth_kbps()? */
switch (link_settings->frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667 / 10;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333 / 10;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444 / 10;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555 / 10;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
default:
cntl.pixel_clock = 666667 / 10;
break;
}
/* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
link_transmitter_control(enc10, &cntl);
}
void dpcs401_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
(void)enc;
/* EQ setting for DP lane0 */
uint32_t eq_main = 0;
uint32_t eq_pre = 0;
uint32_t eq_post = 0;
/* TODO */
//REG_GET_3(RDPCSTX_PHY_FUSE0,
// RDPCS_PHY_DP_TX0_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX0_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX0_EQ_POST, &eq_post);
lane_settings->amplitude[0] = eq_main;
lane_settings->pre_emphasis[0] = eq_pre;
lane_settings->post_emphasis[0] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE1,
// RDPCS_PHY_DP_TX1_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX1_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX1_EQ_POST, &eq_post);
lane_settings->amplitude[1] = eq_main;
lane_settings->pre_emphasis[1] = eq_pre;
lane_settings->post_emphasis[1] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE2,
// RDPCS_PHY_DP_TX2_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX2_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX2_EQ_POST, &eq_post);
lane_settings->amplitude[2] = eq_main;
lane_settings->pre_emphasis[2] = eq_pre;
lane_settings->post_emphasis[2] = eq_post;
//REG_GET_3(RDPCSTX_PHY_FUSE3,
// RDPCS_PHY_DP_TX3_EQ_MAIN, &eq_main,
// RDPCS_PHY_DP_TX3_EQ_PRE, &eq_pre,
// RDPCS_PHY_DP_TX3_EQ_POST, &eq_post);
lane_settings->amplitude[3] = eq_main;
lane_settings->pre_emphasis[3] = eq_pre;
lane_settings->post_emphasis[3] = eq_post;
}
void dpcs401_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings)
{
(void)enc;
(void)lane_settings;
//struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
/* EQ setting for DP lane0 */
//TODO: Unused
//uint32_t eq_main;
//uint32_t eq_pre;
//uint32_t eq_post;
//eq_main = lane_settings->amplitude[0];
//eq_pre = lane_settings->pre_emphasis[0];
//eq_post = lane_settings->post_emphasis[0];
/* TODO */
//REG_UPDATE_3(RDPCSTX_PHY_FUSE0,
// RDPCS_PHY_DP_TX0_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX0_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX0_EQ_POST, eq_post);
//eq_main = lane_settings->amplitude[1];
//eq_pre = lane_settings->pre_emphasis[1];
//eq_post = lane_settings->post_emphasis[1];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE1,
// RDPCS_PHY_DP_TX1_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX1_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX1_EQ_POST, eq_post);
//eq_main = lane_settings->amplitude[2];
//eq_pre = lane_settings->pre_emphasis[2];
//eq_post = lane_settings->post_emphasis[2];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE2,
// RDPCS_PHY_DP_TX2_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX2_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX2_EQ_POST, eq_post);
//eq_main = lane_settings->amplitude[3];
//eq_pre = lane_settings->pre_emphasis[3];
//eq_post = lane_settings->post_emphasis[3];
//REG_UPDATE_3(RDPCSTX_PHY_FUSE3,
// RDPCS_PHY_DP_TX3_EQ_MAIN, eq_main,
// RDPCS_PHY_DP_TX3_EQ_PRE, eq_pre,
// RDPCS_PHY_DP_TX3_EQ_POST, eq_post);
}
void dcn401_link_encoder_setup(
struct link_encoder *enc,
enum signal_type signal)
@@ -214,6 +413,15 @@ static const struct link_encoder_funcs dcn401_link_enc_funcs = {
.get_dig_mode = dcn401_get_dig_mode,
.is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs401_program_eq_setting,
.get_txffe = dpcs401_get_txffe,
.set_txffe = dpcs401_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.get_hpd_state = dcn10_get_hpd_state,
.program_hpd_filter = dcn10_program_hpd_filter,
@@ -314,6 +522,12 @@ void dcn401_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -322,4 +536,10 @@ void dcn401_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -121,6 +121,22 @@ void dcn401_link_encoder_enable_dp_output(
const struct dc_link_settings *link_settings,
enum clock_source_id clock_source);
void dpcs401_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings);
void dpcs401_get_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
void dpcs401_set_txffe(
struct link_encoder *enc,
struct frl_txffe *lane_settings);
void dcn401_link_encoder_setup(
struct link_encoder *enc,
enum signal_type signal);
@@ -93,6 +93,15 @@ static const struct link_encoder_funcs dcn42_link_enc_funcs = {
.get_dig_mode = dcn401_get_dig_mode,
.is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs401_program_eq_setting,
.get_txffe = dpcs401_get_txffe,
.set_txffe = dpcs401_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.enable_dpia_output = dcn35_link_encoder_enable_dpia_output,
.disable_dpia_output = dcn35_link_encoder_disable_dpia_output,
@@ -194,6 +203,12 @@ void dcn42_link_encoder_construct(
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
@@ -202,4 +217,10 @@ void dcn42_link_encoder_construct(
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
}
}
@@ -27,6 +27,7 @@ ifdef CONFIG_DRM_AMD_DC_FP
###############################################################################
# DCN30
###############################################################################
HPO_DCN30 = dcn30_hpo_frl_link_encoder.o dcn30_hpo_frl_stream_encoder.o
AMD_DAL_HPO_DCN30 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn30/,$(HPO_DCN30))
@@ -48,10 +49,19 @@ AMD_DAL_HPO_DCN32 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn32/,$(HPO_DCN32))
AMD_DISPLAY_FILES += $(AMD_DAL_HPO_DCN32)
###############################################################################
# DCN401
###############################################################################
HPO_DCN401 = dcn401_hpo_frl_stream_encoder.o
AMD_DAL_HPO_DCN401 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn401/,$(HPO_DCN401))
AMD_DISPLAY_FILES += $(AMD_DAL_HPO_DCN401)
###############################################################################
# DCN42
###############################################################################
HPO_DCN42 = dcn42_hpo_dp_link_encoder.o
HPO_DCN42 += dcn42_hpo_frl_stream_encoder.o
AMD_DAL_HPO_DCN42 = $(addprefix $(AMDDALPATH)/dc/hpo/dcn42/,$(HPO_DCN42))
@@ -0,0 +1,286 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "core_types.h"
#include "dc_bios_types.h"
#include "dcn30_hpo_frl_link_encoder.h"
#include "reg_helper.h"
#include "dcn10/dcn10_link_encoder.h"
#define DC_LOGGER enc3->base.ctx->logger
#define REG(reg) (enc3->regs->reg)
#undef FN
#define FN(reg_name, field_name) enc3->hpo_le_shift->field_name, enc3->hpo_le_mask->field_name
#define CTX enc3->base.ctx
void hpo_frl_link_enc3_setup_link_encoder(struct hpo_frl_link_encoder *enc,
int lane_count)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
DC_LOG_DEBUG("Entering [%s]\n", __func__);
if (enc->ctx->dc->caps.ips_v2_support) {
REG_UPDATE(HDMI_FRL_ENC_MEM_CTRL,
METERBUFFER_MEM_PWR_DIS, 1);
REG_WAIT(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_STATE, 0, 1, 100);
}
/* Enable Link encoder clock */
REG_UPDATE(HDMI_LINK_ENC_CLK_CTRL,
HDMI_LINK_ENC_CLOCK_EN, 1);
/* Configure lane count of FRL encoder */
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE_COUNT, lane_count == 3 ? 0 : 1);
/* Reset link encoder */
REG_UPDATE_2(HDMI_LINK_ENC_CONTROL,
HDMI_LINK_ENC_ENABLE, 0,
HDMI_LINK_ENC_SOFT_RESET, 1);
REG_UPDATE(HDMI_LINK_ENC_CONTROL,
HDMI_LINK_ENC_SOFT_RESET, 0);
/* Enable link encoder */
REG_UPDATE(HDMI_LINK_ENC_CONTROL,
HDMI_LINK_ENC_ENABLE, 1);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_frl_link_enc3_set_training_pattern(struct hpo_frl_link_encoder *enc,
uint32_t lane0_pattern,
uint32_t lane1_pattern,
uint32_t lane2_pattern,
uint32_t lane3_pattern)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
/* Configure lane count of FRL encoder */
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_TRAINING_ENABLE, 1);
if (lane0_pattern < 8)
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE0_TRAINING_PATTERN, lane0_pattern);
if (lane1_pattern < 8)
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE1_TRAINING_PATTERN, lane1_pattern);
if (lane2_pattern < 8)
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE2_TRAINING_PATTERN, lane2_pattern);
if (lane3_pattern < 8)
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE3_TRAINING_PATTERN, lane3_pattern);
}
void hpo_frl_link_enc3_get_training_pattern(struct hpo_frl_link_encoder *enc,
uint32_t *lane0_pattern,
uint32_t *lane1_pattern,
uint32_t *lane2_pattern,
uint32_t *lane3_pattern)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
/* Configure lane count of FRL encoder */
REG_GET_4(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_LANE0_TRAINING_PATTERN, lane0_pattern,
HDMI_LINK_LANE1_TRAINING_PATTERN, lane1_pattern,
HDMI_LINK_LANE2_TRAINING_PATTERN, lane2_pattern,
HDMI_LINK_LANE3_TRAINING_PATTERN, lane3_pattern);
}
static enum bp_result link_transmitter_control(struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
struct dc_bios *bp = enc10->base.ctx->dc_bios;
return bp->funcs->transmitter_control(bp, cntl);
}
static void hpo_frl_link_enc3_enable_phy_output(struct hpo_frl_link_encoder *hpo_enc,
struct link_encoder *enc,
enum clock_source_id clock_source,
enum hdmi_frl_link_rate frl_link_rate)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(hpo_enc);
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
enum bp_result result;
/* Enable the PHY */
cntl.action = TRANSMITTER_CONTROL_ENABLE;
cntl.engine_id = enc->preferred_engine;
cntl.transmitter = enc10->base.transmitter;
cntl.pll_id = clock_source;
cntl.signal = SIGNAL_TYPE_HDMI_FRL;
cntl.hpd_sel = enc10->base.hpd_source;
switch (frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
default:
cntl.pixel_clock = 666667;
break;
}
cntl.hpo_engine_id = enc3->base.inst + ENGINE_ID_HPO_0;
if (frl_link_rate <= HDMI_FRL_LINK_RATE_6GBPS)
cntl.lanes_number = 3;
else
cntl.lanes_number = 4;
result = link_transmitter_control(enc10, &cntl);
if (result != BP_RESULT_OK) {
DC_LOG_HDMI_FRL("%s: Failed to execute VBIOS command table!\n", __func__);
BREAK_TO_DEBUGGER();
}
}
void hpo_frl_link_enc3_enable_output(struct hpo_frl_link_encoder *enc)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/* Enable FRL packet transmission */
REG_UPDATE(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_TRAINING_ENABLE, 0);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_frl_link_enc3_disable(struct hpo_frl_link_encoder *enc)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
REG_UPDATE_5(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_TRAINING_ENABLE, 1,
HDMI_LINK_LANE0_TRAINING_PATTERN, 0,
HDMI_LINK_LANE1_TRAINING_PATTERN, 0,
HDMI_LINK_LANE2_TRAINING_PATTERN, 0,
HDMI_LINK_LANE3_TRAINING_PATTERN, 0);
/* Disable link encoder */
REG_UPDATE(HDMI_LINK_ENC_CONTROL,
HDMI_LINK_ENC_ENABLE, 0);
/* Disable Link encoder clock */
REG_UPDATE(HDMI_LINK_ENC_CLK_CTRL,
HDMI_LINK_ENC_CLOCK_EN, 0);
REG_UPDATE(HDMI_FRL_ENC_CONFIG2,
HDMI_LINK_RC_COMPRESS_DISABLE, 0);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_frl_link_enc3_read_state(struct hpo_frl_link_encoder *enc,
struct hpo_frl_link_enc_state *state)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
unsigned int link_training_enabled;
unsigned int lane_count_field;
ASSERT(state);
REG_GET(HDMI_LINK_ENC_CONTROL,
HDMI_LINK_ENC_ENABLE, &state->link_enc_enabled);
REG_GET_2(HDMI_FRL_ENC_CONFIG,
HDMI_LINK_TRAINING_ENABLE, &link_training_enabled,
HDMI_LINK_LANE_COUNT, &lane_count_field);
state->link_active = link_training_enabled == 1;
if (lane_count_field == 1)
state->lane_count = 4;
else
state->lane_count = 3;
}
void hpo_frl_link_enc3_destroy(struct hpo_frl_link_encoder **enc)
{
kfree(DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(*enc));
*enc = NULL;
}
void hpo_frl_link_enc3_apply_vsdb_rcc_wa(struct hpo_frl_link_encoder *enc)
{
struct dcn30_hpo_frl_link_encoder *enc3 =
DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(enc);
REG_UPDATE(HDMI_FRL_ENC_CONFIG2,
HDMI_LINK_RC_COMPRESS_DISABLE, 1);
}
static struct hpo_frl_link_encoder_funcs dcn30_hpo_frl_link_encoder_funcs = {
.setup_link_encoder = hpo_frl_link_enc3_setup_link_encoder,
.set_hdmi_training_pattern = hpo_frl_link_enc3_set_training_pattern,
.get_hdmi_training_pattern = hpo_frl_link_enc3_get_training_pattern,
.enable_frl_phy_output = hpo_frl_link_enc3_enable_phy_output,
.enable_output = hpo_frl_link_enc3_enable_output,
.disable_link_encoder = hpo_frl_link_enc3_disable,
.read_state = hpo_frl_link_enc3_read_state,
.destroy = hpo_frl_link_enc3_destroy,
.apply_vsdb_rcc_wa = hpo_frl_link_enc3_apply_vsdb_rcc_wa
};
void hpo_frl_link_encoder3_construct(struct dcn30_hpo_frl_link_encoder *enc3,
struct dc_context *ctx,
uint32_t inst,
const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask)
{
enc3->base.ctx = ctx;
enc3->base.inst = inst;
enc3->base.funcs = &dcn30_hpo_frl_link_encoder_funcs;
enc3->regs = hpo_le_regs;
enc3->hpo_le_shift = hpo_le_shift;
enc3->hpo_le_mask = hpo_le_mask;
}
@@ -0,0 +1,146 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __DAL_DCN30_HPO_FRL_LINK_ENCODER_H__
#define __DAL_DCN30_HPO_FRL_LINK_ENCODER_H__
#include "link_encoder.h"
#define DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(hpo_frl_link_encoder)\
container_of(hpo_frl_link_encoder, struct dcn30_hpo_frl_link_encoder, base)
#define DCN3_0_HPO_FRL_LINK_ENC_REG_LIST(id) \
SR(HDMI_LINK_ENC_CLK_CTRL), \
SR(HDMI_LINK_ENC_CONTROL), \
SR(HDMI_FRL_ENC_CONFIG), \
SR(HDMI_FRL_ENC_CONFIG2),\
SR(HDMI_FRL_ENC_MEM_CTRL)
struct dcn30_hpo_frl_link_encoder_registers {
uint32_t HDMI_LINK_ENC_CLK_CTRL;
uint32_t HDMI_LINK_ENC_CONTROL;
uint32_t HDMI_FRL_ENC_CONFIG;
uint32_t HDMI_FRL_ENC_CONFIG2;
uint32_t HDMI_FRL_ENC_MEM_CTRL;
};
#define DCN3_0_HPO_FRL_LINK_ENC_MASK_SH_LIST(mask_sh)\
SE_SF(HDMI_LINK_ENC_CLK_CTRL, HDMI_LINK_ENC_CLOCK_EN, mask_sh),\
SE_SF(HDMI_LINK_ENC_CONTROL, HDMI_LINK_ENC_ENABLE, mask_sh),\
SE_SF(HDMI_LINK_ENC_CONTROL, HDMI_LINK_ENC_SOFT_RESET, mask_sh),\
SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_DIS, mask_sh),\
SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_FORCE, mask_sh),\
SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_PWR_STATE, mask_sh),\
SE_SF(HDMI_FRL_ENC_MEM_CTRL, METERBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE_COUNT, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_TRAINING_ENABLE, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE0_TRAINING_PATTERN, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE1_TRAINING_PATTERN, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE2_TRAINING_PATTERN, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG, HDMI_LINK_LANE3_TRAINING_PATTERN, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_MAX_JITTER_VALUE, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_THRESHOLD, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_CAL_EN, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_RC_COMPRESS_DISABLE, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_FRL_HDMISTREAMCLK_DB_SEL, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_MAX_JITTER_VALUE_RESET, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_JITTER_EXCEED_STATUS, mask_sh),\
SE_SF(HDMI_FRL_ENC_CONFIG2, HDMI_LINK_METER_BUFFER_OVERFLOW_STATUS, mask_sh)
#define HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(type) \
type HDMI_LINK_ENC_CLOCK_EN;\
type HDMI_LINK_ENC_ENABLE;\
type HDMI_LINK_ENC_SOFT_RESET;\
type HDMI_LINK_LANE_COUNT;\
type HDMI_LINK_TRAINING_ENABLE;\
type HDMI_LINK_LANE0_TRAINING_PATTERN;\
type HDMI_LINK_LANE1_TRAINING_PATTERN;\
type HDMI_LINK_LANE2_TRAINING_PATTERN;\
type HDMI_LINK_LANE3_TRAINING_PATTERN;\
type HDMI_LINK_MAX_JITTER_VALUE;\
type HDMI_LINK_JITTER_THRESHOLD;\
type HDMI_LINK_JITTER_CAL_EN;\
type HDMI_LINK_RC_COMPRESS_DISABLE;\
type METERBUFFER_MEM_PWR_DIS;\
type METERBUFFER_MEM_PWR_STATE;\
type METERBUFFER_MEM_PWR_FORCE;\
type METERBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE;\
type HDMI_FRL_HDMISTREAMCLK_DB_SEL;\
type HDMI_LINK_MAX_JITTER_VALUE_RESET;\
type HDMI_LINK_JITTER_EXCEED_STATUS;\
type HDMI_LINK_METER_BUFFER_OVERFLOW_STATUS
struct dcn30_hpo_frl_link_encoder_shift {
HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(uint8_t);
};
struct dcn30_hpo_frl_link_encoder_mask {
HPO_FRL_LINK_ENC_DCN3_REG_FIELD_LIST(uint32_t);
};
struct dcn30_hpo_frl_link_encoder {
struct hpo_frl_link_encoder base;
const struct dcn30_hpo_frl_link_encoder_registers *regs;
const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift;
const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask;
};
void hpo_frl_link_enc3_setup_link_encoder(struct hpo_frl_link_encoder *enc,
int lane_count);
void hpo_frl_link_enc3_set_training_pattern(struct hpo_frl_link_encoder *enc,
uint32_t lane0_pattern,
uint32_t lane1_pattern,
uint32_t lane2_pattern,
uint32_t lane3_pattern);
void hpo_frl_link_enc3_get_training_pattern(struct hpo_frl_link_encoder *enc,
uint32_t *lane0_pattern,
uint32_t *lane1_pattern,
uint32_t *lane2_pattern,
uint32_t *lane3_pattern);
void hpo_frl_link_enc3_enable_output(struct hpo_frl_link_encoder *enc);
void hpo_frl_link_enc3_disable(struct hpo_frl_link_encoder *enc);
void hpo_frl_link_enc3_read_state(struct hpo_frl_link_encoder *enc,
struct hpo_frl_link_enc_state *state);
void hpo_frl_link_enc3_destroy(struct hpo_frl_link_encoder **enc);
void hpo_frl_link_enc3_apply_vsdb_rcc_wa(struct hpo_frl_link_encoder *enc);
void hpo_frl_link_encoder3_construct(struct dcn30_hpo_frl_link_encoder *enc3,
struct dc_context *ctx,
uint32_t inst,
const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask);
#endif
@@ -0,0 +1,938 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "dc_bios_types.h"
#include "core_types.h"
#include "dcn30_hpo_frl_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "dcn_calc_math.h"
#include "dml/dcn30/dcn30_fpu.h"
#undef DC_LOGGER
#define DC_LOGGER enc3->base.ctx->logger
#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
#define DEBUG_FRL_CAP_CHK 1
#define REG(reg) (enc3->regs->reg)
#undef FN
#define FN(reg_name, field_name) enc3->hpo_se_shift->field_name, enc3->hpo_se_mask->field_name
#define CTX enc3->base.ctx
#define VBI_LINE_0 0
void hpo_enc3_enable(struct hpo_frl_stream_encoder *enc, int otg_inst)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/* Enable DISPCLK, SOCCLK, and HDMISTREAMCLK */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
HDMI_STREAM_ENC_CLOCK_EN, 1);
/* Reset */
REG_UPDATE_2(HDMI_TB_ENC_CONTROL,
HDMI_RESET, 1,
HDMI_TB_ENC_EN, 0);
REG_WAIT(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE,
1, 10, 100);
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_RESET, 0);
/* FOR DEBUG: enable CRC */
REG_UPDATE_2(HDMI_TB_ENC_CRC_CNTL,
HDMI_CRC_EN, 1,
HDMI_CRC_CONT_EN, 1);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2,
FIFO_DB_DISABLE, 1);
/* TODO: confirm if need to set HDMI_DB_DISABLE -- HW team only setting FIFO_DB_DISABLE */
REG_UPDATE(HDMI_TB_ENC_DB_CONTROL,
HDMI_DB_DISABLE, 1);
/* Set the input mux to select OTG source */
REG_UPDATE(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, otg_inst);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_enc3_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
{
(void)otg_inst;
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 0);
/* Reset */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 1);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
1, 10, 1000);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 0);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
0, 10, 1000);
/* Enable HDMI Tribyte Encoder */
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, 1);
/* Enable Clock Ramp Adjuster FIFO */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 1);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
bool hpo_enc3_fifo_odm_enabled(struct hpo_frl_stream_encoder *enc)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
uint32_t fifo_odm_combine_mode;
REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ODM_COMBINE_MODE, &fifo_odm_combine_mode);
return (fifo_odm_combine_mode != 0);
}
void hpo_enc3_blank(struct hpo_frl_stream_encoder *enc)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
/* Disable Clock Ramp Adjuster FIFO */
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 0,
FIFO_ODM_COMBINE_MODE, 0);
/* Disable HDMI Tribyte Encoder */
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, 0);
/* Disable DISPCLK, SOCCLK, and HDMISTREAMCLK */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
HDMI_STREAM_ENC_CLOCK_EN, 0);
}
/* Setup stream encoder in hdmi mode
* - Precondition: link is trained
*/
void hpo_enc3_set_hdmi_stream_attribute(struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
struct frl_borrow_params *borrow_params,
int odm_combine_num_segments)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
uint32_t h_active;
uint32_t h_blank;
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/* Configure pixel encoding */
switch (crtc_timing->pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 1);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING, 1);
break;
case PIXEL_ENCODING_YCBCR420:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 2);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING, 2);
break;
default:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 0);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING, 0);
break;
}
/* Configure color depth */
switch (crtc_timing->display_color_depth) {
case COLOR_DEPTH_888:
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 0,
HDMI_DEEP_COLOR_ENABLE, 0);
break;
case COLOR_DEPTH_101010:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_121212:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
default:
break;
}
/* Configure ODM combine mode */
switch (odm_combine_num_segments) {
case 1:
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ODM_COMBINE_MODE, 0);
if (enc3->hpo_se_mask->HDMI_ODM_COMBINE_MODE)
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_ODM_COMBINE_MODE, 0);
break;
case 2:
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ODM_COMBINE_MODE, 1);
if (enc3->hpo_se_mask->HDMI_ODM_COMBINE_MODE)
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_ODM_COMBINE_MODE, 1);
break;
case 4:
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ODM_COMBINE_MODE, 3);
break;
default:
break;
}
/* Configure horizontal active and blank size */
h_active = crtc_timing->h_addressable + crtc_timing->h_border_left + crtc_timing->h_border_right;
h_blank = crtc_timing->h_total - h_active;
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
h_active /= 2;
h_blank /= 2;
}
REG_SET_2(HDMI_TB_ENC_H_ACTIVE_BLANK, 0,
HDMI_H_ACTIVE, h_active,
HDMI_H_BLANK, h_blank);
/* Configure borrow parameters */
REG_UPDATE(HDMI_TB_ENC_MODE,
HDMI_BORROW_MODE, borrow_params->borrow_mode);
REG_UPDATE(HDMI_TB_ENC_PACKET_CONTROL,
HDMI_MAX_PACKETS_PER_LINE, borrow_params->audio_packets_line);
REG_SET_2(HDMI_TB_ENC_HC_ACTIVE_BLANK, 0,
HDMI_HC_ACTIVE, borrow_params->hc_active_target,
HDMI_HC_BLANK, borrow_params->hc_blank_target);
/* Enable transmission of General Control packet on every frame */
REG_UPDATE_2(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
HDMI_GC_CONT, 1,
HDMI_GC_SEND, 1);
/* Disable Audio Content Protection packet transmission */
/* TODO: review if this needs to be here */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
HDMI_ACP_SEND, 0);
/* Enable Audio InfoFrame packet transmission. */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
HDMI_AUDIO_INFO_SEND, 1);
/* update double-buffered AUDIO_INFO registers immediately */
ASSERT(enc->afmt);
enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
/* Select line number on which to send Audio InfoFrame packets */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE,
VBI_LINE_0 + 2);
/* set HDMI GC AVMUTE */
REG_UPDATE(HDMI_TB_ENC_GC_CONTROL,
HDMI_GC_AVMUTE, 0);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_enc3_update_hdmi_info_packets(struct hpo_frl_stream_encoder *enc,
const struct encoder_info_frame *info_frame)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
hpo_enc3_update_hdmi_info_packet(enc3, 0, &info_frame->avi);
hpo_enc3_update_hdmi_info_packet(enc3, 1, &info_frame->vendor);
hpo_enc3_update_hdmi_info_packet(enc3, 2, &info_frame->gamut);
hpo_enc3_update_hdmi_info_packet(enc3, 3, &info_frame->spd);
hpo_enc3_update_hdmi_info_packet(enc3, 4, &info_frame->hdrsmd);
/* 5-10 used by dsc */
hpo_enc3_update_hdmi_info_packet(enc3, 11, &info_frame->hfvsif);
hpo_enc3_update_hdmi_info_packet(enc3, 12, &info_frame->vtem);
}
void hpo_enc3_update_hdmi_info_packet(struct dcn30_hpo_frl_stream_encoder *enc3,
uint32_t packet_index,
const struct dc_info_packet *info_packet)
{
uint32_t cont, send, line;
if (info_packet->valid) {
enc3->base.vpg->funcs->update_generic_info_packet(
enc3->base.vpg,
packet_index,
info_packet,
true);
/* enable transmission of packet(s) -
* packet transmission begins on the next frame */
cont = 1;
/* send packet(s) every frame */
send = 1;
/* select line number to send packets on */
/* TODO: check if line 2 is correct */
line = 2;
} else {
cont = 0;
send = 0;
line = 0;
}
/* TODO: set bit to indicate if packet is Extended Metadata Packet. */
/* TODO: In DCN3, there are 0-14 generic packets */
/* choose which generic packet control to use */
switch (packet_index) {
case 0:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
HDMI_GENERIC0_LINE, line);
break;
case 1:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
HDMI_GENERIC1_LINE, line);
break;
case 2:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC2_CONT, cont,
HDMI_GENERIC2_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
HDMI_GENERIC2_LINE, line);
break;
case 3:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC3_CONT, cont,
HDMI_GENERIC3_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
HDMI_GENERIC3_LINE, line);
break;
case 4:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC4_CONT, cont,
HDMI_GENERIC4_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
HDMI_GENERIC4_LINE, line);
break;
case 5:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC5_CONT, cont,
HDMI_GENERIC5_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
HDMI_GENERIC5_LINE, line);
break;
case 6:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC6_CONT, cont,
HDMI_GENERIC6_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
HDMI_GENERIC6_LINE, line);
break;
case 7:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC7_CONT, cont,
HDMI_GENERIC7_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
HDMI_GENERIC7_LINE, line);
break;
case 8:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC8_CONT, cont,
HDMI_GENERIC8_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
HDMI_GENERIC8_LINE, line);
break;
case 9:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC9_CONT, cont,
HDMI_GENERIC9_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
HDMI_GENERIC9_LINE, line);
break;
case 10:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC10_CONT, cont,
HDMI_GENERIC10_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
HDMI_GENERIC10_LINE, line);
break;
case 11:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC11_CONT, cont,
HDMI_GENERIC11_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
HDMI_GENERIC11_LINE, line);
break;
case 12:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC12_CONT, cont,
HDMI_GENERIC12_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
HDMI_GENERIC12_LINE, line);
break;
case 13:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC13_CONT, cont,
HDMI_GENERIC13_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
HDMI_GENERIC13_LINE, line);
break;
case 14:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC14_CONT, cont,
HDMI_GENERIC14_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET14_LINE,
HDMI_GENERIC14_LINE, line);
break;
default:
/* invalid HW packet index */
DC_LOG_WARNING("Invalid HW packet index: %s()\n", __func__);
return;
}
}
void hpo_enc3_stop_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
/* TODO: should also set extended metadata packet bit back to 0? */
/* stop generic packets 0,1 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC0_CONT, 0,
HDMI_GENERIC0_SEND, 0,
HDMI_GENERIC1_CONT, 0,
HDMI_GENERIC1_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, 0,
HDMI_GENERIC0_LINE, 0,
HDMI_GENERIC1_LINE, 0);
/* stop generic packets 2,3 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC2_CONT, 0,
HDMI_GENERIC2_SEND, 0,
HDMI_GENERIC3_CONT, 0,
HDMI_GENERIC3_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, 0,
HDMI_GENERIC2_LINE, 0,
HDMI_GENERIC3_LINE, 0);
/* stop generic packets 4,5 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC4_CONT, 0,
HDMI_GENERIC4_SEND, 0,
HDMI_GENERIC5_CONT, 0,
HDMI_GENERIC5_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, 0,
HDMI_GENERIC4_LINE, 0,
HDMI_GENERIC5_LINE, 0);
/* stop generic packets 6,7 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC6_CONT, 0,
HDMI_GENERIC6_SEND, 0,
HDMI_GENERIC7_CONT, 0,
HDMI_GENERIC7_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, 0,
HDMI_GENERIC6_LINE, 0,
HDMI_GENERIC7_LINE, 0);
/* stop generic packets 8,9 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC8_CONT, 0,
HDMI_GENERIC8_SEND, 0,
HDMI_GENERIC9_CONT, 0,
HDMI_GENERIC9_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, 0,
HDMI_GENERIC8_LINE, 0,
HDMI_GENERIC9_LINE, 0);
/* stop generic packets 10,11 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC10_CONT, 0,
HDMI_GENERIC10_SEND, 0,
HDMI_GENERIC11_CONT, 0,
HDMI_GENERIC11_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, 0,
HDMI_GENERIC10_LINE, 0,
HDMI_GENERIC11_LINE, 0);
/* stop generic packets 12,13 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC12_CONT, 0,
HDMI_GENERIC12_SEND, 0,
HDMI_GENERIC13_CONT, 0,
HDMI_GENERIC13_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, 0,
HDMI_GENERIC12_LINE, 0,
HDMI_GENERIC13_LINE, 0);
/* stop generic packets 14 on HDMI */
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC14_CONT, 0,
HDMI_GENERIC14_SEND, 0);
REG_SET(HDMI_TB_ENC_GENERIC_PACKET14_LINE, 0,
HDMI_GENERIC14_LINE, 0);
}
//Covered both, rounding up or rounding down from FRL Link Rate /18.
static const struct frl_audio_clock_info frl_audio_clock_info_table[10] = {
{166666, 4224, 171875, 5292, 156250, 5760, 156250},
{166667, 4224, 171875, 5292, 156250, 5760, 156250},
{333333, 4032, 328125, 5292, 312500, 6048, 328125},
{333334, 4032, 328125, 5292, 312500, 6048, 328125},
{444444, 4032, 437500, 3969, 312500, 6048, 437500},
{444445, 4032, 437500, 3969, 312500, 6048, 437500},
{555555, 3456, 468750, 3969, 390625, 5184, 468750},
{555556, 3456, 468750, 3969, 390625, 5184, 468750},
{666666, 3072, 500000, 3969, 468750, 4752, 515625},
{666667, 3072, 500000, 3969, 468750, 4752, 515625}
};
static void get_audio_clock_info(
enum dc_color_depth color_depth,
uint32_t frl_character_clock_kHz,
struct frl_audio_clock_info *audio_clock_info)
{
(void)color_depth;
const struct frl_audio_clock_info *clock_info;
uint32_t index;
uint32_t audio_array_size;
clock_info = frl_audio_clock_info_table;
audio_array_size = ARRAY_SIZE(
frl_audio_clock_info_table);
if (clock_info != NULL) {
/* search for exact frl character clock in table */
for (index = 0; index < audio_array_size; index++) {
if (clock_info[index].frl_character_clock_kHz >
frl_character_clock_kHz)
break; /* not match */
else if (clock_info[index].frl_character_clock_kHz ==
frl_character_clock_kHz) {
/* match found */
*audio_clock_info = clock_info[index];
return;
}
}
}
/*Only 3, 6, 8, 10 and 12 Gbps are used for FRL Link rates with character
*clocks of 166.667, 333.333, 444.444, 555.555 and 666.667 MHz are used
*so entry should be found in above table if no bugs */
BREAK_TO_DEBUGGER();
}
void hpo_enc3_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
struct frl_audio_clock_info audio_clock_info = {0};
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* TODO: HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
/* HDMI_AUDIO_PACKET_CONTROL */
//REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
// HDMI_AUDIO_DELAY_EN, 1);
/* Setup audio in AFMT - program AFMT block associated with HPO */
ASSERT (enc->afmt);
enc->afmt->funcs->setup_hdmi_audio(enc->afmt);
/* TODO: Same programming, but using HDMI_TB_ENC register */
/* HDMI_ACR_PACKET_CONTROL */
REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0,
HDMI_ACR_AUDIO_PRIORITY, 0);
/* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
/* Program audio clock sample/regeneration parameters */
get_audio_clock_info(crtc_info->color_depth,
crtc_info->frl_character_clock_kHz,
&audio_clock_info);
DC_LOG_HW_AUDIO(
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d \n", __func__, \
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
/* Same register definition, but using HDMI_TB_ENC register */
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
/* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
* Same register definition, but using HDMI_TB_ENC register*/
/* Video driver cannot know in advance which sample rate will
* be used by HD Audio driver
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
* programmed below in interrupt callback
*/
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
void hpo_enc3_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
hpo_enc3_setup_hdmi_audio(enc, audio_crtc_info);
ASSERT (enc->afmt);
enc->afmt->funcs->se_audio_setup(enc->afmt, az_inst, info);
}
void hpo_enc3_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc)
{
ASSERT(enc->afmt);
if (enc->afmt->funcs->afmt_powerdown)
enc->afmt->funcs->afmt_powerdown(enc->afmt);
}
void hpo_enc3_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
ASSERT (enc->afmt);
enc->afmt->funcs->audio_mute_control(enc->afmt, mute);
}
void enc3_stream_encoder_set_avmute(
struct hpo_frl_stream_encoder *enc,
bool enable)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
unsigned int value = enable ? 1 : 0;
REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, value);
}
static enum frl_cap_chk_result frl_cap_chk_uncompressed(
struct hpo_frl_stream_encoder *enc,
struct frl_cap_chk_params *params,
struct frl_cap_chk_intermediates *inter)
{
int res;
DC_FP_START();
res = frl_fpu_cap_chk_uncompressed(enc, params, inter);
DC_FP_END();
return res;
}
static enum frl_cap_chk_result frl_cap_chk_compressed(
struct hpo_frl_stream_encoder *enc,
struct frl_cap_chk_params *params,
struct frl_cap_chk_intermediates *inter)
{
int res;
DC_FP_START();
res = frl_fpu_cap_chk_compressed(enc, params, inter);
DC_FP_END();
return res;
}
static bool hpo_enc3_frl_cap_chk(
struct hpo_frl_stream_encoder *enc,
struct frl_cap_chk_params *params)
{
struct frl_cap_chk_intermediates inter;
enum frl_cap_chk_result res;
if (params->compressed)
res = frl_cap_chk_compressed(enc, params, &inter);
else
res = frl_cap_chk_uncompressed(enc, params, &inter);
return (res == FRL_CAP_CHK_OK);
}
bool hpo_enc3_validate_hdmi_frl_output(
struct hpo_frl_stream_encoder *enc,
const struct dc_crtc_timing *timing,
const struct audio_check *audio,
struct dc_hdmi_frl_link_settings *frl_link_settings,
unsigned int dsc_max_rate)
{
struct frl_cap_chk_params frl_params = {0};
bool frl_check_res = false;
/* Set inputs for FRL check */
frl_params.lanes = frl_link_settings->frl_num_lanes;
DC_FP_START();
hpo_fpu_enc3_validate_hdmi_frl_output_link(enc,
frl_link_settings,
&frl_params,
timing,
dsc_max_rate);
DC_FP_END();
if (timing->display_color_depth == COLOR_DEPTH_888)
frl_params.bpc = 8;
else if (timing->display_color_depth == COLOR_DEPTH_101010)
frl_params.bpc = 10;
else
frl_params.bpc = 12;
switch (timing->hdmi_vic) {
case 1:
frl_params.vic = 95;
break;
case 2:
frl_params.vic = 94;
break;
case 3:
frl_params.vic = 93;
break;
case 4:
frl_params.vic = 98;
break;
default:
break;
}
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_420;
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_422;
else
frl_params.pixel_encoding = HDMI_FRL_PIXEL_ENCODING_444;
/* Audio parameters */
/* TODO: set Audio parameters */
if (audio->audio_packet_type == 2) {
if (audio->max_channel_count <= 2
|| (timing->v_addressable + timing->v_border_top + timing->v_border_bottom) <= 576)
frl_params.layout = 0;
else
frl_params.layout = 1;
}
/* Check HDMI FRL Capacity and compute borrow parameters */
frl_check_res = hpo_enc3_frl_cap_chk(enc, &frl_params);
/* Save borrow parameters and average tribyte rate (for capture sideband) */
if (frl_check_res) {
frl_link_settings->borrow_params.audio_packets_line =
frl_params.borrow_params.audio_packets_line;
frl_link_settings->borrow_params.hc_active_target =
frl_params.borrow_params.hc_active_target;
frl_link_settings->borrow_params.hc_blank_target =
frl_params.borrow_params.hc_blank_target;
frl_link_settings->borrow_params.borrow_mode =
(unsigned int) frl_params.borrow_params.borrow_mode;
frl_link_settings->average_tribyte_rate = frl_params.average_tribyte_rate;
}
return frl_check_res;
}
void hpo_enc3_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state)
{
int pixel_encoding;
int color_depth;
int odm_combine;
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT(state);
REG_GET(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, &state->stream_enc_enabled);
REG_GET(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, &state->otg_inst);
REG_GET_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, &pixel_encoding,
HDMI_DEEP_COLOR_DEPTH, &color_depth);
REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ODM_COMBINE_MODE, &odm_combine);
REG_GET_2(HDMI_TB_ENC_H_ACTIVE_BLANK,
HDMI_H_ACTIVE, &state->h_active,
HDMI_H_BLANK, &state->h_blank);
REG_GET(HDMI_TB_ENC_MODE,
HDMI_BORROW_MODE, &state->borrow_mode);
if (pixel_encoding == 0)
state->pixel_format = PIXEL_ENCODING_YCBCR444;
else if (pixel_encoding == 1)
state->pixel_format = PIXEL_ENCODING_YCBCR422;
else
state->pixel_format = PIXEL_ENCODING_YCBCR420;
if (color_depth == 0)
state->color_depth = 8;
else if (color_depth == 1)
state->color_depth = 10;
else
state->color_depth = 12;
state->num_odm_segments = odm_combine + 1;
}
/* Set Dynamic Metadata-configuration.
* enable_dme: TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME
* hubp_requestor_id: HUBP physical instance that is the source of dynamic metadata
* only needs to be set when enable_dme is TRUE
* dmdata_mode: dynamic metadata packet type: DP, HDMI, or Dolby Vision
*
* Ensure the OTG master update lock is set when changing DME configuration.
*/
void hpo_enc3_set_dynamic_metadata(struct hpo_frl_stream_encoder *enc,
bool enable_dme,
uint32_t hubp_requestor_id,
enum dynamic_metadata_mode dmdata_mode)
{
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
if (enable_dme) {
REG_UPDATE_2(DME_CONTROL,
METADATA_HUBP_REQUESTOR_ID, hubp_requestor_id,
METADATA_STREAM_TYPE, (dmdata_mode == dmdata_dolby_vision) ? 1 : 0);
REG_UPDATE_3(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
HDMI_METADATA_PACKET_ENABLE, 1,
HDMI_METADATA_PACKET_LINE_REFERENCE, 0,
HDMI_METADATA_PACKET_LINE, 2);
REG_UPDATE(DME_CONTROL,
METADATA_ENGINE_EN, 1);
} else {
REG_UPDATE(DME_CONTROL,
METADATA_ENGINE_EN, 0);
REG_UPDATE(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
HDMI_METADATA_PACKET_ENABLE, 0);
}
}
static const struct hpo_frl_stream_encoder_funcs dcn30_str_enc_funcs = {
.hdmi_frl_enable = hpo_enc3_enable,
.hdmi_frl_unblank = hpo_enc3_unblank,
.hdmi_frl_blank = hpo_enc3_blank,
.hdmi_frl_set_stream_attribute = hpo_enc3_set_hdmi_stream_attribute,
.update_hdmi_info_packets = hpo_enc3_update_hdmi_info_packets,
.stop_hdmi_info_packets = hpo_enc3_stop_hdmi_info_packets,
.audio_mute_control = hpo_enc3_audio_mute_control,
.hdmi_audio_setup = hpo_enc3_hdmi_audio_setup,
.hdmi_audio_disable = hpo_enc3_hdmi_audio_disable,
.set_avmute = enc3_stream_encoder_set_avmute,
.validate_hdmi_frl_output = hpo_enc3_validate_hdmi_frl_output,
.read_state = hpo_enc3_read_state,
.set_dynamic_metadata = hpo_enc3_set_dynamic_metadata,
.hdmi_frl_fifo_odm_enabled = hpo_enc3_fifo_odm_enabled,
};
void dcn30_hpo_frl_stream_encoder_construct(
struct dcn30_hpo_frl_stream_encoder *enc3,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct afmt *afmt,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask)
{
enc3->base.funcs = &dcn30_str_enc_funcs;
enc3->base.ctx = ctx;
enc3->base.id = eng_id;
enc3->base.bp = bp;
enc3->base.vpg = vpg;
enc3->base.afmt = afmt;
enc3->regs = regs;
enc3->hpo_se_shift = hpo_se_shift;
enc3->hpo_se_mask = hpo_se_mask;
enc3->base.stream_enc_inst = vpg->inst;
}
@@ -0,0 +1,436 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN30_H__
#define __DC_HPO_FRL_STREAM_ENCODER_DCN30_H__
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "stream_encoder.h"
#include "dml/dml1_frl_cap_chk.h"
#define DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(hpo_frl_stream_encoder)\
container_of(hpo_frl_stream_encoder, struct dcn30_hpo_frl_stream_encoder, base)
#define SE_SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
#define DCN3_0_HDMI_STREAM_ENC_REG_LIST \
SR(HDMI_STREAM_ENC_CLOCK_CONTROL), \
SR(HDMI_STREAM_ENC_INPUT_MUX_CONTROL), \
SR(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0), \
SR(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2)
#define DCN3_0_HDMI_TB_ENC_REG_LIST \
SR(HDMI_TB_ENC_CONTROL), \
SR(HDMI_TB_ENC_H_ACTIVE_BLANK), \
SR(HDMI_TB_ENC_HC_ACTIVE_BLANK), \
SR(HDMI_TB_ENC_MODE), \
SR(HDMI_TB_ENC_PACKET_CONTROL), \
SR(HDMI_TB_ENC_DB_CONTROL), \
SR(HDMI_TB_ENC_PIXEL_FORMAT), \
SR(HDMI_TB_ENC_VBI_PACKET_CONTROL1), \
SR(HDMI_TB_ENC_GC_CONTROL), \
SR(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0), \
SR(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1), \
SR(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE), \
SR(HDMI_TB_ENC_GENERIC_PACKET14_LINE), \
SR(HDMI_TB_ENC_ACR_PACKET_CONTROL), \
SR(HDMI_TB_ENC_ACR_32_0), \
SR(HDMI_TB_ENC_ACR_32_1), \
SR(HDMI_TB_ENC_ACR_44_0), \
SR(HDMI_TB_ENC_ACR_44_1), \
SR(HDMI_TB_ENC_ACR_48_0), \
SR(HDMI_TB_ENC_ACR_48_1), \
SR(HDMI_TB_ENC_CRC_CNTL),\
SR(HDMI_TB_ENC_METADATA_PACKET_CONTROL)
#define DCN3_0_HPO_FRL_STREAM_ENC_REG_LIST(id) \
DCN3_0_HDMI_STREAM_ENC_REG_LIST, \
DCN3_0_HDMI_TB_ENC_REG_LIST
#define DCN3_0_HPO_STREAM_ENC_DME_REG_LIST(id, offset) \
[id - offset]SRI(DME_CONTROL, DME, id)
struct dcn30_hpo_frl_stream_enc_registers {
uint32_t HDMI_STREAM_ENC_CLOCK_CONTROL;
uint32_t HDMI_STREAM_ENC_INPUT_MUX_CONTROL;
uint32_t HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0;
uint32_t HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2;
uint32_t HDMI_STREAM_ENC_AUDIO_CONTROL;
uint32_t HDMI_TB_ENC_CONTROL;
uint32_t HDMI_TB_ENC_MODE;
uint32_t HDMI_TB_ENC_H_ACTIVE_BLANK;
uint32_t HDMI_TB_ENC_HC_ACTIVE_BLANK;
uint32_t HDMI_TB_ENC_PACKET_CONTROL;
uint32_t HDMI_TB_ENC_DB_CONTROL;
uint32_t HDMI_TB_ENC_PIXEL_FORMAT;
uint32_t HDMI_TB_ENC_VBI_PACKET_CONTROL1;
uint32_t HDMI_TB_ENC_GC_CONTROL;
uint32_t HDMI_TB_ENC_GENERIC_PACKET_CONTROL0;
uint32_t HDMI_TB_ENC_GENERIC_PACKET_CONTROL1;
uint32_t HDMI_TB_ENC_GENERIC_PACKET0_1_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET2_3_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET4_5_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET6_7_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET8_9_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET10_11_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET12_13_LINE;
uint32_t HDMI_TB_ENC_GENERIC_PACKET14_LINE;
uint32_t HDMI_TB_ENC_ACR_PACKET_CONTROL;
uint32_t HDMI_TB_ENC_ACR_32_0;
uint32_t HDMI_TB_ENC_ACR_32_1;
uint32_t HDMI_TB_ENC_ACR_44_0;
uint32_t HDMI_TB_ENC_ACR_44_1;
uint32_t HDMI_TB_ENC_ACR_48_0;
uint32_t HDMI_TB_ENC_ACR_48_1;
uint32_t HDMI_TB_ENC_CRC_CNTL;
uint32_t DME_CONTROL;
uint32_t HDMI_TB_ENC_METADATA_PACKET_CONTROL;
uint32_t HDMI_TB_ENC_MEM_CTRL;
uint32_t HDMI_FRL_ENC_MEM_CTRL;
};
#define DCN3_0_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
SE_SF(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ENABLE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_PIXEL_ENCODING, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ODM_COMBINE_MODE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_DSC_MODE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_DIS, mask_sh),\
SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_FORCE, mask_sh),\
SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_PWR_STATE, mask_sh),\
SE_SF(HDMI_TB_ENC_MEM_CTRL, BORROWBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_MISSED, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh)
#define DCN3_0_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_TB_ENC_EN, mask_sh),\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET, mask_sh),\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE, mask_sh),\
SE_SF(HDMI_TB_ENC_MODE, HDMI_BORROW_MODE, mask_sh),\
SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_ACTIVE, mask_sh),\
SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_BLANK, mask_sh),\
SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_ACTIVE, mask_sh),\
SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_BLANK, mask_sh),\
SE_SF(HDMI_TB_ENC_PACKET_CONTROL, HDMI_MAX_PACKETS_PER_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_PIXEL_ENCODING, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DSC_MODE, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC0_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC1_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC2_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC3_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC4_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC5_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC6_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC7_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC8_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC9_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC10_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC11_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC12_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC13_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET14_LINE, HDMI_GENERIC14_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUDIO_PRIORITY, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_EN, mask_sh),\
SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_CONT_EN, mask_sh)
#define DCN3_0_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh)\
DCN3_0_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh),\
DCN3_0_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)
#define DCN3_HDMI_TB_ENC_REG_FIELD_LIST(type) \
type HDMI_TB_ENC_EN;\
type HDMI_RESET;\
type HDMI_RESET_DONE;\
type HDMI_STREAM_ENC_CLOCK_EN;\
type HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL;\
type HDMI_MAX_PACKETS_PER_LINE;\
type FIFO_ENABLE;\
type FIFO_RESET;\
type FIFO_RESET_DONE;\
type FIFO_PIXEL_ENCODING;\
type FIFO_ODM_COMBINE_MODE;\
type FIFO_DSC_MODE;\
type FIFO_DB_DISABLE;\
type HDMI_BORROW_MODE;\
type HDMI_H_ACTIVE;\
type HDMI_H_BLANK;\
type HDMI_HC_ACTIVE;\
type HDMI_HC_BLANK;\
type HDMI_DB_DISABLE;\
type HDMI_PIXEL_ENCODING;\
type HDMI_DEEP_COLOR_DEPTH;\
type HDMI_DEEP_COLOR_ENABLE;\
type HDMI_ODM_COMBINE_MODE;\
type HDMI_DSC_MODE;\
type HDMI_GC_CONT;\
type HDMI_GC_SEND;\
type HDMI_ACP_SEND;\
type HDMI_AUDIO_INFO_SEND;\
type HDMI_AUDIO_INFO_LINE;\
type HDMI_GC_AVMUTE;\
type HDMI_GENERIC0_CONT;\
type HDMI_GENERIC0_SEND;\
type HDMI_GENERIC0_LINE;\
type HDMI_GENERIC1_CONT;\
type HDMI_GENERIC1_SEND;\
type HDMI_GENERIC1_LINE;\
type HDMI_GENERIC2_CONT;\
type HDMI_GENERIC2_SEND;\
type HDMI_GENERIC2_LINE;\
type HDMI_GENERIC3_CONT;\
type HDMI_GENERIC3_SEND;\
type HDMI_GENERIC3_LINE;\
type HDMI_GENERIC4_CONT;\
type HDMI_GENERIC4_SEND;\
type HDMI_GENERIC4_LINE;\
type HDMI_GENERIC5_CONT;\
type HDMI_GENERIC5_SEND;\
type HDMI_GENERIC5_LINE;\
type HDMI_GENERIC6_CONT;\
type HDMI_GENERIC6_SEND;\
type HDMI_GENERIC6_LINE;\
type HDMI_GENERIC7_CONT;\
type HDMI_GENERIC7_SEND;\
type HDMI_GENERIC7_LINE;\
type HDMI_GENERIC8_CONT;\
type HDMI_GENERIC8_SEND;\
type HDMI_GENERIC8_LINE;\
type HDMI_GENERIC9_CONT;\
type HDMI_GENERIC9_SEND;\
type HDMI_GENERIC9_LINE;\
type HDMI_GENERIC10_CONT;\
type HDMI_GENERIC10_SEND;\
type HDMI_GENERIC10_LINE;\
type HDMI_GENERIC11_CONT;\
type HDMI_GENERIC11_SEND;\
type HDMI_GENERIC11_LINE;\
type HDMI_GENERIC12_CONT;\
type HDMI_GENERIC12_SEND;\
type HDMI_GENERIC12_LINE;\
type HDMI_GENERIC13_CONT;\
type HDMI_GENERIC13_SEND;\
type HDMI_GENERIC13_LINE;\
type HDMI_GENERIC14_CONT;\
type HDMI_GENERIC14_SEND;\
type HDMI_GENERIC14_LINE;\
type HDMI_ACR_AUTO_SEND;\
type HDMI_ACR_SOURCE;\
type HDMI_ACR_AUDIO_PRIORITY;\
type HDMI_ACR_CTS_32;\
type HDMI_ACR_N_32;\
type HDMI_ACR_CTS_44;\
type HDMI_ACR_N_44;\
type HDMI_ACR_CTS_48;\
type HDMI_ACR_N_48;\
type HDMI_CRC_EN;\
type HDMI_CRC_CONT_EN;\
type METADATA_HUBP_REQUESTOR_ID;\
type METADATA_ENGINE_EN;\
type METADATA_STREAM_TYPE;\
type HDMI_METADATA_PACKET_ENABLE;\
type HDMI_METADATA_PACKET_LINE_REFERENCE;\
type HDMI_METADATA_PACKET_MISSED;\
type HDMI_METADATA_PACKET_LINE;\
type BORROWBUFFER_MEM_PWR_DIS;\
type BORROWBUFFER_MEM_PWR_FORCE;\
type BORROWBUFFER_MEM_PWR_STATE;\
type BORROWBUFFER_MEM_DEFAULT_MEM_LOW_POWER_STATE
struct dcn30_hpo_frl_stream_encoder_shift {
DCN3_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
};
struct dcn30_hpo_frl_stream_encoder_mask {
DCN3_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
};
struct dcn30_hpo_frl_stream_encoder {
struct hpo_frl_stream_encoder base;
const struct dcn30_hpo_frl_stream_enc_registers *regs;
const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift;
const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask;
};
void hpo_enc3_enable(
struct hpo_frl_stream_encoder *enc,
int otg_inst);
void hpo_enc3_unblank(
struct hpo_frl_stream_encoder *enc,
int otg_inst);
void hpo_enc3_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state);
bool hpo_enc3_fifo_odm_enabled(
struct hpo_frl_stream_encoder *enc);
void hpo_enc3_blank(
struct hpo_frl_stream_encoder *enc);
void hpo_enc3_set_hdmi_stream_attribute(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
struct frl_borrow_params *borrow_params,
int odm_combine_num_segments);
void hpo_enc3_update_hdmi_info_packet(
struct dcn30_hpo_frl_stream_encoder *enc3,
uint32_t packet_index,
const struct dc_info_packet *info_packet);
void hpo_enc3_update_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc,
const struct encoder_info_frame *info_frame);
void hpo_enc3_hdmi_set_dsc_config(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *timing,
uint8_t *dsc_packed_pps);
void hpo_enc3_stop_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc);
void hpo_enc3_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info);
void hpo_enc3_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info);
void hpo_enc3_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc);
void hpo_enc3_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute);
void enc3_stream_encoder_set_avmute(
struct hpo_frl_stream_encoder *enc,
bool enable);
bool hpo_enc3_validate_hdmi_frl_output(
struct hpo_frl_stream_encoder *enc,
const struct dc_crtc_timing *timing,
const struct audio_check *audio,
struct dc_hdmi_frl_link_settings *frl_link_settings,
unsigned int dsc_max_rate);
void hpo_enc3_set_dynamic_metadata(
struct hpo_frl_stream_encoder *enc,
bool enable_dme,
uint32_t hubp_requestor_id,
enum dynamic_metadata_mode dmdata_mode);
void dcn30_hpo_frl_stream_encoder_construct(
struct dcn30_hpo_frl_stream_encoder *enc3,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct afmt *afmt,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn30_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn30_hpo_frl_stream_encoder_mask *hpo_se_mask);
void convert_dc_info_packet_to_128(
const struct dc_info_packet *info_packet,
struct dc_info_packet_128 *info_packet_128);
#endif
@@ -0,0 +1,906 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "dc_bios_types.h"
#include "core_types.h"
#include "dcn401_hpo_frl_stream_encoder.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "dcn_calc_math.h"
#include "dml/dcn30/dcn30_fpu.h"
#undef DC_LOGGER
#define DC_LOGGER \
enc401->base.ctx->logger
#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
#define DEBUG_FRL_CAP_CHK 1
#define REG(reg)\
(enc401->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
enc401->hpo_se_shift->field_name, enc401->hpo_se_mask->field_name
#define CTX \
enc401->base.ctx
#define VBI_LINE_0 0
void hpo_enc401_enable(
struct hpo_frl_stream_encoder *enc,
int otg_inst)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* Enable DISPCLK, SOCCLK, and HDMISTREAMCLK */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, 1);
/* Reset */
REG_UPDATE_2(HDMI_TB_ENC_CONTROL,
HDMI_RESET, 1,
HDMI_TB_ENC_EN, 0);
REG_WAIT(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE,
1, 10, 100);
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_RESET, 0);
/* FOR DEBUG: enable CRC */
REG_UPDATE_2(HDMI_TB_ENC_CRC_CNTL,
HDMI_CRC_EN, 1,
HDMI_CRC_CONT_EN, 1);
// REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL2, FIFO_DB_DISABLE, 1);
/* TODO: confirm if need to set HDMI_DB_DISABLE -- HW team only setting FIFO_DB_DISABLE */
REG_UPDATE(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, 1);
/* Set the input mux to select OTG source */
REG_UPDATE(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, otg_inst);
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
void hpo_enc401_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
{
(void)otg_inst;
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 0);
/* Reset */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 1);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
1, 10, 1000);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 0);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
0, 10, 1000);
/* Enable HDMI Tribyte Encoder */
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, 1);
/* Enable Clock Ramp Adjuster FIFO */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 1);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_enc401_blank(struct hpo_frl_stream_encoder *enc)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
/* Disable Clock Ramp Adjuster FIFO */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 0);
/* Disable HDMI Tribyte Encoder */
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, 0);
/* Disable DISPCLK, SOCCLK, and HDMISTREAMCLK */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_CONTROL,
HDMI_STREAM_ENC_CLOCK_EN, 0);
}
void hpo_enc401_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state)
{
int pixel_encoding;
int color_depth;
// int odm_combine;
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT(state);
REG_GET(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, &state->stream_enc_enabled);
REG_GET(HDMI_STREAM_ENC_INPUT_MUX_CONTROL,
HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, &state->otg_inst);
REG_GET_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, &pixel_encoding,
HDMI_DEEP_COLOR_DEPTH, &color_depth);
// REG_GET(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
// FIFO_ODM_COMBINE_MODE, &odm_combine);
REG_GET_2(HDMI_TB_ENC_H_ACTIVE_BLANK,
HDMI_H_ACTIVE, &state->h_active,
HDMI_H_BLANK, &state->h_blank);
REG_GET(HDMI_TB_ENC_MODE,
HDMI_BORROW_MODE, &state->borrow_mode);
if (pixel_encoding == 0)
state->pixel_format = PIXEL_ENCODING_YCBCR444;
else if (pixel_encoding == 1)
state->pixel_format = PIXEL_ENCODING_YCBCR422;
else
state->pixel_format = PIXEL_ENCODING_YCBCR420;
if (color_depth == 0)
state->color_depth = 8;
else if (color_depth == 1)
state->color_depth = 10;
else
state->color_depth = 12;
// state->num_odm_segments = odm_combine + 1;
}
/* setup stream encoder in hdmi mode */
/* Precondition: link is trained */
void hpo_enc401_set_hdmi_stream_attribute(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
struct frl_borrow_params *borrow_params,
int odm_combine_num_segments)
{
(void)odm_combine_num_segments;
uint32_t h_active;
uint32_t h_blank;
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* Configure pixel encoding */
switch (crtc_timing->pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 1);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
break;
case PIXEL_ENCODING_YCBCR420:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 2);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 1);
break;
default:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 0);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
break;
}
/* Configure color depth */
switch (crtc_timing->display_color_depth) {
case COLOR_DEPTH_888:
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 0,
HDMI_DEEP_COLOR_ENABLE, 0);
break;
case COLOR_DEPTH_101010:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_121212:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
default:
break;
}
/* When compression active, CD/PP/Phase field shall be zero in GCP */
if (crtc_timing->flags.DSC) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 0,
HDMI_DEEP_COLOR_ENABLE, 0);
}
/* Configure horizontal active and blank size */
h_active = crtc_timing->h_addressable + crtc_timing->h_border_left + crtc_timing->h_border_right;
h_blank = crtc_timing->h_total - h_active;
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
h_active /= 2;
h_blank /= 2;
}
REG_SET_2(HDMI_TB_ENC_H_ACTIVE_BLANK, 0,
HDMI_H_ACTIVE, h_active,
HDMI_H_BLANK, h_blank);
/* Configure borrow parameters */
REG_UPDATE(HDMI_TB_ENC_MODE,
HDMI_BORROW_MODE, borrow_params->borrow_mode);
REG_UPDATE(HDMI_TB_ENC_PACKET_CONTROL,
HDMI_MAX_PACKETS_PER_LINE, borrow_params->audio_packets_line);
REG_SET_2(HDMI_TB_ENC_HC_ACTIVE_BLANK, 0,
HDMI_HC_ACTIVE, borrow_params->hc_active_target,
HDMI_HC_BLANK, borrow_params->hc_blank_target);
/* Enable transmission of General Control packet on every frame */
REG_UPDATE_2(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
HDMI_GC_CONT, 1,
HDMI_GC_SEND, 1);
/* Disable Audio Content Protection packet transmission */
/* TODO: review if this needs to be here */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, 0);
/* Enable Audio InfoFrame packet transmission. */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, 1);
/* update double-buffered AUDIO_INFO registers immediately */
if (enc->afmt && enc->afmt->funcs->audio_info_immediate_update)
enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
/* Select line number on which to send Audio InfoFrame packets */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE,
VBI_LINE_0 + 2);
/* set HDMI GC AVMUTE */
REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, 0);
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
void hpo_enc401_update_hdmi_info_packet(
struct dcn401_hpo_frl_stream_encoder *enc401,
uint32_t packet_index,
const struct dc_info_packet *info_packet)
{
uint32_t cont, send, line;
if (info_packet->valid) {
enc401->base.vpg->funcs->update_generic_info_packet(
enc401->base.vpg,
packet_index,
info_packet,
true);
/* enable transmission of packet(s) -
* packet transmission begins on the next frame
*/
cont = 1;
/* send packet(s) every frame */
send = 1;
/* select line number to send packets on */
/* TODO: check if line 2 is correct */
line = 2;
} else {
cont = 0;
send = 0;
line = 0;
}
/* TODO: set bit to indicate if packet is Extended Metadata Packet. */
/* TODO: In DCN3, there are 0-14 generic packets */
/* choose which generic packet control to use */
switch (packet_index) {
case 0:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
HDMI_GENERIC0_LINE, line);
break;
case 1:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE,
HDMI_GENERIC1_LINE, line);
break;
case 2:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC2_CONT, cont,
HDMI_GENERIC2_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
HDMI_GENERIC2_LINE, line);
break;
case 3:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC3_CONT, cont,
HDMI_GENERIC3_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE,
HDMI_GENERIC3_LINE, line);
break;
case 4:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC4_CONT, cont,
HDMI_GENERIC4_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
HDMI_GENERIC4_LINE, line);
break;
case 5:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC5_CONT, cont,
HDMI_GENERIC5_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE,
HDMI_GENERIC5_LINE, line);
break;
case 6:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC6_CONT, cont,
HDMI_GENERIC6_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
HDMI_GENERIC6_LINE, line);
break;
case 7:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC7_CONT, cont,
HDMI_GENERIC7_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE,
HDMI_GENERIC7_LINE, line);
break;
case 8:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC8_CONT, cont,
HDMI_GENERIC8_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
HDMI_GENERIC8_LINE, line);
break;
case 9:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC9_CONT, cont,
HDMI_GENERIC9_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE,
HDMI_GENERIC9_LINE, line);
break;
case 10:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC10_CONT, cont,
HDMI_GENERIC10_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
HDMI_GENERIC10_LINE, line);
break;
case 11:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC11_CONT, cont,
HDMI_GENERIC11_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE,
HDMI_GENERIC11_LINE, line);
break;
case 12:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC12_CONT, cont,
HDMI_GENERIC12_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
HDMI_GENERIC12_LINE, line);
break;
case 13:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC13_CONT, cont,
HDMI_GENERIC13_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE,
HDMI_GENERIC13_LINE, line);
break;
case 14:
REG_UPDATE_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC14_CONT, cont,
HDMI_GENERIC14_SEND, send);
REG_UPDATE(HDMI_TB_ENC_GENERIC_PACKET14_LINE,
HDMI_GENERIC14_LINE, line);
break;
default:
/* invalid HW packet index */
DC_LOG_WARNING(
"Invalid HW packet index: %s()\n",
__func__);
return;
}
}
void hpo_enc401_update_hdmi_info_packets(struct hpo_frl_stream_encoder *enc,
const struct encoder_info_frame *info_frame)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
hpo_enc401_update_hdmi_info_packet(enc401, 0, &info_frame->avi);
hpo_enc401_update_hdmi_info_packet(enc401, 1, &info_frame->vendor);
hpo_enc401_update_hdmi_info_packet(enc401, 2, &info_frame->gamut);
hpo_enc401_update_hdmi_info_packet(enc401, 3, &info_frame->spd);
hpo_enc401_update_hdmi_info_packet(enc401, 4, &info_frame->hdrsmd);
/* 5-10 used by dsc */
hpo_enc401_update_hdmi_info_packet(enc401, 11, &info_frame->hfvsif);
hpo_enc401_update_hdmi_info_packet(enc401, 12, &info_frame->vtem);
}
void hpo_enc401_hdmi_set_dsc_config(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *timing,
uint8_t *dsc_packed_pps)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
enum optc_dsc_mode dsc_mode = OPTC_DSC_DISABLED;
uint8_t i;
if (dsc_packed_pps) {
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
(timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
&& !timing->dsc_cfg.ycbcr422_simple))
dsc_mode = OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
else
dsc_mode = OPTC_DSC_ENABLED_444;
}
switch (dsc_mode) {
case OPTC_DSC_DISABLED:
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 0,
FIFO_COMPRESSED_PIXEL_FORMAT, 0);
break;
case OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED:
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 1,
FIFO_COMPRESSED_PIXEL_FORMAT, 1);
break;
case OPTC_DSC_ENABLED_444:
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 1,
FIFO_COMPRESSED_PIXEL_FORMAT, 0);
break;
}
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DSC_MODE, dsc_mode);
/* 5 packets for hdmi 2.1, use generic packets 5-10 to transmit*/
/* TODO: do we change new bit to 0 after first transmission? Do we set End bit when exiting dsc? */
if (dsc_mode != OPTC_DSC_DISABLED) {
struct dc_info_packet emp_packet = {0};
/* Need to find the padded h_total to recover the expected h_back*/
uint32_t h_active_padding = timing->h_addressable % timing->dsc_cfg.num_slices_h;
if (h_active_padding != 0)
h_active_padding = timing->dsc_cfg.num_slices_h - h_active_padding;
/* if YCBCR420, ensure slice width is even */
uint32_t slice_width = (timing->h_addressable + h_active_padding) / timing->dsc_cfg.num_slices_h;
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
slice_width % 2 != 0)
h_active_padding += timing->dsc_cfg.num_slices_h;
uint32_t dsc_pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right + h_active_padding;
uint32_t h_back = timing->h_total - dsc_pic_width - timing->h_sync_width - timing->h_front_porch + h_active_padding;
/* HCactivebytes = Slices * ceil(SliceWidth * bpp/8)
* Since bpp is stored as 16x actual value do (sliceWidth * bpp + 127) / 128 to ceil
*/
uint32_t h_cactive_bytes = timing->dsc_cfg.num_slices_h * (
(dsc_pic_width /
timing->dsc_cfg.num_slices_h * timing->dsc_cfg.bits_per_pixel + 127) / 128);
/* Packet 0 */
emp_packet.valid = true;
emp_packet.hb0 = 0x7F; /* Default */
emp_packet.hb1 = (1 << 7); /* First */
emp_packet.hb2 = 0; /* Sequence index */
emp_packet.sb[0] = (1 << 1) | (1 << 2) | (1 << 7); /* Sync[1] = 1, VFR[2] = 1, New[7] = 1*/
emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
hpo_enc401_update_hdmi_info_packet(enc401, 5, &emp_packet);
/* Packets 1-3 */
emp_packet.hb1 = 0; /* Not first or last*/
for (i = 1; i < 4; i++) {
emp_packet.hb2 = i; /* Sequence index */
memcpy(&emp_packet.sb[0], &dsc_packed_pps[21 + 28 * (i - 1)], 28);
hpo_enc401_update_hdmi_info_packet(enc401, 5 + i, &emp_packet);
}
/* Packet 4 */
emp_packet.hb2 = 4; /* Sequence index */
memcpy(&emp_packet.sb[0], &dsc_packed_pps[105], 23);
emp_packet.sb[23] = (uint8_t)timing->h_front_porch; /* Hfront[7:0] */
emp_packet.sb[24] = (uint8_t)(timing->h_front_porch >> 8); /* Hfront[15:8] */
emp_packet.sb[25] = (uint8_t)timing->h_sync_width; /* Hsync[7:0] */
emp_packet.sb[26] = (uint8_t)(timing->h_sync_width >> 8); /* Hsync[15:8] */
emp_packet.sb[27] = (uint8_t)h_back; /* Hback[7:0] */
hpo_enc401_update_hdmi_info_packet(enc401, 9, &emp_packet);
/* Packet 5 */
emp_packet.hb1 = (1 << 6); /* Last */
emp_packet.hb2 = 5;
emp_packet.sb[0] = (uint8_t)(h_back >> 8); /* Hback[15:8] */
emp_packet.sb[1] = (uint8_t)h_cactive_bytes; /* HCactive_bytes[7:0] */
emp_packet.sb[2] = (uint8_t)(h_cactive_bytes >> 8); /* HCactive_bytes[15:8] */
hpo_enc401_update_hdmi_info_packet(enc401, 10, &emp_packet);
/* Packet 0 - Clear New[7] */
emp_packet.valid = true;
emp_packet.hb0 = 0x7F; /* Default */
emp_packet.hb1 = (1 << 7); /* First */
emp_packet.hb2 = 0; /* Sequence index */
emp_packet.sb[0] = (1 << 1) | (1 << 2); /* Sync[1] = 1, VFR[2] = 1*/
emp_packet.sb[2] = 1; /* Organization_ID = 1 (Vesa spec)*/
emp_packet.sb[4] = 2; /* Data_Set_Tag(LSB) = 2*/
emp_packet.sb[6] = 136; /* Data_Set_Length(LSB) = 136*/
memcpy(&emp_packet.sb[7], dsc_packed_pps, 21);
hpo_enc401_update_hdmi_info_packet(enc401, 5, &emp_packet);
}
}
void hpo_enc401_stop_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
/* TODO: should also set extended metadata packet bit back to 0? */
/* stop generic packets 0,1 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC0_CONT, 0,
HDMI_GENERIC0_SEND, 0,
HDMI_GENERIC1_CONT, 0,
HDMI_GENERIC1_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, 0,
HDMI_GENERIC0_LINE, 0,
HDMI_GENERIC1_LINE, 0);
/* stop generic packets 2,3 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC2_CONT, 0,
HDMI_GENERIC2_SEND, 0,
HDMI_GENERIC3_CONT, 0,
HDMI_GENERIC3_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, 0,
HDMI_GENERIC2_LINE, 0,
HDMI_GENERIC3_LINE, 0);
/* stop generic packets 4,5 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC4_CONT, 0,
HDMI_GENERIC4_SEND, 0,
HDMI_GENERIC5_CONT, 0,
HDMI_GENERIC5_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, 0,
HDMI_GENERIC4_LINE, 0,
HDMI_GENERIC5_LINE, 0);
/* stop generic packets 6,7 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, 0,
HDMI_GENERIC6_CONT, 0,
HDMI_GENERIC6_SEND, 0,
HDMI_GENERIC7_CONT, 0,
HDMI_GENERIC7_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, 0,
HDMI_GENERIC6_LINE, 0,
HDMI_GENERIC7_LINE, 0);
/* stop generic packets 8,9 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC8_CONT, 0,
HDMI_GENERIC8_SEND, 0,
HDMI_GENERIC9_CONT, 0,
HDMI_GENERIC9_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, 0,
HDMI_GENERIC8_LINE, 0,
HDMI_GENERIC9_LINE, 0);
/* stop generic packets 10,11 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC10_CONT, 0,
HDMI_GENERIC10_SEND, 0,
HDMI_GENERIC11_CONT, 0,
HDMI_GENERIC11_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, 0,
HDMI_GENERIC10_LINE, 0,
HDMI_GENERIC11_LINE, 0);
/* stop generic packets 12,13 on HDMI */
REG_SET_4(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC12_CONT, 0,
HDMI_GENERIC12_SEND, 0,
HDMI_GENERIC13_CONT, 0,
HDMI_GENERIC13_SEND, 0);
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, 0,
HDMI_GENERIC12_LINE, 0,
HDMI_GENERIC13_LINE, 0);
/* stop generic packets 14 on HDMI */
REG_SET_2(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, 0,
HDMI_GENERIC14_CONT, 0,
HDMI_GENERIC14_SEND, 0);
REG_SET(HDMI_TB_ENC_GENERIC_PACKET14_LINE, 0,
HDMI_GENERIC14_LINE, 0);
}
//Covered both, rounding up or rounding down from FRL Link Rate /18.
static const struct frl_audio_clock_info frl_audio_clock_info_table[10] = {
{166666, 4224, 171875, 5292, 156250, 5760, 156250},
{166667, 4224, 171875, 5292, 156250, 5760, 156250},
{333333, 4032, 328125, 5292, 312500, 6048, 328125},
{333334, 4032, 328125, 5292, 312500, 6048, 328125},
{444444, 4032, 437500, 3969, 312500, 6048, 437500},
{444445, 4032, 437500, 3969, 312500, 6048, 437500},
{555555, 3456, 468750, 3969, 390625, 5184, 468750},
{555556, 3456, 468750, 3969, 390625, 5184, 468750},
{666666, 3072, 500000, 3969, 468750, 4752, 515625},
{666667, 3072, 500000, 3969, 468750, 4752, 515625}
};
void frl_get_audio_clock_info(
enum dc_color_depth color_depth,
uint32_t frl_character_clock_kHz,
struct frl_audio_clock_info *audio_clock_info)
{
(void)color_depth;
const struct frl_audio_clock_info *clock_info;
uint32_t index;
uint32_t audio_array_size;
clock_info = frl_audio_clock_info_table;
audio_array_size = ARRAY_SIZE(
frl_audio_clock_info_table);
if (clock_info != NULL) {
/* search for exact frl character clock in table */
for (index = 0; index < audio_array_size; index++) {
if (clock_info[index].frl_character_clock_kHz >
frl_character_clock_kHz)
break; /* not match */
else if (clock_info[index].frl_character_clock_kHz ==
frl_character_clock_kHz) {
/* match found */
*audio_clock_info = clock_info[index];
return;
}
}
}
/*Only 3, 6, 8, 10 and 12 Gbps are used for FRL Link rates with character
*clocks of 166.667, 333.333, 444.444, 555.555 and 666.667 MHz are used
*so entry should be found in above table if no bugs */
BREAK_TO_DEBUGGER();
}
void hpo_enc401_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
struct frl_audio_clock_info audio_clock_info = {0};
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* TODO: HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
/* HDMI_AUDIO_PACKET_CONTROL */
//REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
// HDMI_AUDIO_DELAY_EN, 1);
/* Setup audio in AFMT - program AFMT block associated with HPO */
ASSERT (enc->afmt);
enc->afmt->funcs->setup_hdmi_audio(enc->afmt);
/* TODO: Same programming, but using HDMI_TB_ENC register */
/* HDMI_ACR_PACKET_CONTROL */
REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0,
HDMI_ACR_AUDIO_PRIORITY, 0);
/* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
/* Program audio clock sample/regeneration parameters */
frl_get_audio_clock_info(crtc_info->color_depth,
crtc_info->frl_character_clock_kHz,
&audio_clock_info);
DC_LOG_HW_AUDIO(
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d \n", __func__, \
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
/* Same register definition, but using HDMI_TB_ENC register */
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
/* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
* Same register definition, but using HDMI_TB_ENC register*/
/* Video driver cannot know in advance which sample rate will
* be used by HD Audio driver
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
* programmed below in interrupt callback
*/
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
void hpo_enc401_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
hpo_enc401_setup_hdmi_audio(enc, audio_crtc_info);
ASSERT (enc->afmt);
enc->afmt->funcs->se_audio_setup(enc->afmt, az_inst, info);
}
void hpo_enc401_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc)
{
ASSERT(enc->afmt);
if (enc->afmt->funcs->afmt_powerdown)
enc->afmt->funcs->afmt_powerdown(enc->afmt);
}
void hpo_enc401_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
ASSERT (enc->afmt);
enc->afmt->funcs->audio_mute_control(enc->afmt, mute);
}
void enc401_stream_encoder_set_avmute(
struct hpo_frl_stream_encoder *enc,
bool enable)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
unsigned int value = enable ? 1 : 0;
REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, value);
}
/* Set Dynamic Metadata-configuration.
* enable_dme: TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME
* hubp_requestor_id: HUBP physical instance that is the source of dynamic metadata
* only needs to be set when enable_dme is TRUE
* dmdata_mode: dynamic metadata packet type: DP, HDMI, or Dolby Vision
*
* Ensure the OTG master update lock is set when changing DME configuration.
*/
void hpo_enc401_set_dynamic_metadata(struct hpo_frl_stream_encoder *enc,
bool enable_dme,
uint32_t hubp_requestor_id,
enum dynamic_metadata_mode dmdata_mode)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
if (enable_dme) {
REG_UPDATE_2(DME_CONTROL,
METADATA_HUBP_REQUESTOR_ID, hubp_requestor_id,
METADATA_STREAM_TYPE, (dmdata_mode == dmdata_dolby_vision) ? 1 : 0);
REG_UPDATE_3(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
HDMI_METADATA_PACKET_ENABLE, 1,
HDMI_METADATA_PACKET_LINE_REFERENCE, 0,
HDMI_METADATA_PACKET_LINE, 2);
REG_UPDATE(DME_CONTROL,
METADATA_ENGINE_EN, 1);
} else {
REG_UPDATE(DME_CONTROL,
METADATA_ENGINE_EN, 0);
REG_UPDATE(HDMI_TB_ENC_METADATA_PACKET_CONTROL,
HDMI_METADATA_PACKET_ENABLE, 0);
}
}
static const struct hpo_frl_stream_encoder_funcs dcn401_str_enc_funcs = {
.hdmi_frl_enable = hpo_enc401_enable,
.hdmi_frl_unblank = hpo_enc401_unblank,
.hdmi_frl_blank = hpo_enc401_blank,
.hdmi_frl_set_stream_attribute = hpo_enc401_set_hdmi_stream_attribute,
.validate_hdmi_frl_output = hpo_enc3_validate_hdmi_frl_output,
.update_hdmi_info_packets = hpo_enc401_update_hdmi_info_packets,
.stop_hdmi_info_packets = hpo_enc401_stop_hdmi_info_packets,
.audio_mute_control = hpo_enc401_audio_mute_control,
.hdmi_audio_setup = hpo_enc401_hdmi_audio_setup,
.hdmi_audio_disable = hpo_enc401_hdmi_audio_disable,
.set_avmute = enc401_stream_encoder_set_avmute,
.read_state = hpo_enc401_read_state,
.set_dynamic_metadata = hpo_enc401_set_dynamic_metadata,
};
void dcn401_hpo_frl_stream_encoder_construct(
struct dcn401_hpo_frl_stream_encoder *enc401,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct afmt *afmt,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask)
{
enc401->base.funcs = &dcn401_str_enc_funcs;
enc401->base.ctx = ctx;
enc401->base.id = eng_id;
enc401->base.bp = bp;
enc401->base.vpg = vpg;
enc401->base.afmt = afmt;
enc401->regs = regs;
enc401->hpo_se_shift = hpo_se_shift;
enc401->hpo_se_mask = hpo_se_mask;
enc401->base.stream_enc_inst = vpg->inst;
}
@@ -0,0 +1,335 @@
/*
* Copyright 2023 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN401_H__
#define __DC_HPO_FRL_STREAM_ENCODER_DCN401_H__
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "stream_encoder.h"
#include "dml/dml1_frl_cap_chk.h"
#define DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(hpo_frl_stream_encoder)\
container_of(hpo_frl_stream_encoder, struct dcn401_hpo_frl_stream_encoder, base)
#define SE_SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
#define DCN401_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
SE_SF(HDMI_STREAM_ENC_INPUT_MUX_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_ENABLE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_PIXEL_ENCODING_TYPE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_UNCOMPRESSED_PIXEL_FORMAT, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_COMPRESSED_PIXEL_FORMAT, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE, mask_sh),\
SE_SF(HDMI_STREAM_ENC_CLOCK_CONTROL, HDMI_STREAM_ENC_CLOCK_EN, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_MISSED, mask_sh),\
SE_SF(HDMI_TB_ENC_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh)
#define DCN401_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_TB_ENC_EN, mask_sh),\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET, mask_sh),\
SE_SF(HDMI_TB_ENC_CONTROL, HDMI_RESET_DONE, mask_sh),\
SE_SF(HDMI_TB_ENC_MODE, HDMI_BORROW_MODE, mask_sh),\
SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_ACTIVE, mask_sh),\
SE_SF(HDMI_TB_ENC_H_ACTIVE_BLANK, HDMI_H_BLANK, mask_sh),\
SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_ACTIVE, mask_sh),\
SE_SF(HDMI_TB_ENC_HC_ACTIVE_BLANK, HDMI_HC_BLANK, mask_sh),\
SE_SF(HDMI_TB_ENC_PACKET_CONTROL, HDMI_MAX_PACKETS_PER_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_PIXEL_ENCODING, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
SE_SF(HDMI_TB_ENC_PIXEL_FORMAT, HDMI_DSC_MODE, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_GC_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_CONT, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC8_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC9_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC10_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC11_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC12_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC13_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET_CONTROL1, HDMI_GENERIC14_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC0_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET0_1_LINE, HDMI_GENERIC1_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC2_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET2_3_LINE, HDMI_GENERIC3_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC4_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET4_5_LINE, HDMI_GENERIC5_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC6_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET6_7_LINE, HDMI_GENERIC7_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC8_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET8_9_LINE, HDMI_GENERIC9_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC10_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET10_11_LINE, HDMI_GENERIC11_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC12_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET12_13_LINE, HDMI_GENERIC13_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_GENERIC_PACKET14_LINE, HDMI_GENERIC14_LINE, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_PACKET_CONTROL, HDMI_ACR_AUDIO_PRIORITY, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
SE_SF(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_EN, mask_sh),\
SE_SF(HDMI_TB_ENC_CRC_CNTL, HDMI_CRC_CONT_EN, mask_sh)
#define DCN401_HDMI_TB_ENC_REG_FIELD_LIST(type) \
type HDMI_TB_ENC_EN;\
type HDMI_RESET;\
type HDMI_RESET_DONE;\
type HDMI_STREAM_ENC_CLOCK_EN;\
type HDMI_STREAM_ENC_INPUT_MUX_SOURCE_SEL;\
type HDMI_MAX_PACKETS_PER_LINE;\
type FIFO_ENABLE;\
type FIFO_RESET;\
type FIFO_PIXEL_ENCODING_TYPE;\
type FIFO_UNCOMPRESSED_PIXEL_FORMAT;\
type FIFO_COMPRESSED_PIXEL_FORMAT;\
type FIFO_RESET_DONE;\
type HDMI_BORROW_MODE;\
type HDMI_H_ACTIVE;\
type HDMI_H_BLANK;\
type HDMI_HC_ACTIVE;\
type HDMI_HC_BLANK;\
type HDMI_DB_DISABLE;\
type HDMI_PIXEL_ENCODING;\
type HDMI_DEEP_COLOR_DEPTH;\
type HDMI_DEEP_COLOR_ENABLE;\
type HDMI_ODM_COMBINE_MODE;\
type HDMI_DSC_MODE;\
type HDMI_GC_CONT;\
type HDMI_GC_SEND;\
type HDMI_ACP_SEND;\
type HDMI_AUDIO_INFO_SEND;\
type HDMI_AUDIO_INFO_LINE;\
type HDMI_GC_AVMUTE;\
type HDMI_GENERIC0_CONT;\
type HDMI_GENERIC0_SEND;\
type HDMI_GENERIC0_LINE;\
type HDMI_GENERIC1_CONT;\
type HDMI_GENERIC1_SEND;\
type HDMI_GENERIC1_LINE;\
type HDMI_GENERIC2_CONT;\
type HDMI_GENERIC2_SEND;\
type HDMI_GENERIC2_LINE;\
type HDMI_GENERIC3_CONT;\
type HDMI_GENERIC3_SEND;\
type HDMI_GENERIC3_LINE;\
type HDMI_GENERIC4_CONT;\
type HDMI_GENERIC4_SEND;\
type HDMI_GENERIC4_LINE;\
type HDMI_GENERIC5_CONT;\
type HDMI_GENERIC5_SEND;\
type HDMI_GENERIC5_LINE;\
type HDMI_GENERIC6_CONT;\
type HDMI_GENERIC6_SEND;\
type HDMI_GENERIC6_LINE;\
type HDMI_GENERIC7_CONT;\
type HDMI_GENERIC7_SEND;\
type HDMI_GENERIC7_LINE;\
type HDMI_GENERIC8_CONT;\
type HDMI_GENERIC8_SEND;\
type HDMI_GENERIC8_LINE;\
type HDMI_GENERIC9_CONT;\
type HDMI_GENERIC9_SEND;\
type HDMI_GENERIC9_LINE;\
type HDMI_GENERIC10_CONT;\
type HDMI_GENERIC10_SEND;\
type HDMI_GENERIC10_LINE;\
type HDMI_GENERIC11_CONT;\
type HDMI_GENERIC11_SEND;\
type HDMI_GENERIC11_LINE;\
type HDMI_GENERIC12_CONT;\
type HDMI_GENERIC12_SEND;\
type HDMI_GENERIC12_LINE;\
type HDMI_GENERIC13_CONT;\
type HDMI_GENERIC13_SEND;\
type HDMI_GENERIC13_LINE;\
type HDMI_GENERIC14_CONT;\
type HDMI_GENERIC14_SEND;\
type HDMI_GENERIC14_LINE;\
type HDMI_ACR_AUTO_SEND;\
type HDMI_ACR_SOURCE;\
type HDMI_ACR_AUDIO_PRIORITY;\
type HDMI_ACR_CTS_32;\
type HDMI_ACR_N_32;\
type HDMI_ACR_CTS_44;\
type HDMI_ACR_N_44;\
type HDMI_ACR_CTS_48;\
type HDMI_ACR_N_48;\
type HDMI_CRC_EN;\
type HDMI_CRC_CONT_EN;\
type METADATA_HUBP_REQUESTOR_ID;\
type METADATA_ENGINE_EN;\
type METADATA_STREAM_TYPE;\
type HDMI_METADATA_PACKET_ENABLE;\
type HDMI_METADATA_PACKET_LINE_REFERENCE;\
type HDMI_METADATA_PACKET_MISSED;\
type HDMI_METADATA_PACKET_LINE
#define DCN401_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh)\
DCN401_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh),\
DCN401_HDMI_TB_ENC_MASK_SH_LIST(mask_sh)
#define DCN42_HDMI_TB_ENC_REG_FIELD_LIST(type) \
type HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL;\
type HDMI_STREAM_ENC_APG_CLOCK_EN
struct dcn401_hpo_frl_stream_encoder_shift {
DCN401_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
DCN42_HDMI_TB_ENC_REG_FIELD_LIST(uint8_t);
};
struct dcn401_hpo_frl_stream_encoder_mask {
DCN401_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
DCN42_HDMI_TB_ENC_REG_FIELD_LIST(uint32_t);
};
struct dcn401_hpo_frl_stream_encoder {
struct hpo_frl_stream_encoder base;
const struct dcn30_hpo_frl_stream_enc_registers *regs;
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift;
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask;
};
void hpo_enc401_enable(
struct hpo_frl_stream_encoder *enc,
int otg_inst);
void hpo_enc401_unblank(
struct hpo_frl_stream_encoder *enc,
int otg_inst);
void hpo_enc401_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state);
void hpo_enc401_blank(
struct hpo_frl_stream_encoder *enc);
void hpo_enc401_set_hdmi_stream_attribute(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
struct frl_borrow_params *borrow_params,
int odm_combine_num_segments);
void hpo_enc401_update_hdmi_info_packet(
struct dcn401_hpo_frl_stream_encoder *enc401,
uint32_t packet_index,
const struct dc_info_packet *info_packet);
void hpo_enc401_update_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc,
const struct encoder_info_frame *info_frame);
void hpo_enc401_hdmi_set_dsc_config(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *timing,
uint8_t *dsc_packed_pps);
void hpo_enc401_stop_hdmi_info_packets(
struct hpo_frl_stream_encoder *enc);
void hpo_enc401_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info);
void hpo_enc401_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info);
void hpo_enc401_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc);
void hpo_enc401_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute);
void enc401_stream_encoder_set_avmute(
struct hpo_frl_stream_encoder *enc,
bool enable);
void hpo_enc401_set_dynamic_metadata(
struct hpo_frl_stream_encoder *enc,
bool enable_dme,
uint32_t hubp_requestor_id,
enum dynamic_metadata_mode dmdata_mode);
void frl_get_audio_clock_info(
enum dc_color_depth color_depth,
uint32_t frl_character_clock_kHz,
struct frl_audio_clock_info *audio_clock_info);
void dcn401_hpo_frl_stream_encoder_construct(
struct dcn401_hpo_frl_stream_encoder *enc401,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct afmt *afmt,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask);
#endif
@@ -0,0 +1,206 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dc_bios_types.h"
#include "core_types.h"
#include "dcn42_hpo_frl_stream_encoder.h"
#include "dcn31/dcn31_apg.h"
#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "dcn_calc_math.h"
#include "dml/dcn30/dcn30_fpu.h"
#undef DC_LOGGER
#define DC_LOGGER \
enc401->base.ctx->logger
#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
#define DEBUG_FRL_CAP_CHK 1
#define REG(reg)\
(enc401->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
enc401->hpo_se_shift->field_name, enc401->hpo_se_mask->field_name
#define CTX \
enc401->base.ctx
#define VBI_LINE_0 0
void hpo_enc42_unblank(struct hpo_frl_stream_encoder *enc, int otg_inst)
{
(void)otg_inst;
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_HDMI_FRL("Entering [%s]\n", __func__);
/*make sure FIFO_VIDEO_STREAM_ACTIVE =1*/
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 0);
/* Reset */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 1);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
1, 10, 1000);
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_RESET, 0);
REG_WAIT(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, FIFO_RESET_DONE,
0, 10, 1000);
/* Enable HDMI Tribyte Encoder */
REG_UPDATE(HDMI_TB_ENC_CONTROL,
HDMI_TB_ENC_EN, 1);
/* Enable Clock Ramp Adjuster FIFO */
REG_UPDATE(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_ENABLE, 1);
DC_LOG_HDMI_FRL("Exiting [%s]\n", __func__);
}
void hpo_enc42_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
struct frl_audio_clock_info audio_clock_info = {0};
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* TODO: HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
/* HDMI_AUDIO_PACKET_CONTROL */
//REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
// HDMI_AUDIO_DELAY_EN, 1);
/* Setup audio in APG - program APG block associated with HPO */
ASSERT(enc->apg);
/* HDMI_ACR_PACKET_CONTROL */
REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0,
HDMI_ACR_AUDIO_PRIORITY, 0);
/* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
/* Program audio clock sample/regeneration parameters */
frl_get_audio_clock_info(crtc_info->color_depth,
crtc_info->frl_character_clock_kHz,
&audio_clock_info);
DC_LOG_HW_AUDIO(
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d \n", __func__, \
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
/* Same register definition, but using HDMI_TB_ENC register */
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
/* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
* Same register definition, but using HDMI_TB_ENC register*/
/* Video driver cannot know in advance which sample rate will
* be used by HD Audio driver
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
* programmed below in interrupt callback
*/
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
void hpo_enc42_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
REG_UPDATE_2(HDMI_STREAM_ENC_AUDIO_CONTROL,
HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst,
HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
hpo_enc42_setup_hdmi_audio(enc, audio_crtc_info);
ASSERT (enc->apg);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
}
void hpo_enc42_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc)
{
ASSERT(enc->apg);
if (enc->apg->funcs->disable_apg)
enc->apg->funcs->disable_apg(enc->apg);
}
void hpo_enc42_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
ASSERT (enc->apg);
if (mute)
enc->apg->funcs->disable_apg(enc->apg);
else
enc->apg->funcs->enable_apg(enc->apg);
}
static const struct hpo_frl_stream_encoder_funcs dcn42_str_enc_funcs = {
.hdmi_frl_enable = hpo_enc401_enable,
.hdmi_frl_unblank = hpo_enc42_unblank,
.hdmi_frl_blank = hpo_enc401_blank,
.hdmi_frl_set_stream_attribute = hpo_enc401_set_hdmi_stream_attribute,
.validate_hdmi_frl_output = hpo_enc3_validate_hdmi_frl_output,
.update_hdmi_info_packets = hpo_enc401_update_hdmi_info_packets,
.stop_hdmi_info_packets = hpo_enc401_stop_hdmi_info_packets,
.audio_mute_control = hpo_enc42_audio_mute_control,
.hdmi_audio_setup = hpo_enc42_hdmi_audio_setup,
.hdmi_audio_disable = hpo_enc42_hdmi_audio_disable,
.set_avmute = enc401_stream_encoder_set_avmute,
.read_state = hpo_enc401_read_state,
.set_dynamic_metadata = hpo_enc401_set_dynamic_metadata,
};
void dcn42_hpo_frl_stream_encoder_construct(
struct dcn42_hpo_frl_stream_encoder *enc42,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask)
{
enc42->base.funcs = &dcn42_str_enc_funcs;
enc42->base.ctx = ctx;
enc42->base.id = eng_id;
enc42->base.bp = bp;
enc42->base.vpg = vpg;
enc42->base.apg = apg;
enc42->regs = regs;
enc42->hpo_se_shift = hpo_se_shift;
enc42->hpo_se_mask = hpo_se_mask;
enc42->base.stream_enc_inst = vpg->inst;
}
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN42_H__
#define __DC_HPO_FRL_STREAM_ENCODER_DCN42_H__
#include "dcn30/dcn30_vpg.h"
#include "dcn31/dcn31_apg.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
#include "stream_encoder.h"
#include "dml/dml1_frl_cap_chk.h"
#define DCN42_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
DCN401_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh),\
SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, mask_sh)
struct dcn42_hpo_frl_stream_encoder {
struct hpo_frl_stream_encoder base;
const struct dcn30_hpo_frl_stream_enc_registers *regs;
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift;
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask;
};
void hpo_enc42_unblank(
struct hpo_frl_stream_encoder *enc,
int otg_inst);
void hpo_enc42_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info);
void hpo_enc42_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info);
void hpo_enc42_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc);
void hpo_enc42_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute);
void dcn42_hpo_frl_stream_encoder_construct(
struct dcn42_hpo_frl_stream_encoder *enc42,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask);
#endif /* __DC_HPO_STREAM_ENCODER_DCN42_H__ */
@@ -263,6 +263,7 @@ void opp1_set_dyn_expansion(
/*00 - 10-bit -> 12-bit dynamic expansion*/
/*01 - 8-bit -> 12-bit dynamic expansion*/
if (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
signal == SIGNAL_TYPE_HDMI_FRL ||
signal == SIGNAL_TYPE_DISPLAY_PORT ||
signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
signal == SIGNAL_TYPE_VIRTUAL) {
@@ -266,6 +266,7 @@
struct dcn_optc_registers {
OPTC_REG_VARIABLE_LIST_DCN;
uint32_t OTG_DRR_V_TOTAL_REACH_RANGE;
OPTC_REG_VARIABLE_LIST_DCN42;
};
@@ -595,7 +596,9 @@ struct dcn_optc_registers {
type MANUAL_FLOW_CONTROL;\
type MANUAL_FLOW_CONTROL_SEL;
#define V_TOTAL_REGS(type)
#define V_TOTAL_REGS(type) \
type OTG_DRR_V_TOTAL_REACH_LOWER_RANGE;\
type OTG_DRR_V_TOTAL_REACH_UPPER_RANGE;
#define TG_REG_FIELD_LIST(type) \
TG_REG_FIELD_LIST_DCN1_0(type)\
@@ -28,7 +28,9 @@
#include "dcn20/dcn20_optc.h"
#define V_TOTAL_REGS_DCN30_SRI(inst)
#define V_TOTAL_REGS_DCN30_SRI(inst) \
SRI(OTG_V_TOTAL_MID, OTG, inst),\
SRI(OTG_DRR_V_TOTAL_REACH_RANGE, OTG, inst),
#define OPTC_COMMON_REG_LIST_DCN3_BASE(inst) \
SRI(OTG_VSTARTUP_PARAM, OTG, inst),\
@@ -112,7 +114,9 @@
SR(DWB_SOURCE_SELECT),\
SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst)
#define DCN30_VTOTAL_REGS_SF(mask_sh)
#define DCN30_VTOTAL_REGS_SF(mask_sh)\
SF(OTG0_OTG_DRR_V_TOTAL_REACH_RANGE, OTG_DRR_V_TOTAL_REACH_LOWER_RANGE, mask_sh),\
SF(OTG0_OTG_DRR_V_TOTAL_REACH_RANGE, OTG_DRR_V_TOTAL_REACH_UPPER_RANGE, mask_sh),
#define OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh)\
SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\
@@ -320,6 +320,8 @@ void optc31_read_reg_state(struct timing_generator *optc, struct dcn_optc_reg_st
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
optc_reg_state->otg_drr_v_total_reach_range = REG_READ(OTG_DRR_V_TOTAL_REACH_RANGE);
optc_reg_state->optc_bytes_per_pixel = REG_READ(OPTC_BYTES_PER_PIXEL);
optc_reg_state->optc_data_format_control = REG_READ(OPTC_DATA_FORMAT_CONTROL);
optc_reg_state->optc_data_source_select = REG_READ(OPTC_DATA_SOURCE_SELECT);
@@ -378,6 +378,8 @@ void optc401_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest de
01 - OTG_CONTROL_OTG_OUT_MUX_1 : Reserved.
02 - OTG_CONTROL_OTG_OUT_MUX_2 : Connects to HPO.
*/
if (dest == OUT_MUX_HPO_FRL)
dest = OUT_MUX_HPO_DP;
REG_UPDATE(OTG_CONTROL, OTG_OUT_MUX, dest);
}