summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c306
1 files changed, 268 insertions, 38 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c
index 0552fc5f7ecc..718688c41f7b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c
@@ -23,18 +23,18 @@
*
*/
-#include "mem_input.h"
+#include "dce_mem_input.h"
#include "reg_helper.h"
#include "basics/conversion.h"
#define CTX \
- mi->ctx
+ dce_mi->base.ctx
#define REG(reg)\
- mi->regs->reg
+ dce_mi->regs->reg
#undef FN
#define FN(reg_name, field_name) \
- mi->shifts->field_name, mi->masks->field_name
+ dce_mi->shifts->field_name, dce_mi->masks->field_name
struct pte_setting {
unsigned int bpp;
@@ -130,11 +130,13 @@ static bool is_vert_scan(enum dc_rotation_angle rotation)
}
}
-void dce_mem_input_program_pte_vm(struct mem_input *mi,
+static void dce_mi_program_pte_vm(
+ struct mem_input *mi,
enum surface_pixel_format format,
union dc_tiling_info *tiling_info,
enum dc_rotation_angle rotation)
{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
enum mi_bits_per_pixel mi_bpp = get_mi_bpp(format);
enum mi_tiling_format mi_tiling = get_mi_tiling(tiling_info);
const struct pte_setting *pte = &pte_settings[mi_tiling][mi_bpp];
@@ -158,7 +160,8 @@ void dce_mem_input_program_pte_vm(struct mem_input *mi,
DVMM_MAX_PTE_REQ_OUTSTANDING, 0xff);
}
-static void program_urgency_watermark(struct mem_input *mi,
+static void program_urgency_watermark(
+ struct dce_mem_input *dce_mi,
uint32_t wm_select,
uint32_t urgency_low_wm,
uint32_t urgency_high_wm)
@@ -171,7 +174,8 @@ static void program_urgency_watermark(struct mem_input *mi,
URGENCY_HIGH_WATERMARK, urgency_high_wm);
}
-static void program_nbp_watermark(struct mem_input *mi,
+static void program_nbp_watermark(
+ struct dce_mem_input *dce_mi,
uint32_t wm_select,
uint32_t nbp_wm)
{
@@ -202,7 +206,8 @@ static void program_nbp_watermark(struct mem_input *mi,
}
}
-static void program_stutter_watermark(struct mem_input *mi,
+static void program_stutter_watermark(
+ struct dce_mem_input *dce_mi,
uint32_t wm_select,
uint32_t stutter_mark)
{
@@ -217,41 +222,67 @@ static void program_stutter_watermark(struct mem_input *mi,
STUTTER_EXIT_SELF_REFRESH_WATERMARK, stutter_mark);
}
-void dce_mem_input_program_display_marks(struct mem_input *mi,
+static void dce_mi_program_display_marks(
+ struct mem_input *mi,
struct dce_watermarks nbp,
struct dce_watermarks stutter,
struct dce_watermarks urgent,
uint32_t total_dest_line_time_ns)
{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
uint32_t stutter_en = mi->ctx->dc->debug.disable_stutter ? 0 : 1;
- program_urgency_watermark(mi, 0, /* set a */
+ program_urgency_watermark(dce_mi, 2, /* set a */
urgent.a_mark, total_dest_line_time_ns);
- program_urgency_watermark(mi, 1, /* set b */
+ program_urgency_watermark(dce_mi, 1, /* set d */
+ urgent.d_mark, total_dest_line_time_ns);
+
+ REG_UPDATE_2(DPG_PIPE_STUTTER_CONTROL,
+ STUTTER_ENABLE, stutter_en,
+ STUTTER_IGNORE_FBC, 1);
+ program_nbp_watermark(dce_mi, 2, nbp.a_mark); /* set a */
+ program_nbp_watermark(dce_mi, 1, nbp.d_mark); /* set d */
+
+ program_stutter_watermark(dce_mi, 2, stutter.a_mark); /* set a */
+ program_stutter_watermark(dce_mi, 1, stutter.d_mark); /* set d */
+}
+
+static void dce120_mi_program_display_marks(struct mem_input *mi,
+ struct dce_watermarks nbp,
+ struct dce_watermarks stutter,
+ struct dce_watermarks urgent,
+ uint32_t total_dest_line_time_ns)
+{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
+ uint32_t stutter_en = mi->ctx->dc->debug.disable_stutter ? 0 : 1;
+
+ program_urgency_watermark(dce_mi, 0, /* set a */
+ urgent.a_mark, total_dest_line_time_ns);
+ program_urgency_watermark(dce_mi, 1, /* set b */
urgent.b_mark, total_dest_line_time_ns);
- program_urgency_watermark(mi, 2, /* set c */
+ program_urgency_watermark(dce_mi, 2, /* set c */
urgent.c_mark, total_dest_line_time_ns);
- program_urgency_watermark(mi, 3, /* set d */
+ program_urgency_watermark(dce_mi, 3, /* set d */
urgent.d_mark, total_dest_line_time_ns);
REG_UPDATE_2(DPG_PIPE_STUTTER_CONTROL,
STUTTER_ENABLE, stutter_en,
STUTTER_IGNORE_FBC, 1);
- program_nbp_watermark(mi, 0, nbp.a_mark); /* set a */
- program_nbp_watermark(mi, 1, nbp.b_mark); /* set b */
- program_nbp_watermark(mi, 2, nbp.c_mark); /* set c */
- program_nbp_watermark(mi, 3, nbp.d_mark); /* set d */
-
- program_stutter_watermark(mi, 0, stutter.a_mark); /* set a */
- program_stutter_watermark(mi, 1, stutter.b_mark); /* set b */
- program_stutter_watermark(mi, 2, stutter.c_mark); /* set c */
- program_stutter_watermark(mi, 3, stutter.d_mark); /* set d */
+ program_nbp_watermark(dce_mi, 0, nbp.a_mark); /* set a */
+ program_nbp_watermark(dce_mi, 1, nbp.b_mark); /* set b */
+ program_nbp_watermark(dce_mi, 2, nbp.c_mark); /* set c */
+ program_nbp_watermark(dce_mi, 3, nbp.d_mark); /* set d */
+
+ program_stutter_watermark(dce_mi, 0, stutter.a_mark); /* set a */
+ program_stutter_watermark(dce_mi, 1, stutter.b_mark); /* set b */
+ program_stutter_watermark(dce_mi, 2, stutter.c_mark); /* set c */
+ program_stutter_watermark(dce_mi, 3, stutter.d_mark); /* set d */
}
-static void program_tiling(struct mem_input *mi,
- const union dc_tiling_info *info)
+static void program_tiling(
+ struct dce_mem_input *dce_mi, const union dc_tiling_info *info)
{
- if (mi->masks->GRPH_SW_MODE) { /* GFX9 */
+ if (dce_mi->masks->GRPH_SW_MODE) { /* GFX9 */
REG_UPDATE_6(GRPH_CONTROL,
GRPH_SW_MODE, info->gfx9.swizzle,
GRPH_NUM_BANKS, log_2(info->gfx9.num_banks),
@@ -265,7 +296,7 @@ static void program_tiling(struct mem_input *mi,
*/
}
- if (mi->masks->GRPH_ARRAY_MODE) { /* GFX8 */
+ if (dce_mi->masks->GRPH_ARRAY_MODE) { /* GFX8 */
REG_UPDATE_9(GRPH_CONTROL,
GRPH_NUM_BANKS, info->gfx8.num_banks,
GRPH_BANK_WIDTH, info->gfx8.bank_width,
@@ -285,7 +316,7 @@ static void program_tiling(struct mem_input *mi,
static void program_size_and_rotation(
- struct mem_input *mi,
+ struct dce_mem_input *dce_mi,
enum dc_rotation_angle rotation,
const union plane_size *plane_size)
{
@@ -326,7 +357,7 @@ static void program_size_and_rotation(
}
static void program_grph_pixel_format(
- struct mem_input *mi,
+ struct dce_mem_input *dce_mi,
enum surface_pixel_format format)
{
uint32_t red_xbar = 0, blue_xbar = 0; /* no swap */
@@ -397,7 +428,8 @@ static void program_grph_pixel_format(
GRPH_PRESCALE_B_SIGN, sign);
}
-void dce_mem_input_program_surface_config(struct mem_input *mi,
+static void dce_mi_program_surface_config(
+ struct mem_input *mi,
enum surface_pixel_format format,
union dc_tiling_info *tiling_info,
union plane_size *plane_size,
@@ -405,14 +437,15 @@ void dce_mem_input_program_surface_config(struct mem_input *mi,
struct dc_plane_dcc_param *dcc,
bool horizontal_mirror)
{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
REG_UPDATE(GRPH_ENABLE, GRPH_ENABLE, 1);
- program_tiling(mi, tiling_info);
- program_size_and_rotation(mi, rotation, plane_size);
+ program_tiling(dce_mi, tiling_info);
+ program_size_and_rotation(dce_mi, rotation, plane_size);
if (format >= SURFACE_PIXEL_FORMAT_GRPH_BEGIN &&
format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
- program_grph_pixel_format(mi, format);
+ program_grph_pixel_format(dce_mi, format);
}
static uint32_t get_dmif_switch_time_us(
@@ -461,12 +494,14 @@ static uint32_t get_dmif_switch_time_us(
return frame_time;
}
-void dce_mem_input_allocate_dmif(struct mem_input *mi,
+static void dce_mi_allocate_dmif(
+ struct mem_input *mi,
uint32_t h_total,
uint32_t v_total,
uint32_t pix_clk_khz,
uint32_t total_stream_num)
{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
const uint32_t retry_delay = 10;
uint32_t retry_count = get_dmif_switch_time_us(
h_total,
@@ -497,18 +532,20 @@ void dce_mem_input_allocate_dmif(struct mem_input *mi,
PIXEL_DURATION, pix_dur);
}
- if (mi->wa.single_head_rdreq_dmif_limit) {
+ if (dce_mi->wa.single_head_rdreq_dmif_limit) {
uint32_t eanble = (total_stream_num > 1) ? 0 :
- mi->wa.single_head_rdreq_dmif_limit;
+ dce_mi->wa.single_head_rdreq_dmif_limit;
REG_UPDATE(MC_HUB_RDREQ_DMIF_LIMIT,
ENABLE, eanble);
}
}
-void dce_mem_input_free_dmif(struct mem_input *mi,
+static void dce_mi_free_dmif(
+ struct mem_input *mi,
uint32_t total_stream_num)
{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
uint32_t buffers_allocated;
uint32_t dmif_buffer_control;
@@ -525,11 +562,204 @@ void dce_mem_input_free_dmif(struct mem_input *mi,
DMIF_BUFFERS_ALLOCATION_COMPLETED, 1,
10, 3500);
- if (mi->wa.single_head_rdreq_dmif_limit) {
+ if (dce_mi->wa.single_head_rdreq_dmif_limit) {
uint32_t eanble = (total_stream_num > 1) ? 0 :
- mi->wa.single_head_rdreq_dmif_limit;
+ dce_mi->wa.single_head_rdreq_dmif_limit;
REG_UPDATE(MC_HUB_RDREQ_DMIF_LIMIT,
ENABLE, eanble);
}
}
+
+
+static void program_sec_addr(
+ struct dce_mem_input *dce_mi,
+ PHYSICAL_ADDRESS_LOC address)
+{
+ /*high register MUST be programmed first*/
+ REG_SET(GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0,
+ GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+ address.high_part);
+
+ REG_SET_2(GRPH_SECONDARY_SURFACE_ADDRESS, 0,
+ GRPH_SECONDARY_SURFACE_ADDRESS, address.low_part >> 8,
+ GRPH_SECONDARY_DFQ_ENABLE, 0);
+}
+
+static void program_pri_addr(
+ struct dce_mem_input *dce_mi,
+ PHYSICAL_ADDRESS_LOC address)
+{
+ /*high register MUST be programmed first*/
+ REG_SET(GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
+ GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+ address.high_part);
+
+ REG_SET(GRPH_PRIMARY_SURFACE_ADDRESS, 0,
+ GRPH_PRIMARY_SURFACE_ADDRESS,
+ address.low_part >> 8);
+}
+
+
+static bool dce_mi_is_flip_pending(struct mem_input *mem_input)
+{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mem_input);
+ uint32_t update_pending;
+
+ REG_GET(GRPH_UPDATE, GRPH_SURFACE_UPDATE_PENDING, &update_pending);
+ if (update_pending)
+ return true;
+
+ mem_input->current_address = mem_input->request_address;
+ return false;
+}
+
+static bool dce_mi_program_surface_flip_and_addr(
+ struct mem_input *mem_input,
+ const struct dc_plane_address *address,
+ bool flip_immediate)
+{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mem_input);
+
+ /* TODO: Figure out if two modes are needed:
+ * non-XDMA Mode: GRPH_SURFACE_UPDATE_IMMEDIATE_EN = 1
+ * XDMA Mode: GRPH_SURFACE_UPDATE_H_RETRACE_EN = 1
+ */
+ REG_UPDATE(GRPH_UPDATE,
+ GRPH_UPDATE_LOCK, 1);
+
+ if (flip_immediate) {
+ REG_UPDATE_2(GRPH_FLIP_CONTROL,
+ GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
+ GRPH_SURFACE_UPDATE_H_RETRACE_EN, 1);
+ } else {
+ REG_UPDATE_2(GRPH_FLIP_CONTROL,
+ GRPH_SURFACE_UPDATE_IMMEDIATE_EN, 0,
+ GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
+ }
+
+ switch (address->type) {
+ case PLN_ADDR_TYPE_GRAPHICS:
+ if (address->grph.addr.quad_part == 0)
+ break;
+ program_pri_addr(dce_mi, address->grph.addr);
+ break;
+ case PLN_ADDR_TYPE_GRPH_STEREO:
+ if (address->grph_stereo.left_addr.quad_part == 0
+ || address->grph_stereo.right_addr.quad_part == 0)
+ break;
+ program_pri_addr(dce_mi, address->grph_stereo.left_addr);
+ program_sec_addr(dce_mi, address->grph_stereo.right_addr);
+ break;
+ default:
+ /* not supported */
+ BREAK_TO_DEBUGGER();
+ break;
+ }
+
+ mem_input->request_address = *address;
+
+ if (flip_immediate)
+ mem_input->current_address = *address;
+
+ REG_UPDATE(GRPH_UPDATE,
+ GRPH_UPDATE_LOCK, 0);
+
+ return true;
+}
+
+static void dce_mi_update_dchub(struct mem_input *mi,
+ struct dchub_init_data *dh_data)
+{
+ struct dce_mem_input *dce_mi = TO_DCE_MEM_INPUT(mi);
+ /* TODO: port code from dal2 */
+ switch (dh_data->fb_mode) {
+ case FRAME_BUFFER_MODE_ZFB_ONLY:
+ /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
+ REG_UPDATE_2(DCHUB_FB_LOCATION,
+ FB_TOP, 0,
+ FB_BASE, 0x0FFFF);
+
+ REG_UPDATE(DCHUB_AGP_BASE,
+ AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
+
+ REG_UPDATE(DCHUB_AGP_BOT,
+ AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
+
+ REG_UPDATE(DCHUB_AGP_TOP,
+ AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
+ break;
+ case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
+ /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
+ REG_UPDATE(DCHUB_AGP_BASE,
+ AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
+
+ REG_UPDATE(DCHUB_AGP_BOT,
+ AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
+
+ REG_UPDATE(DCHUB_AGP_TOP,
+ AGP_TOP, (dh_data->zfb_mc_base_addr + dh_data->zfb_size_in_byte - 1) >> 22);
+ break;
+ case FRAME_BUFFER_MODE_LOCAL_ONLY:
+ /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
+ REG_UPDATE(DCHUB_AGP_BASE,
+ AGP_BASE, 0);
+
+ REG_UPDATE(DCHUB_AGP_BOT,
+ AGP_BOT, 0x03FFFF);
+
+ REG_UPDATE(DCHUB_AGP_TOP,
+ AGP_TOP, 0);
+ break;
+ default:
+ break;
+ }
+
+ dh_data->dchub_initialzied = true;
+ dh_data->dchub_info_valid = false;
+}
+
+static struct mem_input_funcs dce_mi_funcs = {
+ .mem_input_program_display_marks = dce_mi_program_display_marks,
+ .allocate_mem_input = dce_mi_allocate_dmif,
+ .free_mem_input = dce_mi_free_dmif,
+ .mem_input_program_surface_flip_and_addr =
+ dce_mi_program_surface_flip_and_addr,
+ .mem_input_program_pte_vm = dce_mi_program_pte_vm,
+ .mem_input_program_surface_config =
+ dce_mi_program_surface_config,
+ .mem_input_is_flip_pending = dce_mi_is_flip_pending,
+ .mem_input_update_dchub = dce_mi_update_dchub
+};
+
+
+void dce_mem_input_construct(
+ struct dce_mem_input *dce_mi,
+ struct dc_context *ctx,
+ int inst,
+ const struct dce_mem_input_registers *regs,
+ const struct dce_mem_input_shift *mi_shift,
+ const struct dce_mem_input_mask *mi_mask)
+{
+ dce_mi->base.ctx = ctx;
+
+ dce_mi->base.inst = inst;
+ dce_mi->base.funcs = &dce_mi_funcs;
+
+ dce_mi->regs = regs;
+ dce_mi->shifts = mi_shift;
+ dce_mi->masks = mi_mask;
+
+}
+
+void dce112_mem_input_construct(
+ struct dce_mem_input *dce_mi,
+ struct dc_context *ctx,
+ int inst,
+ const struct dce_mem_input_registers *regs,
+ const struct dce_mem_input_shift *mi_shift,
+ const struct dce_mem_input_mask *mi_mask)
+{
+ dce_mem_input_construct(dce_mi, ctx, inst, regs, mi_shift, mi_mask);
+ dce_mi->base.funcs->mem_input_program_display_marks = dce120_mi_program_display_marks;
+}