[PATCH 16/29] drm/amd/dal: Add surface HW programming

Harry Wentland harry.wentland at amd.com
Thu Feb 11 17:19:56 UTC 2016


Adds watermark, DMIF, and surface programming.

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
 .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c   | 965 +++++++++++++++++++++
 .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h   | 117 +++
 2 files changed, 1082 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
new file mode 100644
index 000000000000..3a928e63e647
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
@@ -0,0 +1,965 @@
+/*
+ * Copyright 2012-15 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 "dm_services.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+/* TODO: this needs to be looked at, used by Stella's workaround*/
+#include "gmc/gmc_8_2_d.h"
+#include "gmc/gmc_8_2_sh_mask.h"
+
+#include "include/logger_interface.h"
+#include "adapter_service_interface.h"
+#include "inc/bandwidth_calcs.h"
+
+#include "dce110_mem_input.h"
+
+#define MAX_WATERMARK 0xFFFF
+#define SAFE_NBP_MARK 0x7FFF
+
+#define DCP_REG(reg) (reg + mem_input110->offsets.dcp)
+#define DMIF_REG(reg) (reg + mem_input110->offsets.dmif)
+#define PIPE_REG(reg) (reg + mem_input110->offsets.pipe)
+
+static void set_flip_control(
+	struct dce110_mem_input *mem_input110,
+	bool immediate)
+{
+	uint32_t value = 0;
+
+	value = dm_read_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_FLIP_CONTROL));
+	set_reg_field_value(value, 0,
+				GRPH_FLIP_CONTROL,
+				GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
+	set_reg_field_value(value, 0,
+				GRPH_FLIP_CONTROL,
+				GRPH_SURFACE_UPDATE_H_RETRACE_EN);
+	if (immediate == true)
+		set_reg_field_value(value, 1,
+			GRPH_FLIP_CONTROL,
+			GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
+
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_FLIP_CONTROL),
+		value);
+}
+
+static void program_sec_addr(
+	struct dce110_mem_input *mem_input110,
+	PHYSICAL_ADDRESS_LOC address)
+{
+	uint32_t value = 0;
+	uint32_t temp = 0;
+	/*high register MUST be programmed first*/
+	temp = address.high_part &
+GRPH_SECONDARY_SURFACE_ADDRESS_HIGH__GRPH_SECONDARY_SURFACE_ADDRESS_HIGH_MASK;
+
+	set_reg_field_value(value, temp,
+		GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+		GRPH_SECONDARY_SURFACE_ADDRESS_HIGH);
+
+	dm_write_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH),
+			value);
+
+	temp = 0;
+	value = 0;
+	temp = address.low_part >>
+	GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS__SHIFT;
+
+	set_reg_field_value(value, temp,
+		GRPH_SECONDARY_SURFACE_ADDRESS,
+		GRPH_SECONDARY_SURFACE_ADDRESS);
+
+	dm_write_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS),
+			value);
+}
+
+static void program_pri_addr(
+	struct dce110_mem_input *mem_input110,
+	PHYSICAL_ADDRESS_LOC address)
+{
+	uint32_t value = 0;
+	uint32_t temp = 0;
+
+	/*high register MUST be programmed first*/
+	temp = address.high_part &
+GRPH_PRIMARY_SURFACE_ADDRESS_HIGH__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_MASK;
+
+	set_reg_field_value(value, temp,
+		GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+		GRPH_PRIMARY_SURFACE_ADDRESS_HIGH);
+
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH),
+		value);
+
+	temp = 0;
+	value = 0;
+	temp = address.low_part >>
+	GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS__SHIFT;
+
+	set_reg_field_value(value, temp,
+		GRPH_PRIMARY_SURFACE_ADDRESS,
+		GRPH_PRIMARY_SURFACE_ADDRESS);
+
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS),
+		value);
+}
+
+static void program_addr(
+	struct dce110_mem_input *mem_input110,
+	const struct dc_plane_address *addr)
+{
+	switch (addr->type) {
+	case PLN_ADDR_TYPE_GRAPHICS:
+		program_pri_addr(
+			mem_input110,
+			addr->grph.addr);
+		break;
+	case PLN_ADDR_TYPE_GRPH_STEREO:
+		program_pri_addr(
+			mem_input110,
+			addr->grph_stereo.left_addr);
+		program_sec_addr(
+			mem_input110,
+			addr->grph_stereo.right_addr);
+		break;
+	case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
+	default:
+		/* not supported */
+		BREAK_TO_DEBUGGER();
+	}
+}
+
+static void enable(struct dce110_mem_input *mem_input110)
+{
+	uint32_t value = 0;
+
+	value = dm_read_reg(mem_input110->base.ctx, DCP_REG(mmGRPH_ENABLE));
+	set_reg_field_value(value, 1, GRPH_ENABLE, GRPH_ENABLE);
+	dm_write_reg(mem_input110->base.ctx,
+		DCP_REG(mmGRPH_ENABLE),
+		value);
+}
+
+static void program_tiling(
+	struct dce110_mem_input *mem_input110,
+	const struct dc_tiling_info *info,
+	const enum surface_pixel_format pixel_format)
+{
+	uint32_t value = 0;
+
+	value = dm_read_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_CONTROL));
+
+	set_reg_field_value(value, info->num_banks,
+		GRPH_CONTROL, GRPH_NUM_BANKS);
+
+	set_reg_field_value(value, info->bank_width,
+		GRPH_CONTROL, GRPH_BANK_WIDTH);
+
+	set_reg_field_value(value, info->bank_height,
+		GRPH_CONTROL, GRPH_BANK_HEIGHT);
+
+	set_reg_field_value(value, info->tile_aspect,
+		GRPH_CONTROL, GRPH_MACRO_TILE_ASPECT);
+
+	set_reg_field_value(value, info->tile_split,
+		GRPH_CONTROL, GRPH_TILE_SPLIT);
+
+	set_reg_field_value(value, info->tile_mode,
+		GRPH_CONTROL, GRPH_MICRO_TILE_MODE);
+
+	set_reg_field_value(value, info->pipe_config,
+		GRPH_CONTROL, GRPH_PIPE_CONFIG);
+
+	set_reg_field_value(value, info->array_mode,
+		GRPH_CONTROL, GRPH_ARRAY_MODE);
+
+	set_reg_field_value(value, 1,
+		GRPH_CONTROL, GRPH_COLOR_EXPANSION_MODE);
+
+	set_reg_field_value(value, 0,
+		GRPH_CONTROL, GRPH_Z);
+
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_CONTROL),
+		value);
+}
+
+static void program_size_and_rotation(
+	struct dce110_mem_input *mem_input110,
+	enum dc_rotation_angle rotation,
+	const union plane_size *plane_size)
+{
+	uint32_t value = 0;
+	union plane_size local_size = *plane_size;
+
+	if (rotation == ROTATION_ANGLE_90 ||
+		rotation == ROTATION_ANGLE_270) {
+
+		uint32_t swap;
+
+		swap = local_size.grph.surface_size.x;
+		local_size.grph.surface_size.x =
+			local_size.grph.surface_size.y;
+		local_size.grph.surface_size.y  = swap;
+
+		swap = local_size.grph.surface_size.width;
+		local_size.grph.surface_size.width =
+			local_size.grph.surface_size.height;
+		local_size.grph.surface_size.height = swap;
+	}
+
+	set_reg_field_value(value, local_size.grph.surface_size.x,
+			GRPH_X_START, GRPH_X_START);
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_X_START),
+		value);
+
+	value = 0;
+	set_reg_field_value(value, local_size.grph.surface_size.y,
+			GRPH_Y_START, GRPH_Y_START);
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_Y_START),
+		value);
+
+	value = 0;
+	set_reg_field_value(value, local_size.grph.surface_size.width,
+			GRPH_X_END, GRPH_X_END);
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_X_END),
+		value);
+
+	value = 0;
+	set_reg_field_value(value, local_size.grph.surface_size.height,
+			GRPH_Y_END, GRPH_Y_END);
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_Y_END),
+		value);
+
+	value = 0;
+	set_reg_field_value(value, local_size.grph.surface_pitch,
+			GRPH_PITCH, GRPH_PITCH);
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmGRPH_PITCH),
+		value);
+
+
+	value = 0;
+	switch (rotation) {
+	case ROTATION_ANGLE_90:
+		set_reg_field_value(value, 3,
+			HW_ROTATION, GRPH_ROTATION_ANGLE);
+		break;
+	case ROTATION_ANGLE_180:
+		set_reg_field_value(value, 2,
+			HW_ROTATION, GRPH_ROTATION_ANGLE);
+		break;
+	case ROTATION_ANGLE_270:
+		set_reg_field_value(value, 1,
+			HW_ROTATION, GRPH_ROTATION_ANGLE);
+		break;
+	default:
+		set_reg_field_value(value, 0,
+			HW_ROTATION, GRPH_ROTATION_ANGLE);
+		break;
+	}
+	dm_write_reg(
+		mem_input110->base.ctx,
+		DCP_REG(mmHW_ROTATION),
+		value);
+}
+
+static void program_pixel_format(
+	struct dce110_mem_input *mem_input110,
+	enum surface_pixel_format format)
+{
+	if (format >= SURFACE_PIXEL_FORMAT_GRPH_BEGIN &&
+		format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+		uint32_t value = 0;
+
+		/* handle colour twizzle formats, swapping R and B */
+		if (format == SURFACE_PIXEL_FORMAT_GRPH_BGRA8888 ||
+			format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 ||
+			format ==
+			SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS ||
+			format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
+			set_reg_field_value(
+				value, 2, GRPH_SWAP_CNTL, GRPH_RED_CROSSBAR);
+			set_reg_field_value(
+				value, 2, GRPH_SWAP_CNTL, GRPH_BLUE_CROSSBAR);
+		}
+
+		dm_write_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_SWAP_CNTL),
+			value);
+
+
+		value =	dm_read_reg(
+				mem_input110->base.ctx,
+				DCP_REG(mmGRPH_CONTROL));
+
+		switch (format) {
+		case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
+			set_reg_field_value(
+				value, 0, GRPH_CONTROL, GRPH_DEPTH);
+			set_reg_field_value(
+				value, 0, GRPH_CONTROL, GRPH_FORMAT);
+			break;
+		case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+			set_reg_field_value(
+				value, 1, GRPH_CONTROL, GRPH_DEPTH);
+			set_reg_field_value(
+				value, 1, GRPH_CONTROL, GRPH_FORMAT);
+			break;
+		case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
+		case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
+			set_reg_field_value(
+				value, 2, GRPH_CONTROL, GRPH_DEPTH);
+			set_reg_field_value(
+				value, 0, GRPH_CONTROL, GRPH_FORMAT);
+			break;
+		case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
+		case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
+		case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
+			set_reg_field_value(
+				value, 2, GRPH_CONTROL, GRPH_DEPTH);
+			set_reg_field_value(
+				value, 1, GRPH_CONTROL, GRPH_FORMAT);
+			break;
+		case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+		case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+			set_reg_field_value(
+				value, 3, GRPH_CONTROL, GRPH_DEPTH);
+			set_reg_field_value(
+				value, 0, GRPH_CONTROL, GRPH_FORMAT);
+			break;
+		default:
+			break;
+		}
+		dm_write_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmGRPH_CONTROL),
+			value);
+
+		/*TODO [hwentlan] MOVE THIS TO CONTROLLER GAMMA!!!!!*/
+		value = dm_read_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmPRESCALE_GRPH_CONTROL));
+
+		if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
+			set_reg_field_value(
+				value, 1, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_SELECT);
+			set_reg_field_value(
+				value, 1, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_R_SIGN);
+			set_reg_field_value(
+				value, 1, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_G_SIGN);
+			set_reg_field_value(
+				value, 1, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_B_SIGN);
+		} else {
+			set_reg_field_value(
+				value, 0, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_SELECT);
+			set_reg_field_value(
+				value, 0, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_R_SIGN);
+			set_reg_field_value(
+				value, 0, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_G_SIGN);
+			set_reg_field_value(
+				value, 0, PRESCALE_GRPH_CONTROL,
+				GRPH_PRESCALE_B_SIGN);
+		}
+		dm_write_reg(
+			mem_input110->base.ctx,
+			DCP_REG(mmPRESCALE_GRPH_CONTROL),
+			value);
+	}
+}
+
+static void wait_for_no_surface_update_pending(
+				struct dce110_mem_input *mem_input110)
+{
+	uint32_t value;
+
+	do  {
+		value = dm_read_reg(mem_input110->base.ctx,
+				DCP_REG(mmGRPH_UPDATE));
+
+	} while (get_reg_field_value(value, GRPH_UPDATE,
+			GRPH_SURFACE_UPDATE_PENDING));
+}
+
+bool dce110_mem_input_program_surface_flip_and_addr(
+	struct mem_input *mem_input,
+	const struct dc_plane_address *address,
+	bool flip_immediate)
+{
+	struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+
+	set_flip_control(mem_input110, flip_immediate);
+	program_addr(mem_input110,
+		address);
+
+	if (flip_immediate)
+		wait_for_no_surface_update_pending(mem_input110);
+
+	return true;
+}
+
+bool dce110_mem_input_program_surface_config(
+	struct mem_input *mem_input,
+	enum surface_pixel_format format,
+	struct dc_tiling_info *tiling_info,
+	union plane_size *plane_size,
+	enum dc_rotation_angle rotation)
+{
+	struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+
+	enable(mem_input110);
+	program_tiling(mem_input110, tiling_info, format);
+	program_size_and_rotation(mem_input110, rotation, plane_size);
+	program_pixel_format(mem_input110, format);
+
+	return true;
+}
+
+static void program_urgency_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks_low,
+	uint32_t total_dest_line_time_ns)
+{
+	/* register value */
+	uint32_t urgency_cntl = 0;
+	uint32_t wm_mask_cntl = 0;
+
+	uint32_t urgency_addr = offset + mmDPG_PIPE_URGENCY_CONTROL;
+	uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+	/*Write mask to enable reading/writing of watermark set A*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			1,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(
+		urgency_cntl,
+		marks_low.a_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(
+		urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+
+
+	/*Write mask to enable reading/writing of watermark set B*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+			2,
+			DPG_WATERMARK_MASK_CONTROL,
+			URGENCY_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+	set_reg_field_value(urgency_cntl,
+		marks_low.b_mark,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_LOW_WATERMARK);
+
+	set_reg_field_value(urgency_cntl,
+		total_dest_line_time_ns,
+		DPG_PIPE_URGENCY_CONTROL,
+		URGENCY_HIGH_WATERMARK);
+	dm_write_reg(ctx, urgency_addr, urgency_cntl);
+}
+
+static void program_stutter_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks)
+{
+	/* register value */
+	uint32_t stutter_cntl = 0;
+	uint32_t wm_mask_cntl = 0;
+
+	uint32_t stutter_addr = offset + mmDPG_PIPE_STUTTER_CONTROL;
+	uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+	/*Write mask to enable reading/writing of watermark set A*/
+
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		1,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set A*/
+	set_reg_field_value(stutter_cntl,
+		marks.a_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+
+	/*Write mask to enable reading/writing of watermark set B*/
+	wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+	set_reg_field_value(wm_mask_cntl,
+		2,
+		DPG_WATERMARK_MASK_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+	dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+	stutter_cntl = dm_read_reg(ctx, stutter_addr);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_ENABLE);
+	set_reg_field_value(stutter_cntl,
+		1,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_IGNORE_FBC);
+
+	/*Write watermark set B*/
+	set_reg_field_value(stutter_cntl,
+		marks.b_mark,
+		DPG_PIPE_STUTTER_CONTROL,
+		STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+	dm_write_reg(ctx, stutter_addr, stutter_cntl);
+}
+
+static void program_nbp_watermark(
+	const struct dc_context *ctx,
+	const uint32_t offset,
+	struct bw_watermarks marks)
+{
+	uint32_t value;
+	uint32_t addr;
+	/* Write mask to enable reading/writing of watermark set A */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set A */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.a_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write mask to enable reading/writing of watermark set B */
+	addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		2,
+		DPG_WATERMARK_MASK_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK_MASK);
+	dm_write_reg(ctx, addr, value);
+
+	addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_ENABLE);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+	set_reg_field_value(
+		value,
+		1,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+	dm_write_reg(ctx, addr, value);
+
+	/* Write watermark set B */
+	value = dm_read_reg(ctx, addr);
+	set_reg_field_value(
+		value,
+		marks.b_mark,
+		DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+		NB_PSTATE_CHANGE_WATERMARK);
+	dm_write_reg(ctx, addr, value);
+}
+
+void dce110_mem_input_program_safe_display_marks(struct mem_input *mi)
+{
+	struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
+	struct bw_watermarks max_marks = { MAX_WATERMARK, MAX_WATERMARK };
+	struct bw_watermarks nbp_marks = { SAFE_NBP_MARK, SAFE_NBP_MARK };
+
+	program_urgency_watermark(
+		mi->ctx, bm_dce110->offsets.dmif, max_marks, MAX_WATERMARK);
+	program_stutter_watermark(mi->ctx, bm_dce110->offsets.dmif, max_marks);
+	program_nbp_watermark(mi->ctx, bm_dce110->offsets.dmif, nbp_marks);
+}
+
+void dce110_mem_input_program_display_marks(
+	struct mem_input *mem_input,
+	struct bw_watermarks nbp,
+	struct bw_watermarks stutter,
+	struct bw_watermarks urgent,
+	uint32_t h_total,
+	uint32_t pixel_clk_in_khz,
+	uint32_t pstate_blackout_duration_ns)
+{
+	struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mem_input);
+	uint32_t total_dest_line_time_ns = 1000000UL * h_total
+		/ pixel_clk_in_khz + pstate_blackout_duration_ns;
+
+	program_urgency_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		urgent,
+		total_dest_line_time_ns);
+	program_nbp_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		nbp);
+	program_stutter_watermark(
+		mem_input->ctx,
+		bm_dce110->offsets.dmif,
+		stutter);
+}
+
+static uint32_t get_dmif_switch_time_us(struct dc_crtc_timing *timing)
+{
+	uint32_t frame_time;
+	uint32_t pixels_per_second;
+	uint32_t pixels_per_frame;
+	uint32_t refresh_rate;
+	const uint32_t us_in_sec = 1000000;
+	const uint32_t min_single_frame_time_us = 30000;
+	/*return double of frame time*/
+	const uint32_t single_frame_time_multiplier = 2;
+
+	if (timing == NULL)
+		return single_frame_time_multiplier * min_single_frame_time_us;
+
+	/*TODO: should we use pixel format normalized pixel clock here?*/
+	pixels_per_second = timing->pix_clk_khz * 1000;
+	pixels_per_frame = timing->h_total * timing->v_total;
+
+	if (!pixels_per_second || !pixels_per_frame) {
+		/* avoid division by zero */
+		ASSERT(pixels_per_frame);
+		ASSERT(pixels_per_second);
+		return single_frame_time_multiplier * min_single_frame_time_us;
+	}
+
+	refresh_rate = pixels_per_second / pixels_per_frame;
+
+	if (!refresh_rate) {
+		/* avoid division by zero*/
+		ASSERT(refresh_rate);
+		return single_frame_time_multiplier * min_single_frame_time_us;
+	}
+
+	frame_time = us_in_sec / refresh_rate;
+
+	if (frame_time < min_single_frame_time_us)
+		frame_time = min_single_frame_time_us;
+
+	frame_time *= single_frame_time_multiplier;
+
+	return frame_time;
+}
+
+void dce110_mem_input_allocate_dmif_buffer(
+		struct mem_input *mi,
+		struct dc_crtc_timing *timing,
+		uint32_t paths_num)
+{
+	const uint32_t retry_delay = 10;
+	uint32_t retry_count = get_dmif_switch_time_us(timing) / retry_delay;
+
+	struct dce110_mem_input *bm110 = TO_DCE110_MEM_INPUT(mi);
+	uint32_t addr = bm110->offsets.pipe + mmPIPE0_DMIF_BUFFER_CONTROL;
+	uint32_t value;
+	uint32_t field;
+	uint32_t pix_dur;
+
+	if (bm110->supported_stutter_mode
+			& STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)
+		goto register_underflow_int;
+
+	/*Allocate DMIF buffer*/
+	value = dm_read_reg(mi->ctx, addr);
+	field = get_reg_field_value(
+		value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
+	if (field == 2)
+		goto register_underflow_int;
+
+	set_reg_field_value(
+			value,
+			2,
+			PIPE0_DMIF_BUFFER_CONTROL,
+			DMIF_BUFFERS_ALLOCATED);
+
+	dm_write_reg(mi->ctx, addr, value);
+
+	do {
+		value = dm_read_reg(mi->ctx, addr);
+		field = get_reg_field_value(
+			value,
+			PIPE0_DMIF_BUFFER_CONTROL,
+			DMIF_BUFFERS_ALLOCATION_COMPLETED);
+
+		if (field)
+			break;
+
+		dm_delay_in_microseconds(mi->ctx, retry_delay);
+		retry_count--;
+
+	} while (retry_count > 0);
+
+	if (field == 0)
+		dal_logger_write(mi->ctx->logger,
+				LOG_MAJOR_ERROR,
+				LOG_MINOR_COMPONENT_GPU,
+				"%s: DMIF allocation failed",
+				__func__);
+
+
+	if (timing->pix_clk_khz != 0) {
+		addr = mmDPG_PIPE_ARBITRATION_CONTROL1 + bm110->offsets.dmif;
+		value = dm_read_reg(mi->ctx, addr);
+		pix_dur = 1000000000ULL / timing->pix_clk_khz;
+
+		set_reg_field_value(
+			value,
+			pix_dur,
+			DPG_PIPE_ARBITRATION_CONTROL1,
+			PIXEL_DURATION);
+
+		dm_write_reg(mi->ctx, addr, value);
+	}
+
+	/*
+	 * Stella Wong proposed the following change
+	 *
+	 * Value of mcHubRdReqDmifLimit.ENABLE:
+	 * 00 - disable DMIF rdreq limit
+	 * 01 - enable DMIF rdreq limit, disabled by DMIF stall = 1 || urg != 0
+	 * 02 - enable DMIF rdreq limit, disable by DMIF stall = 1
+	 * 03 - force enable DMIF rdreq limit, ignore DMIF stall / urgent
+	 */
+	if (!IS_FPGA_MAXIMUS_DC(mi->ctx->dce_environment)) {
+		addr = mmMC_HUB_RDREQ_DMIF_LIMIT;
+		value = dm_read_reg(mi->ctx, addr);
+
+		if (paths_num > 1)
+			set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
+		else
+			set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
+		dm_write_reg(mi->ctx, addr, value);
+	}
+
+register_underflow_int:
+	/*todo*/;
+	/*register_interrupt(bm110, irq_source, ctrl_id);*/
+}
+
+static void deallocate_dmif_buffer_helper(
+				struct dc_context *ctx, uint32_t offset)
+{
+	uint32_t value;
+	uint32_t count = 0xBB8; /* max retry count */
+
+	value = dm_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
+
+	if (!get_reg_field_value(
+		value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED))
+		return;
+
+	set_reg_field_value(
+		value, 0, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
+
+	dm_write_reg(
+		ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset, value);
+
+	do {
+		value = dm_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
+		dm_delay_in_microseconds(ctx, 10);
+		count--;
+	} while (count > 0 &&
+		!get_reg_field_value(
+			value,
+			PIPE0_DMIF_BUFFER_CONTROL,
+			DMIF_BUFFERS_ALLOCATION_COMPLETED));
+}
+
+void dce110_mem_input_deallocate_dmif_buffer(
+	struct mem_input *mi, uint32_t paths_num)
+{
+	struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
+	uint32_t value;
+
+	if (!(bm_dce110->supported_stutter_mode &
+		STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)) {
+
+		/* De-allocate DMIF buffer first */
+		if (mmPIPE0_DMIF_BUFFER_CONTROL + bm_dce110->offsets.pipe != 0)
+			deallocate_dmif_buffer_helper(
+					mi->ctx, bm_dce110->offsets.pipe);
+	}
+
+	/* TODO: unregister underflow interrupt
+	unregisterInterrupt();
+	*/
+
+	/* Value of mcHubRdReqDmifLimit.ENABLE.
+	 * 00 - disable dmif rdreq limit
+	 * 01 - enable dmif rdreq limit, disable by dmif stall=1||urg!=0
+	 * 02 - enable dmif rdreq limit, disable by dmif stall=1
+	 * 03 - force enable dmif rdreq limit, ignore dmif stall/urgent
+	 * Stella Wong proposed this change. */
+	if (!IS_FPGA_MAXIMUS_DC(mi->ctx->dce_environment)) {
+		value = dm_read_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT);
+		if (paths_num > 1)
+			set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
+		else
+			set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
+
+		dm_write_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT, value);
+	}
+}
+
+static struct mem_input_funcs dce110_mem_input_funcs = {
+	.mem_input_program_safe_display_marks =
+			dce110_mem_input_program_safe_display_marks,
+	.mem_input_program_display_marks =
+			dce110_mem_input_program_display_marks,
+	.mem_input_allocate_dmif_buffer = dce110_mem_input_allocate_dmif_buffer,
+	.mem_input_deallocate_dmif_buffer =
+			dce110_mem_input_deallocate_dmif_buffer,
+	.mem_input_program_surface_flip_and_addr =
+			dce110_mem_input_program_surface_flip_and_addr,
+	.mem_input_program_surface_config =
+			dce110_mem_input_program_surface_config,
+};
+/*****************************************/
+/* Constructor, Destructor               */
+/*****************************************/
+
+bool dce110_mem_input_construct(
+	struct dce110_mem_input *mem_input110,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offsets)
+{
+	mem_input110->base.funcs = &dce110_mem_input_funcs;
+	mem_input110->base.ctx = ctx;
+
+	mem_input110->base.inst = inst;
+
+	mem_input110->offsets = *offsets;
+
+	mem_input110->supported_stutter_mode = 0;
+	dal_adapter_service_get_feature_value(FEATURE_STUTTER_MODE,
+			&(mem_input110->supported_stutter_mode),
+			sizeof(mem_input110->supported_stutter_mode));
+
+	return true;
+}
+
+void dce110_mem_input_destroy(struct mem_input **mem_input)
+{
+	dm_free((*mem_input)->ctx, TO_DCE110_MEM_INPUT(*mem_input));
+	*mem_input = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
new file mode 100644
index 000000000000..5a4e5fe33a79
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
@@ -0,0 +1,117 @@
+/* Copyright 2012-15 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_MEM_INPUT_DCE110_H__
+#define __DC_MEM_INPUT_DCE110_H__
+
+#include "inc/mem_input.h"
+
+#define TO_DCE110_MEM_INPUT(mi)\
+	container_of(mi, struct dce110_mem_input, base)
+
+struct dce110_mem_input_reg_offsets {
+	uint32_t dcp;
+	uint32_t dmif;
+	uint32_t pipe;
+};
+
+struct dce110_mem_input {
+	struct mem_input base;
+	struct dce110_mem_input_reg_offsets offsets;
+	uint32_t supported_stutter_mode;
+};
+
+bool dce110_mem_input_construct(
+	struct dce110_mem_input *mem_input110,
+	struct dc_context *ctx,
+	uint32_t inst,
+	const struct dce110_mem_input_reg_offsets *offsets);
+
+/*
+ * dce110_mem_input_program_display_marks
+ *
+ * This function will program nbp stutter and urgency watermarks to maximum
+ * safe values
+ */
+void dce110_mem_input_program_safe_display_marks(struct mem_input *mi);
+
+/*
+ * dce110_mem_input_program_display_marks
+ *
+ * This function will program nbp stutter and urgency watermarks to minimum
+ * allowable values
+ */
+void dce110_mem_input_program_display_marks(
+	struct mem_input *mem_input,
+	struct bw_watermarks nbp,
+	struct bw_watermarks stutter,
+	struct bw_watermarks urgent,
+	uint32_t h_total,
+	uint32_t pixel_clk_in_khz,
+	uint32_t pstate_blackout_duration_ns);
+
+/*
+ * dce110_mem_input_allocate_dmif_buffer
+ *
+ * This function will allocate a dmif buffer and program required
+ * pixel duration for pipe
+ */
+void dce110_mem_input_allocate_dmif_buffer(
+		struct mem_input *mem_input,
+		struct dc_crtc_timing *timing,
+		uint32_t paths_num);
+
+/*
+ * dce110_mem_input_deallocate_dmif_buffer
+ *
+ * This function will deallocate a dmif buffer from pipe
+ */
+void dce110_mem_input_deallocate_dmif_buffer(
+	struct mem_input *mem_input, uint32_t paths_num);
+
+/*
+ * dce110_mem_input_program_surface_flip_and_addr
+ *
+ * This function programs hsync/vsync mode and surface address
+ */
+bool dce110_mem_input_program_surface_flip_and_addr(
+	struct mem_input *mem_input,
+	const struct dc_plane_address *address,
+	bool flip_immediate);
+
+/*
+ * dce110_mem_input_program_surface_config
+ *
+ * This function will program surface tiling, size, rotation and pixel format
+ * to corresponding dcp registers.
+ */
+bool  dce110_mem_input_program_surface_config(
+	struct mem_input *mem_input,
+	enum surface_pixel_format format,
+	struct dc_tiling_info *tiling_info,
+	union plane_size *plane_size,
+	enum dc_rotation_angle rotation);
+
+
+#endif
-- 
2.1.4



More information about the dri-devel mailing list