mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
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:
parent
02a342e3c4
commit
a0c898f28a
6 changed files with 268 additions and 1 deletions
|
@ -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)
|
||||
|
|
80
drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
Normal file
80
drivers/gpu/drm/amd/display/dc/dc_edid_parser.c
Normal 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;
|
||||
}
|
44
drivers/gpu/drm/amd/display/dc/dc_edid_parser.h
Normal file
44
drivers/gpu/drm/amd/display/dc/dc_edid_parser.h
Normal 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_ */
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue