Rework infoframe to add audio informations. Support two additional pixel formats in GDP planes.
Arnaud Pouliquen (1): drm: sti: HDMI add audio infoframe
Benjamin Gaignard (1): drm: sti: add support of ABGR8888 for gdp plane
Fabien Dessenne (1): drm: sti: add support of XBGR8888 for gdp plane
Jassi Brar (1): drm: sti: fix check for clk_pix_main
Vincent Abriou (1): drm: sti: fix static checker warning in sti_awg_utils
drivers/gpu/drm/sti/sti_awg_utils.c | 2 - drivers/gpu/drm/sti/sti_gdp.c | 11 +++ drivers/gpu/drm/sti/sti_hdmi.c | 179 +++++++++++++++++++++++++++--------- drivers/gpu/drm/sti/sti_hqvdp.c | 2 +- 4 files changed, 149 insertions(+), 45 deletions(-)
From: Jassi Brar jaswinder.singh@linaro.org
copy-paste wasn't followed by editing, do it.
Signed-off-by: Jassi Brar jaswinder.singh@linaro.org --- drivers/gpu/drm/sti/sti_hqvdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index f3db05d..b0eb62d 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -1025,7 +1025,7 @@ static int sti_hqvdp_probe(struct platform_device *pdev) /* Get clock resources */ hqvdp->clk = devm_clk_get(dev, "hqvdp"); hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main"); - if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk)) { + if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk_pix_main)) { DRM_ERROR("Cannot get clocks\n"); return -ENXIO; }
From: Vincent Abriou vincent.abriou@st.com
The shift and the mask done on arg value is useless since arg is null.
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_awg_utils.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c index 9fde3ee..6029a2e 100644 --- a/drivers/gpu/drm/sti/sti_awg_utils.c +++ b/drivers/gpu/drm/sti/sti_awg_utils.c @@ -60,8 +60,6 @@ static int awg_generate_instr(enum opcode opcode, * pixel. So we transform SKIP into SET * instruction */ opcode = SET; - arg = (arg << 24) >> 24; - arg &= (0x0ff); break; }
Use GDP capabilities to support DRM_FORMAT_ABGR8888 (AB24)
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/drm/sti/sti_gdp.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 32448d1..f018bb1 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -14,7 +14,9 @@ #include "sti_layer.h" #include "sti_vtg.h"
+#define ALPHASWITCH BIT(6) #define ENA_COLOR_FILL BIT(8) +#define BIGNOTLITTLE BIT(23) #define WAIT_NEXT_VSYNC BIT(31)
/* GDP color formats */ @@ -23,6 +25,7 @@ #define GDP_RGB888_32 0x02 #define GDP_ARGB8565 0x04 #define GDP_ARGB8888 0x05 +#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) #define GDP_ARGB1555 0x06 #define GDP_ARGB4444 0x07 #define GDP_CLUT8 0x0B @@ -104,6 +107,7 @@ struct sti_gdp { static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB1555, DRM_FORMAT_RGB565, @@ -131,6 +135,8 @@ static int sti_gdp_fourcc2format(int fourcc) return GDP_RGB888_32; case DRM_FORMAT_ARGB8888: return GDP_ARGB8888; + case DRM_FORMAT_ABGR8888: + return GDP_ABGR8888; case DRM_FORMAT_ARGB4444: return GDP_ARGB4444; case DRM_FORMAT_ARGB1555: @@ -157,6 +163,7 @@ static int sti_gdp_get_alpharange(int format) case GDP_ARGB8565: case GDP_ARGB8888: case GDP_AYCBR8888: + case GDP_ABGR8888: return GAM_GDP_ALPHARANGE_255; } return 0;
From: Fabien Dessenne fabien.dessenne@st.com
Use GDP capabilities to support DRM_FORMAT_XBGR8888 (XB24)
Signed-off-by: Fabien Dessenne fabien.dessenne@st.com --- drivers/gpu/drm/sti/sti_gdp.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index f018bb1..087906f 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -23,6 +23,7 @@ #define GDP_RGB565 0x00 #define GDP_RGB888 0x01 #define GDP_RGB888_32 0x02 +#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) #define GDP_ARGB8565 0x04 #define GDP_ARGB8888 0x05 #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) @@ -106,6 +107,7 @@ struct sti_gdp {
static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB4444, @@ -133,6 +135,8 @@ static int sti_gdp_fourcc2format(int fourcc) switch (fourcc) { case DRM_FORMAT_XRGB8888: return GDP_RGB888_32; + case DRM_FORMAT_XBGR8888: + return GDP_XBGR8888; case DRM_FORMAT_ARGB8888: return GDP_ARGB8888; case DRM_FORMAT_ABGR8888:
From: Arnaud Pouliquen arnaud.pouliquen@st.com
Add a default audio infoframe for HDMI compliance
Signed-off-by: Arnaud Pouliquen arnaud.pouliquen@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 179 +++++++++++++++++++++++++++++++---------- 1 file changed, 137 insertions(+), 42 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index e840ca5d..1485ade 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -42,8 +42,17 @@ #define HDMI_SW_DI_1_PKT_WORD5 0x0228 #define HDMI_SW_DI_1_PKT_WORD6 0x022C #define HDMI_SW_DI_CFG 0x0230 +#define HDMI_SW_DI_2_HEAD_WORD 0x0600 +#define HDMI_SW_DI_2_PKT_WORD0 0x0604 +#define HDMI_SW_DI_2_PKT_WORD1 0x0608 +#define HDMI_SW_DI_2_PKT_WORD2 0x060C +#define HDMI_SW_DI_2_PKT_WORD3 0x0610 +#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_IFRAME_SLOT_AVI 1 +#define HDMI_IFRAME_SLOT_AUDIO 2
#define XCAT(prefix, x, suffix) prefix ## x ## suffix #define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD) @@ -99,6 +108,10 @@
#define HDMI_STA_SW_RST BIT(1)
+#define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) +#define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) +#define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) + struct sti_hdmi_connector { struct drm_connector drm_connector; struct drm_encoder *encoder; @@ -228,6 +241,90 @@ static void hdmi_config(struct sti_hdmi *hdmi) }
/** + * Helper to concatenate infoframe in 32 bits word + * + * @ptr: pointer on the hdmi internal structure + * @data: infoframe to write + * @size: size to write + */ +static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size) +{ + unsigned long value = 0; + size_t i; + + for (i = size; i > 0; i--) + value = (value << 8) | ptr[i - 1]; + + return value; +} + +/** + * Helper to write info frame + * + * @hdmi: pointer on the hdmi internal structure + * @data: infoframe to write + * @size: size to write + */ +static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data) +{ + const u8 *ptr = data; + u32 val, slot, mode, i; + u32 head_offset, pack_offset; + size_t size; + + switch (*ptr) { + case HDMI_INFOFRAME_TYPE_AVI: + slot = HDMI_IFRAME_SLOT_AVI; + 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; + + default: + DRM_ERROR("unsupported infoframe type: %#x\n", *ptr); + return; + } + + /* Disable transmission slot for updated infoframe */ + 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); + + val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++); + val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++); + val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++); + writel(val, hdmi->regs + head_offset); + + /* + * Each subpack contains 4 bytes + * The First Bytes of the first subpacket must contain the checksum + * Packet size in increase by one. + */ + for (i = 0; i < size; i += sizeof(u32)) { + size_t num; + + num = min_t(size_t, size - i, sizeof(u32)); + val = hdmi_infoframe_subpack(ptr, num); + ptr += sizeof(u32); + writel(val, hdmi->regs + pack_offset + i); + } + + /* Enable transmission slot for updated infoframe */ + val = hdmi_read(hdmi, HDMI_SW_DI_CFG); + val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot); + hdmi_write(hdmi, val, HDMI_SW_DI_CFG); +} + +/** * Prepare and configure the AVI infoframe * * AVI infoframe are transmitted at least once per two video field and @@ -243,8 +340,6 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) struct drm_display_mode *mode = &hdmi->mode; struct hdmi_avi_infoframe infoframe; u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; - u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE; - u32 val; int ret;
DRM_DEBUG_DRIVER("\n"); @@ -266,47 +361,43 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) return ret; }
- /* Disable transmission slot for AVI infoframe */ - val = hdmi_read(hdmi, HDMI_SW_DI_CFG); - val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI); - hdmi_write(hdmi, val, HDMI_SW_DI_CFG); + hdmi_infoframe_write_infopack(hdmi, buffer);
- /* Infoframe header */ - val = buffer[0]; - val |= buffer[1] << 8; - val |= buffer[2] << 16; - hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI)); - - /* Infoframe packet bytes */ - val = buffer[3]; - val |= *(frame++) << 8; - val |= *(frame++) << 16; - val |= *(frame++) << 24; - hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI)); - - val = *(frame++); - val |= *(frame++) << 8; - val |= *(frame++) << 16; - val |= *(frame++) << 24; - hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI)); - - val = *(frame++); - val |= *(frame++) << 8; - val |= *(frame++) << 16; - val |= *(frame++) << 24; - hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI)); - - val = *(frame++); - val |= *(frame) << 8; - hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI)); - - /* Enable transmission slot for AVI infoframe - * According to the hdmi specification, AVI infoframe should be - * transmitted at least once per two video fields - */ - val = hdmi_read(hdmi, HDMI_SW_DI_CFG); - val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI); - hdmi_write(hdmi, val, HDMI_SW_DI_CFG); + return 0; +} + +/** + * Prepare and configure the AUDIO infoframe + * + * AUDIO infoframe are transmitted once per frame and + * contains information about HDMI transmission mode such as audio codec, + * sample size, ... + * + * @hdmi: pointer on the hdmi internal structure + * + * Return negative value if error occurs + */ +static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) +{ + struct hdmi_audio_infoframe infofame; + u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; + int ret; + + ret = hdmi_audio_infoframe_init(&infofame); + if (ret < 0) { + DRM_ERROR("failed to setup audio infoframe: %d\n", ret); + return ret; + } + + infofame.channels = 2; + + ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer)); + if (ret < 0) { + DRM_ERROR("failed to pack audio infoframe: %d\n", ret); + return ret; + } + + hdmi_infoframe_write_infopack(hdmi, buffer);
return 0; } @@ -427,6 +518,10 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge) if (hdmi_avi_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AVI infoframe\n");
+ /* Program AUDIO infoframe */ + if (hdmi_audio_infoframe_config(hdmi)) + DRM_ERROR("Unable to configure AUDIO infoframe\n"); + /* Sw reset */ hdmi_swreset(hdmi); }
linaro-mm-sig@lists.linaro.org