drm/amd/display: Add Freesync HDMI support to DMCU

[Why]
Adding support for Freesync HDMI to DC and DMCU

[How]
Create DC interface and implementation on top of DMCU to support
parsing CEA blocks in DMCU.

Signed-off-by: Stylon Wang <stylon.wang@amd.com>
Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
Acked-by: Anson Jacob <Anson.Jacob@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Stylon Wang 2020-12-04 12:08:31 +08:00 committed by Alex Deucher
parent 02a342e3c4
commit a0c898f28a
6 changed files with 268 additions and 1 deletions

View file

@ -69,5 +69,7 @@ AMD_DISPLAY_FILES += $(AMD_DISPLAY_CORE)
AMD_DISPLAY_FILES += $(AMD_DM_REG_UPDATE)
DC_DMUB += dc_dmub_srv.o
DC_EDID += dc_edid_parser.o
AMD_DISPLAY_DMUB = $(addprefix $(AMDDALPATH)/dc/,$(DC_DMUB))
AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB)
AMD_DISPLAY_EDID = $(addprefix $(AMDDALPATH)/dc/,$(DC_EDID))
AMD_DISPLAY_FILES += $(AMD_DISPLAY_DMUB) $(AMD_DISPLAY_EDID)

View file

@ -0,0 +1,80 @@
/*
* Copyright 2021 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 "dce/dce_dmcu.h"
#include "dc_edid_parser.h"
bool dc_edid_parser_send_cea(struct dc *dc,
int offset,
int total_length,
uint8_t *data,
int length)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->send_edid_cea) {
return dmcu->funcs->send_edid_cea(dmcu,
offset,
total_length,
data,
length);
}
return false;
}
bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->recv_edid_cea_ack) {
return dmcu->funcs->recv_edid_cea_ack(dmcu, offset);
}
return false;
}
bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
int *version,
int *min_frame_rate,
int *max_frame_rate)
{
struct dmcu *dmcu = dc->res_pool->dmcu;
if (dmcu &&
dmcu->funcs->is_dmcu_initialized(dmcu) &&
dmcu->funcs->recv_amd_vsdb) {
return dmcu->funcs->recv_amd_vsdb(dmcu,
version,
min_frame_rate,
max_frame_rate);
}
return false;
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2021 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_EDID_PARSER_H_
#define _DC_EDID_PARSER_H_
#include "core_types.h"
bool dc_edid_parser_send_cea(struct dc *dc,
int offset,
int total_length,
uint8_t *data,
int length);
bool dc_edid_parser_recv_cea_ack(struct dc *dc, int *offset);
bool dc_edid_parser_recv_amd_vsdb(struct dc *dc,
int *version,
int *min_frame_rate,
int *max_frame_rate);
#endif /* _DC_EDID_PARSER_H_ */

View file

@ -57,6 +57,9 @@
#define MCP_SYNC_PHY_LOCK 0x90
#define MCP_SYNC_PHY_UNLOCK 0x91
#define MCP_BL_SET_PWM_FRAC 0x6A /* Enable or disable Fractional PWM */
#define MCP_SEND_EDID_CEA 0xA0
#define EDID_CEA_CMD_ACK 1
#define EDID_CEA_CMD_NACK 2
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
// PSP FW version
@ -811,6 +814,120 @@ static bool dcn20_unlock_phy(struct dmcu *dmcu)
return true;
}
static bool dcn10_send_edid_cea(struct dmcu *dmcu,
int offset,
int total_length,
uint8_t *data,
int length)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t header, data1, data2;
/* If microcontroller is not running, do nothing */
if (dmcu->dmcu_state != DMCU_RUNNING)
return false;
if (length > 8 || length <= 0)
return false;
header = ((uint32_t)offset & 0xFFFF) << 16 | (total_length & 0xFFFF);
data1 = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) |
(((uint32_t)data[2]) << 8) | ((uint32_t)data[3]);
data2 = (((uint32_t)data[4]) << 24) | (((uint32_t)data[5]) << 16) |
(((uint32_t)data[6]) << 8) | ((uint32_t)data[7]);
/* waitDMCUReadyForCmd */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
/* setDMCUParam_Cmd */
REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SEND_EDID_CEA);
REG_WRITE(MASTER_COMM_DATA_REG1, header);
REG_WRITE(MASTER_COMM_DATA_REG2, data1);
REG_WRITE(MASTER_COMM_DATA_REG3, data2);
/* notifyDMCUMsg */
REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
/* waitDMCUReadyForCmd */
REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000);
return true;
}
static bool dcn10_get_scp_results(struct dmcu *dmcu,
uint32_t *cmd,
uint32_t *data1,
uint32_t *data2,
uint32_t *data3)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
/* If microcontroller is not running, do nothing */
if (dmcu->dmcu_state != DMCU_RUNNING)
return false;
*cmd = REG_READ(SLAVE_COMM_CMD_REG);
*data1 = REG_READ(SLAVE_COMM_DATA_REG1);
*data2 = REG_READ(SLAVE_COMM_DATA_REG2);
*data3 = REG_READ(SLAVE_COMM_DATA_REG3);
/* clear SCP interrupt */
REG_UPDATE(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, 0);
return true;
}
static bool dcn10_recv_amd_vsdb(struct dmcu *dmcu,
int *version,
int *min_frame_rate,
int *max_frame_rate)
{
uint32_t data[4];
int cmd, ack, len;
if (!dcn10_get_scp_results(dmcu, &data[0], &data[1], &data[2], &data[3]))
return false;
cmd = data[0] & 0x3FF;
len = (data[0] >> 10) & 0x3F;
ack = data[1];
if (cmd != MCP_SEND_EDID_CEA || ack != EDID_CEA_CMD_ACK || len != 12)
return false;
if ((data[2] & 0xFF)) {
*version = (data[2] >> 8) & 0xFF;
*min_frame_rate = (data[3] >> 16) & 0xFFFF;
*max_frame_rate = data[3] & 0xFFFF;
return true;
}
return false;
}
static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
{
uint32_t data[4];
int cmd, ack;
if (!dcn10_get_scp_results(dmcu,
&data[0], &data[1], &data[2], &data[3]))
return false;
cmd = data[0] & 0x3FF;
ack = data[1];
if (cmd != MCP_SEND_EDID_CEA)
return false;
if (ack == EDID_CEA_CMD_ACK)
return true;
*offset = data[2]; /* nack */
return false;
}
#endif //(CONFIG_DRM_AMD_DC_DCN)
static const struct dmcu_funcs dce_funcs = {
@ -833,6 +950,9 @@ static const struct dmcu_funcs dcn10_funcs = {
.get_psr_state = dcn10_get_dmcu_psr_state,
.set_psr_wait_loop = dcn10_psr_wait_loop,
.get_psr_wait_loop = dcn10_get_psr_wait_loop,
.send_edid_cea = dcn10_send_edid_cea,
.recv_amd_vsdb = dcn10_recv_amd_vsdb,
.recv_edid_cea_ack = dcn10_recv_edid_cea_ack,
.is_dmcu_initialized = dcn10_is_dmcu_initialized
};

View file

@ -40,6 +40,10 @@
SR(MASTER_COMM_DATA_REG3), \
SR(MASTER_COMM_CMD_REG), \
SR(MASTER_COMM_CNTL_REG), \
SR(SLAVE_COMM_DATA_REG1), \
SR(SLAVE_COMM_DATA_REG2), \
SR(SLAVE_COMM_DATA_REG3), \
SR(SLAVE_COMM_CMD_REG), \
SR(DMCU_IRAM_RD_CTRL), \
SR(DMCU_IRAM_RD_DATA), \
SR(DMCU_INTERRUPT_TO_UC_EN_MASK), \
@ -112,6 +116,7 @@
DMCU_SF(MASTER_COMM_CMD_REG, \
MASTER_COMM_CMD_REG_BYTE0, mask_sh), \
DMCU_SF(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, mask_sh), \
DMCU_SF(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, mask_sh), \
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
STATIC_SCREEN1_INT_TO_UC_EN, mask_sh), \
DMCU_SF(DMCU_INTERRUPT_TO_UC_EN_MASK, \
@ -179,6 +184,7 @@
type UC_IN_RESET; \
type MASTER_COMM_CMD_REG_BYTE0; \
type MASTER_COMM_INTERRUPT; \
type SLAVE_COMM_INTERRUPT; \
type DPHY_RX_FAST_TRAINING_CAPABLE; \
type DPHY_LOAD_BS_COUNT; \
type STATIC_SCREEN1_INT_TO_UC_EN; \
@ -211,6 +217,11 @@ struct dce_dmcu_registers {
uint32_t MASTER_COMM_DATA_REG3;
uint32_t MASTER_COMM_CMD_REG;
uint32_t MASTER_COMM_CNTL_REG;
uint32_t SLAVE_COMM_DATA_REG1;
uint32_t SLAVE_COMM_DATA_REG2;
uint32_t SLAVE_COMM_DATA_REG3;
uint32_t SLAVE_COMM_CMD_REG;
uint32_t SLAVE_COMM_CNTL_REG;
uint32_t DMCU_IRAM_RD_CTRL;
uint32_t DMCU_IRAM_RD_DATA;
uint32_t DMCU_INTERRUPT_TO_UC_EN_MASK;

View file

@ -74,6 +74,16 @@ struct dmcu_funcs {
bool (*is_dmcu_initialized)(struct dmcu *dmcu);
bool (*lock_phy)(struct dmcu *dmcu);
bool (*unlock_phy)(struct dmcu *dmcu);
bool (*send_edid_cea)(struct dmcu *dmcu,
int offset,
int total_length,
uint8_t *data,
int length);
bool (*recv_amd_vsdb)(struct dmcu *dmcu,
int *version,
int *min_frame_rate,
int *max_frame_rate);
bool (*recv_edid_cea_ack)(struct dmcu *dmcu, int *offset);
};
#endif