This bunch of patches deals with encoders and connectors. For the HDMI connector, it bring the support of the vendor specific infoframe and bring the support of 2 HDMI connector properties. It also solves the panel detection and timing issues on the DVO connector and force the HDA connector reset at start up.
Bich Hemon (2): drm/sti: adjust delay for DVO drm/sti: fix dvo data_enable signal
Vincent Abriou (9): drm/sti: do not clip RGB/YUV component value at connector side drm/sti: fix panel detection for DVO connector drm/sti: add missing encoder cleanup for DVO connector drm/sti: reset HD DACS when HDA connector is created drm/sti: HDMI infoframe transmission mode not take into account drm/sti: reset infoframe transmission when HDMI is stopped drm/sti: add HDMI vendor specific infoframe drm/sti: add colorspace property to the HDMI connector drm/sti: add hdmi_mode property for HDMI connector
drivers/gpu/drm/sti/sti_awg_utils.c | 51 +++++--- drivers/gpu/drm/sti/sti_dvo.c | 8 +- drivers/gpu/drm/sti/sti_hda.c | 3 + drivers/gpu/drm/sti/sti_hdmi.c | 225 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/sti/sti_hdmi.h | 27 +++++ drivers/gpu/drm/sti/sti_tvout.c | 18 +-- drivers/gpu/drm/sti/sti_vtg.c | 5 +- 7 files changed, 296 insertions(+), 41 deletions(-)
Disable the clipping mode for hdmi, dvo and hda connectors.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_tvout.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 1c27a2c..784a3e2 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -326,9 +326,8 @@ static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path) TVO_VIP_REORDER_Y_G_SEL, TVO_VIP_REORDER_CB_B_SEL);
- /* Set clipping mode (Limited range RGB/Y) */ - tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, - TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); + /* Set clipping mode */ + tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO, TVO_VIP_CLIP_DISABLED);
/* Set round mode (rounded to 8-bit per component) */ tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED); @@ -383,9 +382,8 @@ static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) TVO_VIP_REORDER_Y_G_SEL, TVO_VIP_REORDER_CB_B_SEL);
- /* set clipping mode (Limited range RGB/Y) */ - tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, - TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); + /* set clipping mode */ + tvout_vip_set_clip_mode(tvout, TVO_VIP_HDMI, TVO_VIP_CLIP_DISABLED);
/* set round mode (rounded to 8-bit per component) */ tvout_vip_set_rnd(tvout, TVO_VIP_HDMI, TVO_VIP_RND_8BIT_ROUNDED); @@ -442,8 +440,8 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) TVO_VIP_REORDER_Y_G_SEL, TVO_VIP_REORDER_CB_B_SEL);
- /* set clipping mode (EAV/SAV clipping) */ - tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_EAV_SAV); + /* set clipping mode */ + tvout_vip_set_clip_mode(tvout, TVO_VIP_HDF, TVO_VIP_CLIP_DISABLED);
/* set round mode (rounded to 10-bit per component) */ tvout_vip_set_rnd(tvout, TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
The DVO connector is tag as disconnect because of a wrong management of the panel detection.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_dvo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 45cbe2b..9e90b74 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -345,12 +345,14 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_DRIVER("\n");
- if (!dvo->panel) + if (!dvo->panel) { dvo->panel = of_drm_find_panel(dvo->panel_node); + if (dvo->panel) + drm_panel_attach(dvo->panel, connector); + }
if (dvo->panel) - if (!drm_panel_attach(dvo->panel, connector)) - return connector_status_connected; + return connector_status_connected;
return connector_status_disconnected; }
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_tvout.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 784a3e2..0b171fd 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -663,6 +663,10 @@ static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) if (tvout->hda) drm_encoder_cleanup(tvout->hda); tvout->hda = NULL; + + if (tvout->dvo) + drm_encoder_cleanup(tvout->dvo); + tvout->dvo = NULL; }
static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
From: Bich Hemon bich.hemon@st.com
Modify delay to display last pixel column on DVO
Signed-off-by: Bich Hemon bich.hemon@st.com --- drivers/gpu/drm/sti/sti_vtg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index 313d703..32c7986 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -64,6 +64,9 @@ /* Delay introduced by the HDMI in nb of pixel */ #define HDMI_DELAY (5)
+/* Delay introduced by the DVO in nb of pixel */ +#define DVO_DELAY (2) + /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ #define AWG_DELAY_HD (-9) #define AWG_DELAY_ED (-8) @@ -278,7 +281,7 @@ static void vtg_set_mode(struct sti_vtg *vtg, vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_HDF - 1], AWG_DELAY_HD, mode);
/* Set hsync and vsync position for DVO */ - vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_DVO - 1], 0, mode); + vtg_set_hsync_vsync_pos(&sync[VTG_SYNC_ID_DVO - 1], DVO_DELAY, mode);
/* Progam the syncs outputs */ for (i = 0; i < VTG_MAX_SYNC_OUTPUT ; i++) {
From: Bich Hemon bich.hemon@st.com
Modify AWG algorithm in order to handle more than 1023 lines
Signed-off-by: Bich Hemon bich.hemon@st.com --- drivers/gpu/drm/sti/sti_awg_utils.c | 51 +++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index 2378b93..a516eb8 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c @@ -7,6 +7,7 @@ #include "sti_awg_utils.h"
#define AWG_OPCODE_OFFSET 10 +#define AWG_MAX_ARG 0x3ff
enum opcode { SET, @@ -67,7 +68,7 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0; data_enable = 0; - arg &= (0x3ff); + arg &= AWG_MAX_ARG; break; case REPEAT: case REPLAY: @@ -78,13 +79,13 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0; data_enable = 0; - arg &= (0x3ff); + arg &= AWG_MAX_ARG; break; case JUMP: mux = 0; data_enable = 0; arg |= 0x40; /* for jump instruction 7th bit is 1 */ - arg &= 0x3ff; + arg &= AWG_MAX_ARG; break; case STOP: arg = 0; @@ -112,22 +113,13 @@ static int awg_generate_instr(enum opcode opcode, return 0; }
-int sti_awg_generate_code_data_enable_mode( +static int awg_generate_line_signal( struct awg_code_generation_params *fwparams, struct awg_timing *timing) { long int val; int ret = 0;
- if (timing->trailing_lines > 0) { - /* skip trailing lines */ - val = timing->blanking_level; - ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); - - val = timing->trailing_lines - 1; - ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams); - } - if (timing->trailing_pixels > 0) { /* skip trailing pixel */ val = timing->blanking_level; @@ -152,9 +144,36 @@ int sti_awg_generate_code_data_enable_mode( ret |= awg_generate_instr(SET, val, 0, 0, fwparams); }
- /* replay the sequence as many active lines defined */ - val = timing->active_lines - 1; - ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams); + return ret; +} + +int sti_awg_generate_code_data_enable_mode( + struct awg_code_generation_params *fwparams, + struct awg_timing *timing) +{ + long int val, tmp_val; + int ret = 0; + + if (timing->trailing_lines > 0) { + /* skip trailing lines */ + val = timing->blanking_level; + ret |= awg_generate_instr(RPLSET, val, 0, 0, fwparams); + + val = timing->trailing_lines - 1; + ret |= awg_generate_instr(REPLAY, val, 0, 0, fwparams); + } + + tmp_val = timing->active_lines - 1; + + while (tmp_val > 0) { + /* generate DE signal for each line */ + ret |= awg_generate_line_signal(fwparams, timing); + /* replay the sequence as many active lines defined */ + ret |= awg_generate_instr(REPLAY, + min_t(int, AWG_MAX_ARG, tmp_val), + 0, 0, fwparams); + tmp_val -= AWG_MAX_ARG; + }
if (timing->blanking_lines > 0) { /* skip blanking lines */
Make sure the HD DACS are disabled when the HDA connector is created.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hda.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 49cce83..293a133 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -685,6 +685,9 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) goto err_sysfs; }
+ /* force to disable hd dacs at startup */ + hda_enable_hd_dacs(hda, false); + return 0;
err_sysfs:
Set the infoframe transmission mode according to the type of the infoframe.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index cd50156..8537852 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -321,7 +321,7 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
/* Enable transmission slot for updated infoframe */ val = hdmi_read(hdmi, HDMI_SW_DI_CFG); - val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot); + val |= HDMI_IFRAME_CFG_DI_N(mode, slot); hdmi_write(hdmi, val, HDMI_SW_DI_CFG); }
Clear all infoframe registers when the HDMI link is stopped.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 8537852..ff04ed2 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -65,6 +65,8 @@ #define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5) #define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
+#define HDMI_SW_DI_MAX_WORD 7 + #define HDMI_IFRAME_DISABLED 0x0 #define HDMI_IFRAME_SINGLE_SHOT 0x1 #define HDMI_IFRAME_FIELD 0x2 @@ -241,6 +243,43 @@ static void hdmi_config(struct sti_hdmi *hdmi) hdmi_write(hdmi, conf, HDMI_CFG); }
+/* + * Helper to reset info frame + * + * @hdmi: pointer on the hdmi internal structure + * @slot: infoframe to reset + */ +static void hdmi_infoframe_reset(struct sti_hdmi *hdmi, + u32 slot) +{ + u32 val, i; + u32 head_offset, pack_offset; + + switch (slot) { + case HDMI_IFRAME_SLOT_AVI: + head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); + pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); + break; + case HDMI_IFRAME_SLOT_AUDIO: + head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); + pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); + break; + default: + DRM_ERROR("unsupported infoframe slot: %#x\n", slot); + return; + } + + /* Disable transmission for the selected slot */ + val = hdmi_read(hdmi, HDMI_SW_DI_CFG); + val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot); + hdmi_write(hdmi, val, HDMI_SW_DI_CFG); + + /* Reset info frame registers */ + hdmi_write(hdmi, 0x0, head_offset); + for (i = 0; i < HDMI_SW_DI_MAX_WORD; i += sizeof(u32)) + hdmi_write(hdmi, 0x0, pack_offset + i); +} + /** * Helper to concatenate infoframe in 32 bits word * @@ -468,6 +507,10 @@ static void sti_hdmi_disable(struct drm_bridge *bridge) /* Stop the phy */ hdmi->phy_ops->stop(hdmi);
+ /* Reset info frame transmission */ + hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI); + hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO); + /* Set the default channel data to be a dark red */ hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT); hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
Vendor specific infoframe is mandatory for 4K2K resolution. Without this, the HDMI protocol compliance fails.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 82 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index ff04ed2..34e33a1 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -51,9 +51,18 @@ #define HDMI_SW_DI_2_PKT_WORD4 0x0614 #define HDMI_SW_DI_2_PKT_WORD5 0x0618 #define HDMI_SW_DI_2_PKT_WORD6 0x061C +#define HDMI_SW_DI_3_HEAD_WORD 0x0620 +#define HDMI_SW_DI_3_PKT_WORD0 0x0624 +#define HDMI_SW_DI_3_PKT_WORD1 0x0628 +#define HDMI_SW_DI_3_PKT_WORD2 0x062C +#define HDMI_SW_DI_3_PKT_WORD3 0x0630 +#define HDMI_SW_DI_3_PKT_WORD4 0x0634 +#define HDMI_SW_DI_3_PKT_WORD5 0x0638 +#define HDMI_SW_DI_3_PKT_WORD6 0x063C
#define HDMI_IFRAME_SLOT_AVI 1 #define HDMI_IFRAME_SLOT_AUDIO 2 +#define HDMI_IFRAME_SLOT_VENDOR 3
#define XCAT(prefix, x, suffix) prefix ## x ## suffix #define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD) @@ -264,6 +273,10 @@ static void hdmi_infoframe_reset(struct sti_hdmi *hdmi, head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); break; + case HDMI_IFRAME_SLOT_VENDOR: + head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR); + pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR); + break; default: DRM_ERROR("unsupported infoframe slot: %#x\n", slot); return; @@ -305,12 +318,13 @@ static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size) * @data: infoframe to write * @size: size to write */ -static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) +static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, + const u8 *data, + size_t size) { const u8 *ptr = data; u32 val, slot, mode, i; u32 head_offset, pack_offset; - size_t size;
switch (*ptr) { case HDMI_INFOFRAME_TYPE_AVI: @@ -318,17 +332,19 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) mode = HDMI_IFRAME_FIELD; head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); - size = HDMI_AVI_INFOFRAME_SIZE; break; - case HDMI_INFOFRAME_TYPE_AUDIO: slot = HDMI_IFRAME_SLOT_AUDIO; mode = HDMI_IFRAME_FRAME; head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); - size = HDMI_AUDIO_INFOFRAME_SIZE; break; - + case HDMI_INFOFRAME_TYPE_VENDOR: + slot = HDMI_IFRAME_SLOT_VENDOR; + mode = HDMI_IFRAME_FRAME; + head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR); + pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR); + break; default: DRM_ERROR("unsupported infoframe type: %#x\n", *ptr); return; @@ -347,8 +363,9 @@ static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) /* * Each subpack contains 4 bytes * The First Bytes of the first subpacket must contain the checksum - * Packet size in increase by one. + * Packet size is increase by one. */ + size = size - HDMI_INFOFRAME_HEADER_SIZE + 1; for (i = 0; i < size; i += sizeof(u32)) { size_t num;
@@ -401,7 +418,7 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) return ret; }
- hdmi_infoframe_write_infopack(hdmi, buffer); + hdmi_infoframe_write_infopack(hdmi, buffer, ret);
return 0; } @@ -437,7 +454,49 @@ static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) return ret; }
- hdmi_infoframe_write_infopack(hdmi, buffer); + hdmi_infoframe_write_infopack(hdmi, buffer, ret); + + return 0; +} + +/* + * Prepare and configure the VS infoframe + * + * Vendor Specific infoframe are transmitted once per frame and + * contains vendor specific information. + * + * @hdmi: pointer on the hdmi internal structure + * + * Return negative value if error occurs + */ +#define HDMI_VENDOR_INFOFRAME_MAX_SIZE 6 +static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi) +{ + struct drm_display_mode *mode = &hdmi->mode; + struct hdmi_vendor_infoframe infoframe; + u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_MAX_SIZE]; + int ret; + + DRM_DEBUG_DRIVER("\n"); + + ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode); + if (ret < 0) { + /* + * Going into that statement does not means vendor infoframe + * fails. It just informed us that vendor infoframe is not + * needed for the selected mode. Only 4k or stereoscopic 3D + * mode requires vendor infoframe. So just simply return 0. + */ + return 0; + } + + ret = hdmi_vendor_infoframe_pack(&infoframe, buffer, sizeof(buffer)); + if (ret < 0) { + DRM_ERROR("failed to pack VS infoframe: %d\n", ret); + return ret; + } + + hdmi_infoframe_write_infopack(hdmi, buffer, ret);
return 0; } @@ -510,6 +569,7 @@ static void sti_hdmi_disable(struct drm_bridge *bridge) /* Reset info frame transmission */ hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI); hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO); + hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_VENDOR);
/* Set the default channel data to be a dark red */ hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT); @@ -566,6 +626,10 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) if (hdmi_audio_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AUDIO infoframe\n");
+ /* Program VS infoframe */ + if (hdmi_vendor_infoframe_config(hdmi)) + DRM_ERROR("Unable to configure VS infoframe\n"); + /* Sw reset */ hdmi_swreset(hdmi); }
Make the value of the colorspace of the HDMI infoframe configurable. HDMI colorspace could be: RGB, YUV422 or YUV444
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 68 +++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.h | 12 ++++++++ 2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 34e33a1..1f37dc4 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -128,6 +128,7 @@ struct sti_hdmi_connector { struct drm_connector drm_connector; struct drm_encoder *encoder; struct sti_hdmi *hdmi; + struct drm_property *colorspace_property; };
#define to_sti_hdmi_connector(x) \ @@ -408,7 +409,7 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) }
/* fixed infoframe configuration not linked to the mode */ - infoframe.colorspace = HDMI_COLORSPACE_RGB; + infoframe.colorspace = hdmi->colorspace; infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
@@ -771,12 +772,74 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector) kfree(hdmi_connector); }
+static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, + struct drm_connector *connector) +{ + struct sti_hdmi_connector *hdmi_connector + = to_sti_hdmi_connector(connector); + struct sti_hdmi *hdmi = hdmi_connector->hdmi; + struct drm_property *prop; + + /* colorspace property */ + hdmi->colorspace = DEFAULT_COLORSPACE_MODE; + prop = drm_property_create_enum(drm_dev, 0, "colorspace", + colorspace_mode_names, + ARRAY_SIZE(colorspace_mode_names)); + if (!prop) { + DRM_ERROR("fails to create colorspace property\n"); + return; + } + hdmi_connector->colorspace_property = prop; + drm_object_attach_property(&connector->base, prop, hdmi->colorspace); +} + +static int +sti_hdmi_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + struct sti_hdmi_connector *hdmi_connector + = to_sti_hdmi_connector(connector); + struct sti_hdmi *hdmi = hdmi_connector->hdmi; + + if (property == hdmi_connector->colorspace_property) { + hdmi->colorspace = val; + return 0; + } + + DRM_ERROR("failed to set hdmi connector property\n"); + return -EINVAL; +} + +static int +sti_hdmi_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct sti_hdmi_connector *hdmi_connector + = to_sti_hdmi_connector(connector); + struct sti_hdmi *hdmi = hdmi_connector->hdmi; + + if (property == hdmi_connector->colorspace_property) { + *val = hdmi->colorspace; + return 0; + } + + DRM_ERROR("failed to get hdmi connector property\n"); + return -EINVAL; +} + static const struct drm_connector_funcs sti_hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, .destroy = sti_hdmi_connector_destroy, .reset = drm_atomic_helper_connector_reset, + .set_property = drm_atomic_helper_connector_set_property, + .atomic_set_property = sti_hdmi_connector_set_property, + .atomic_get_property = sti_hdmi_connector_get_property, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; @@ -836,6 +899,9 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_hdmi_connector_helper_funcs);
+ /* initialise property */ + sti_hdmi_connector_init_property(drm_dev, drm_connector); + err = drm_connector_register(drm_connector); if (err) goto err_connector; diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index 3d22390..f621cd7 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -7,6 +7,7 @@ #ifndef _STI_HDMI_H_ #define _STI_HDMI_H_
+#include <linux/hdmi.h> #include <linux/platform_device.h>
#include <drm/drmP.h> @@ -24,6 +25,14 @@ struct hdmi_phy_ops { void (*stop)(struct sti_hdmi *hdmi); };
+static const struct drm_prop_enum_list colorspace_mode_names[] = { + { HDMI_COLORSPACE_RGB, "rgb" }, + { HDMI_COLORSPACE_YUV422, "yuv422" }, + { HDMI_COLORSPACE_YUV444, "yuv444" }, +}; + +#define DEFAULT_COLORSPACE_MODE HDMI_COLORSPACE_RGB + /** * STI hdmi structure * @@ -44,6 +53,8 @@ struct hdmi_phy_ops { * @wait_event: wait event * @event_received: wait event status * @reset: reset control of the hdmi phy + * @ddc_adapt: i2c ddc adapter + * @colorspace: current colorspace selected */ struct sti_hdmi { struct device dev; @@ -64,6 +75,7 @@ struct sti_hdmi { bool event_received; struct reset_control *reset; struct i2c_adapter *ddc_adapt; + enum hdmi_colorspace colorspace; };
u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
Configures the framer of the HDMI connection. By default starts in HDMI mode and can be swtich to DVI.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/drm/sti/sti_hdmi.h | 15 +++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 1f37dc4..69a2286 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -129,6 +129,7 @@ struct sti_hdmi_connector { struct drm_encoder *encoder; struct sti_hdmi *hdmi; struct drm_property *colorspace_property; + struct drm_property *hdmi_mode_property; };
#define to_sti_hdmi_connector(x) \ @@ -229,8 +230,10 @@ static void hdmi_config(struct sti_hdmi *hdmi) /* Clear overrun and underrun fifo */ conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
- /* Enable HDMI mode not DVI */ - conf |= HDMI_CFG_HDMI_NOT_DVI | HDMI_CFG_ESS_NOT_OESS; + /* Select encryption type and the framing mode */ + conf |= HDMI_CFG_ESS_NOT_OESS; + if (hdmi->hdmi_mode == HDMI_MODE_HDMI) + conf |= HDMI_CFG_HDMI_NOT_DVI;
/* Enable sink term detection */ conf |= HDMI_CFG_SINK_TERM_DET_EN; @@ -791,6 +794,19 @@ static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, } hdmi_connector->colorspace_property = prop; drm_object_attach_property(&connector->base, prop, hdmi->colorspace); + + /* hdmi_mode property */ + hdmi->hdmi_mode = DEFAULT_HDMI_MODE; + prop = drm_property_create_enum(drm_dev, 0, "hdmi_mode", + hdmi_mode_names, + ARRAY_SIZE(hdmi_mode_names)); + if (!prop) { + DRM_ERROR("fails to create colorspace property\n"); + return; + } + hdmi_connector->hdmi_mode_property = prop; + drm_object_attach_property(&connector->base, prop, hdmi->hdmi_mode); + }
static int @@ -808,6 +824,11 @@ sti_hdmi_connector_set_property(struct drm_connector *connector, return 0; }
+ if (property == hdmi_connector->hdmi_mode_property) { + hdmi->hdmi_mode = val; + return 0; + } + DRM_ERROR("failed to set hdmi connector property\n"); return -EINVAL; } @@ -827,6 +848,11 @@ sti_hdmi_connector_get_property(struct drm_connector *connector, return 0; }
+ if (property == hdmi_connector->hdmi_mode_property) { + *val = hdmi->hdmi_mode; + return 0; + } + DRM_ERROR("failed to get hdmi connector property\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index f621cd7..77edb73 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -25,6 +25,19 @@ struct hdmi_phy_ops { void (*stop)(struct sti_hdmi *hdmi); };
+/* values for the framing mode property */ +enum sti_hdmi_modes { + HDMI_MODE_HDMI, + HDMI_MODE_DVI, +}; + +static const struct drm_prop_enum_list hdmi_mode_names[] = { + { HDMI_MODE_HDMI, "hdmi" }, + { HDMI_MODE_DVI, "dvi" }, +}; + +#define DEFAULT_HDMI_MODE HDMI_MODE_HDMI + static const struct drm_prop_enum_list colorspace_mode_names[] = { { HDMI_COLORSPACE_RGB, "rgb" }, { HDMI_COLORSPACE_YUV422, "yuv422" }, @@ -55,6 +68,7 @@ static const struct drm_prop_enum_list colorspace_mode_names[] = { * @reset: reset control of the hdmi phy * @ddc_adapt: i2c ddc adapter * @colorspace: current colorspace selected + * @hdmi_mode: select framing for HDMI or DVI */ struct sti_hdmi { struct device dev; @@ -76,6 +90,7 @@ struct sti_hdmi { struct reset_control *reset; struct i2c_adapter *ddc_adapt; enum hdmi_colorspace colorspace; + enum sti_hdmi_modes hdmi_mode; };
u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
dri-devel@lists.freedesktop.org