mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 19:43:40 +02:00
drm/amd/display: RV stereo support
HDMI frame pack and DP frame alternate in band Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
c9742685c2
commit
9edba5574d
|
|
@ -361,6 +361,7 @@ struct dc_surface_status {
|
|||
struct dc_plane_address requested_address;
|
||||
struct dc_plane_address current_address;
|
||||
bool is_flip_pending;
|
||||
bool is_right_eye;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -476,7 +477,7 @@ struct dc_stream {
|
|||
const struct dc_transfer_func *out_transfer_func;
|
||||
struct colorspace_transform gamut_remap_matrix;
|
||||
struct csc_transform csc_color_matrix;
|
||||
|
||||
enum view_3d_format view_format;
|
||||
/* TODO: custom INFO packets */
|
||||
/* TODO: ABM info (DMCU) */
|
||||
/* TODO: PSR info */
|
||||
|
|
@ -591,6 +592,15 @@ bool dc_commit_streams(
|
|||
struct dc *dc,
|
||||
const struct dc_stream *streams[],
|
||||
uint8_t stream_count);
|
||||
/*
|
||||
* Enable stereo when commit_streams is not required,
|
||||
* for example, frame alternate.
|
||||
*/
|
||||
bool dc_enable_stereo(
|
||||
struct dc *dc,
|
||||
struct validate_context *context,
|
||||
const struct dc_stream *streams[],
|
||||
uint8_t stream_count);
|
||||
|
||||
/**
|
||||
* Create a new default stream for the requested sink
|
||||
|
|
@ -777,6 +787,14 @@ struct dc_container_id {
|
|||
unsigned short productCode;
|
||||
};
|
||||
|
||||
struct stereo_3d_features {
|
||||
bool supported ;
|
||||
bool allTimings ;
|
||||
bool cloneMode ;
|
||||
bool scaling ;
|
||||
bool singleFrameSWPacked;
|
||||
};
|
||||
|
||||
/*
|
||||
* The sink structure contains EDID and other display device properties
|
||||
*/
|
||||
|
|
@ -788,6 +806,7 @@ struct dc_sink {
|
|||
uint32_t dongle_max_pix_clk;
|
||||
bool converter_disable_audio;
|
||||
void *priv;
|
||||
struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX];
|
||||
};
|
||||
|
||||
void dc_sink_retain(const struct dc_sink *sink);
|
||||
|
|
|
|||
|
|
@ -78,112 +78,22 @@ static void dcn10_program_global_sync(
|
|||
VREADY_OFFSET, tg->dlg_otg_param.vready_offset);
|
||||
}
|
||||
|
||||
struct crtc_stereo_flags {
|
||||
uint8_t PROGRAM_STEREO :1;
|
||||
uint8_t PROGRAM_POLARITY :1;
|
||||
uint8_t RIGHT_EYE_POLARITY :1;
|
||||
uint8_t FRAME_PACKED :1;
|
||||
uint8_t DISABLE_STEREO_DP_SYNC :1;
|
||||
};
|
||||
|
||||
static void dcn10_enable_stereo(struct timing_generator *tg,
|
||||
const struct crtc_stereo_flags *flags,
|
||||
const struct dc_crtc_timing *timing)
|
||||
{
|
||||
struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
|
||||
|
||||
uint32_t active_width = timing->h_addressable;
|
||||
uint32_t space1_size = timing->v_total - timing->v_addressable;
|
||||
|
||||
if (flags) {
|
||||
uint32_t stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0;
|
||||
|
||||
if (flags->PROGRAM_STEREO)
|
||||
REG_UPDATE_3(OTG_STEREO_CONTROL,
|
||||
OTG_STEREO_EN, stereo_en,
|
||||
OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0,
|
||||
OTG_STEREO_SYNC_OUTPUT_POLARITY, 0);
|
||||
|
||||
if (flags->PROGRAM_POLARITY)
|
||||
REG_UPDATE(OTG_STEREO_CONTROL,
|
||||
OTG_STEREO_EYE_FLAG_POLARITY,
|
||||
flags->RIGHT_EYE_POLARITY == 0 ? 0:1);
|
||||
|
||||
if (flags->DISABLE_STEREO_DP_SYNC)
|
||||
REG_UPDATE(OTG_STEREO_CONTROL,
|
||||
OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
|
||||
|
||||
if (flags->PROGRAM_STEREO && flags->FRAME_PACKED)
|
||||
REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL,
|
||||
OTG_3D_STRUCTURE_EN, 1,
|
||||
OTG_3D_STRUCTURE_V_UPDATE_MODE, 1,
|
||||
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 1);
|
||||
|
||||
}
|
||||
|
||||
REG_UPDATE(OPPBUF_CONTROL,
|
||||
OPPBUF_ACTIVE_WIDTH, active_width);
|
||||
|
||||
REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
|
||||
OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void dcn10_disable_stereo(struct timing_generator *tg)
|
||||
{
|
||||
struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
|
||||
|
||||
REG_SET(OTG_STEREO_CONTROL, 0,
|
||||
OTG_STEREO_EN, 0);
|
||||
OTG_STEREO_EN, 0);
|
||||
|
||||
REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0,
|
||||
OTG_3D_STRUCTURE_EN, 0,
|
||||
OTG_3D_STRUCTURE_V_UPDATE_MODE, 0,
|
||||
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
|
||||
OTG_3D_STRUCTURE_EN, 0,
|
||||
OTG_3D_STRUCTURE_V_UPDATE_MODE, 0,
|
||||
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
|
||||
|
||||
REG_UPDATE(OPPBUF_CONTROL,
|
||||
OPPBUF_ACTIVE_WIDTH, 0);
|
||||
OPPBUF_ACTIVE_WIDTH, 0);
|
||||
REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
|
||||
OPPBUF_3D_VACT_SPACE1_SIZE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static bool is_frame_alternate_stereo(enum dc_timing_3d_format fmt)
|
||||
{
|
||||
bool ret = false;
|
||||
if (fmt == TIMING_3D_FORMAT_FRAME_ALTERNATE ||
|
||||
fmt == TIMING_3D_FORMAT_INBAND_FA ||
|
||||
fmt == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
|
||||
fmt == TIMING_3D_FORMAT_SIDEBAND_FA)
|
||||
ret = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dcn10_do_stereo(struct timing_generator *tg,
|
||||
const struct dc_crtc_timing *dc_crtc_timing)
|
||||
{
|
||||
struct crtc_stereo_flags stereo_flags = {0};
|
||||
if (dc_crtc_timing->timing_3d_format == TIMING_3D_FORMAT_NONE ||
|
||||
dc_crtc_timing->timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
|
||||
dc_crtc_timing->timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
|
||||
dcn10_disable_stereo(tg);
|
||||
else {
|
||||
stereo_flags.PROGRAM_STEREO = 1;
|
||||
stereo_flags.PROGRAM_POLARITY = 1;
|
||||
stereo_flags.DISABLE_STEREO_DP_SYNC = 0;
|
||||
stereo_flags.RIGHT_EYE_POLARITY =
|
||||
dc_crtc_timing->flags.RIGHT_EYE_3D_POLARITY;
|
||||
if (dc_crtc_timing->timing_3d_format ==
|
||||
TIMING_3D_FORMAT_HW_FRAME_PACKING)
|
||||
stereo_flags.FRAME_PACKED = 1;
|
||||
|
||||
if (is_frame_alternate_stereo(
|
||||
dc_crtc_timing->timing_3d_format) ||
|
||||
dc_crtc_timing->timing_3d_format ==
|
||||
TIMING_3D_FORMAT_HW_FRAME_PACKING)
|
||||
dcn10_enable_stereo(tg, &stereo_flags, dc_crtc_timing);
|
||||
}
|
||||
OPPBUF_3D_VACT_SPACE1_SIZE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -361,9 +271,8 @@ static void tg_program_timing_generator(
|
|||
REG_UPDATE(OTG_H_TIMING_CNTL,
|
||||
OTG_H_TIMING_DIV_BY2, h_div_2);
|
||||
|
||||
/* Enable crtc stereo frame pack tested... todo more
|
||||
*/
|
||||
dcn10_do_stereo(tg, &patched_crtc_timing);
|
||||
dcn10_disable_stereo( tg);
|
||||
|
||||
}
|
||||
|
||||
/** tg_program_blanking
|
||||
|
|
@ -605,7 +514,8 @@ static bool tg_validate_timing(
|
|||
timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING &&
|
||||
timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM &&
|
||||
timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE &&
|
||||
timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE)
|
||||
timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE &&
|
||||
timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA)
|
||||
return false;
|
||||
|
||||
/* Temporarily blocking interlacing mode until it's supported */
|
||||
|
|
@ -1145,6 +1055,76 @@ void dcn10_timing_generator_get_crtc_scanoutpos(
|
|||
*v_position = position.vertical_count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void dcn10_enable_stereo(struct timing_generator *tg,
|
||||
const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags)
|
||||
{
|
||||
struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
|
||||
|
||||
uint32_t active_width = timing->h_addressable;
|
||||
uint32_t space1_size = timing->v_total - timing->v_addressable;
|
||||
|
||||
if (flags) {
|
||||
uint32_t stereo_en;
|
||||
stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0;
|
||||
|
||||
if (flags->PROGRAM_STEREO)
|
||||
REG_UPDATE_3(OTG_STEREO_CONTROL,
|
||||
OTG_STEREO_EN, stereo_en,
|
||||
OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0,
|
||||
OTG_STEREO_SYNC_OUTPUT_POLARITY, 0);
|
||||
|
||||
if (flags->PROGRAM_POLARITY)
|
||||
REG_UPDATE(OTG_STEREO_CONTROL,
|
||||
OTG_STEREO_EYE_FLAG_POLARITY,
|
||||
flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1);
|
||||
|
||||
if (flags->DISABLE_STEREO_DP_SYNC)
|
||||
REG_UPDATE(OTG_STEREO_CONTROL,
|
||||
OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
|
||||
|
||||
if (flags->PROGRAM_STEREO && flags->FRAME_PACKED)
|
||||
REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL,
|
||||
OTG_3D_STRUCTURE_EN, 1,
|
||||
OTG_3D_STRUCTURE_V_UPDATE_MODE, 1,
|
||||
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 1);
|
||||
|
||||
}
|
||||
|
||||
REG_UPDATE(OPPBUF_CONTROL,
|
||||
OPPBUF_ACTIVE_WIDTH, active_width);
|
||||
|
||||
REG_UPDATE(OPPBUF_3D_PARAMETERS_0,
|
||||
OPPBUF_3D_VACT_SPACE1_SIZE, space1_size);
|
||||
}
|
||||
|
||||
static void dcn10_program_stereo(struct timing_generator *tg,
|
||||
const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags)
|
||||
{
|
||||
if (flags->PROGRAM_STEREO)
|
||||
dcn10_enable_stereo(tg, timing, flags);
|
||||
else
|
||||
dcn10_disable_stereo(tg);
|
||||
}
|
||||
|
||||
|
||||
static bool dcn10_is_stereo_left_eye(struct timing_generator *tg)
|
||||
{
|
||||
bool ret = false;
|
||||
uint32_t left_eye = 0;
|
||||
struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
|
||||
|
||||
REG_GET(OTG_STEREO_STATUS,
|
||||
OTG_STEREO_CURRENT_EYE, &left_eye);
|
||||
if (left_eye == 1)
|
||||
ret = true;
|
||||
else
|
||||
ret = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct timing_generator_funcs dcn10_tg_funcs = {
|
||||
.validate_timing = tg_validate_timing,
|
||||
.program_timing = tg_program_timing,
|
||||
|
|
@ -1183,7 +1163,9 @@ static struct timing_generator_funcs dcn10_tg_funcs = {
|
|||
.enable_optc_clock = enable_optc_clock,
|
||||
.set_drr = dcn10_timing_generator_set_drr,
|
||||
.set_static_screen_control = set_static_screen_control,
|
||||
.set_test_pattern = dcn10_timing_generator_set_test_pattern
|
||||
.set_test_pattern = dcn10_timing_generator_set_test_pattern,
|
||||
.program_stereo = dcn10_program_stereo,
|
||||
.is_stereo_left_eye = dcn10_is_stereo_left_eye
|
||||
};
|
||||
|
||||
void dcn10_timing_generator_init(struct dcn10_timing_generator *tgn10)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
SRI(OTG_CONTROL, OTG, inst),\
|
||||
SRI(OTG_STEREO_CONTROL, OTG, inst),\
|
||||
SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\
|
||||
SRI(OTG_STEREO_STATUS, OTG, inst),\
|
||||
SRI(OTG_V_TOTAL_MAX, OTG, inst),\
|
||||
SRI(OTG_V_TOTAL_MIN, OTG, inst),\
|
||||
SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\
|
||||
|
|
@ -96,6 +97,7 @@ struct dcn_tg_registers {
|
|||
uint32_t OTG_CONTROL;
|
||||
uint32_t OTG_STEREO_CONTROL;
|
||||
uint32_t OTG_3D_STRUCTURE_CONTROL;
|
||||
uint32_t OTG_STEREO_STATUS;
|
||||
uint32_t OTG_V_TOTAL_MAX;
|
||||
uint32_t OTG_V_TOTAL_MIN;
|
||||
uint32_t OTG_V_TOTAL_CONTROL;
|
||||
|
|
@ -157,6 +159,8 @@ struct dcn_tg_registers {
|
|||
SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\
|
||||
SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\
|
||||
SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\
|
||||
SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\
|
||||
SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\
|
||||
SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\
|
||||
SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\
|
||||
SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\
|
||||
|
|
@ -243,6 +247,7 @@ struct dcn_tg_registers {
|
|||
type OTG_STEREO_SYNC_OUTPUT_LINE_NUM;\
|
||||
type OTG_STEREO_SYNC_OUTPUT_POLARITY;\
|
||||
type OTG_STEREO_EYE_FLAG_POLARITY;\
|
||||
type OTG_STEREO_CURRENT_EYE;\
|
||||
type OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP;\
|
||||
type OTG_3D_STRUCTURE_EN;\
|
||||
type OTG_3D_STRUCTURE_V_UPDATE_MODE;\
|
||||
|
|
|
|||
|
|
@ -100,6 +100,15 @@ struct _dlg_otg_param {
|
|||
enum signal_type signal;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct crtc_stereo_flags {
|
||||
uint8_t PROGRAM_STEREO : 1;
|
||||
uint8_t PROGRAM_POLARITY : 1;
|
||||
uint8_t RIGHT_EYE_POLARITY : 1;
|
||||
uint8_t FRAME_PACKED : 1;
|
||||
uint8_t DISABLE_STEREO_DP_SYNC : 1;
|
||||
};
|
||||
|
||||
struct timing_generator {
|
||||
const struct timing_generator_funcs *funcs;
|
||||
struct dc_bios *bp;
|
||||
|
|
@ -171,6 +180,9 @@ struct timing_generator_funcs {
|
|||
void (*program_global_sync)(struct timing_generator *tg);
|
||||
void (*enable_optc_clock)(struct timing_generator *tg, bool enable);
|
||||
#endif
|
||||
void (*program_stereo)(struct timing_generator *tg,
|
||||
const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags);
|
||||
bool (*is_stereo_left_eye)(struct timing_generator *tg);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -143,6 +143,10 @@ struct hw_sequencer_funcs {
|
|||
struct pipe_ctx *pipe_ctx,
|
||||
struct validate_context *context,
|
||||
struct core_dc *dc);
|
||||
|
||||
void (*setup_stereo)(
|
||||
struct pipe_ctx *pipe_ctx,
|
||||
struct core_dc *dc);
|
||||
};
|
||||
|
||||
void color_space_to_black_color(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user