Commit a0c898f2 authored by Stylon Wang's avatar Stylon Wang Committed by Alex Deucher
Browse files

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: default avatarStylon Wang <stylon.wang@amd.com>
Reviewed-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Acked-by: default avatarAnson Jacob <Anson.Jacob@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 02a342e3
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
/*
 * 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_ */
+120 −0
Original line number Diff line number Diff line
@@ -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
};

+11 −0
Original line number Diff line number Diff line
@@ -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;
Loading