Skip to content

Commit d7d57ec

Browse files
committed
drm/msm/hdmi: also send the SPD and HDMI Vendor Specific InfoFrames
Extend the driver to send SPD and HDMI Vendor Specific InfoFrames. While the HDMI block has special block to send HVS InfoFrame, use GENERIC0 block instead. VENSPEC_INFO registers pack frame data in a way that requires manual repacking in the driver, while GENERIC0 doesn't have such format requirements. The msm-4.4 kernel uses GENERIC0 to send HDR InfoFrame which we do not at this point anyway. Acked-by: Maxime Ripard <[email protected]> Reviewed-by: Abhinav Kumar <[email protected]> Signed-off-by: Dmitry Baryshkov <[email protected]> Patchwork: https://patchwork.freedesktop.org/patch/639661/ Link: https://lore.kernel.org/r/[email protected]
1 parent e925736 commit d7d57ec

File tree

1 file changed

+93
-0
lines changed

1 file changed

+93
-0
lines changed

drivers/gpu/drm/msm/hdmi/hdmi_bridge.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static void power_off(struct drm_bridge *bridge)
6969
}
7070

7171
#define AVI_IFRAME_LINE_NUMBER 1
72+
#define SPD_IFRAME_LINE_NUMBER 1
73+
#define VENSPEC_IFRAME_LINE_NUMBER 3
7274

7375
static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi,
7476
const u8 *buffer, size_t len)
@@ -142,6 +144,74 @@ static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi,
142144
return 0;
143145
}
144146

147+
static int msm_hdmi_config_spd_infoframe(struct hdmi *hdmi,
148+
const u8 *buffer, size_t len)
149+
{
150+
u32 buf[7] = {};
151+
u32 val;
152+
int i;
153+
154+
if (len != HDMI_INFOFRAME_SIZE(SPD) || len - 3 > sizeof(buf)) {
155+
DRM_DEV_ERROR(&hdmi->pdev->dev,
156+
"failed to configure SPD infoframe\n");
157+
return -EINVAL;
158+
}
159+
160+
/* checksum gets written together with the body of the frame */
161+
hdmi_write(hdmi, REG_HDMI_GENERIC1_HDR,
162+
buffer[0] |
163+
buffer[1] << 8 |
164+
buffer[2] << 16);
165+
166+
memcpy(buf, &buffer[3], len - 3);
167+
168+
for (i = 0; i < ARRAY_SIZE(buf); i++)
169+
hdmi_write(hdmi, REG_HDMI_GENERIC1(i), buf[i]);
170+
171+
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
172+
val |= HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
173+
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
174+
HDMI_GEN_PKT_CTRL_GENERIC1_LINE(SPD_IFRAME_LINE_NUMBER);
175+
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
176+
177+
return 0;
178+
}
179+
180+
static int msm_hdmi_config_hdmi_infoframe(struct hdmi *hdmi,
181+
const u8 *buffer, size_t len)
182+
{
183+
u32 buf[7] = {};
184+
u32 val;
185+
int i;
186+
187+
if (len < HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_SIZE ||
188+
len - 3 > sizeof(buf)) {
189+
DRM_DEV_ERROR(&hdmi->pdev->dev,
190+
"failed to configure HDMI infoframe\n");
191+
return -EINVAL;
192+
}
193+
194+
/* checksum gets written together with the body of the frame */
195+
hdmi_write(hdmi, REG_HDMI_GENERIC0_HDR,
196+
buffer[0] |
197+
buffer[1] << 8 |
198+
buffer[2] << 16);
199+
200+
memcpy(buf, &buffer[3], len - 3);
201+
202+
for (i = 0; i < ARRAY_SIZE(buf); i++)
203+
hdmi_write(hdmi, REG_HDMI_GENERIC0(i), buf[i]);
204+
205+
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
206+
val |= HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
207+
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
208+
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
209+
HDMI_GEN_PKT_CTRL_GENERIC0_LINE(VENSPEC_IFRAME_LINE_NUMBER);
210+
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
211+
212+
return 0;
213+
}
214+
145215
static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
146216
enum hdmi_infoframe_type type)
147217
{
@@ -176,6 +246,25 @@ static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge,
176246

177247
break;
178248

249+
case HDMI_INFOFRAME_TYPE_SPD:
250+
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
251+
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC1_SEND |
252+
HDMI_GEN_PKT_CTRL_GENERIC1_CONT |
253+
HDMI_GEN_PKT_CTRL_GENERIC1_LINE__MASK);
254+
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
255+
256+
break;
257+
258+
case HDMI_INFOFRAME_TYPE_VENDOR:
259+
val = hdmi_read(hdmi, REG_HDMI_GEN_PKT_CTRL);
260+
val &= ~(HDMI_GEN_PKT_CTRL_GENERIC0_SEND |
261+
HDMI_GEN_PKT_CTRL_GENERIC0_CONT |
262+
HDMI_GEN_PKT_CTRL_GENERIC0_UPDATE |
263+
HDMI_GEN_PKT_CTRL_GENERIC0_LINE__MASK);
264+
hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, val);
265+
266+
break;
267+
179268
default:
180269
drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
181270
}
@@ -197,6 +286,10 @@ static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge,
197286
return msm_hdmi_config_avi_infoframe(hdmi, buffer, len);
198287
case HDMI_INFOFRAME_TYPE_AUDIO:
199288
return msm_hdmi_config_audio_infoframe(hdmi, buffer, len);
289+
case HDMI_INFOFRAME_TYPE_SPD:
290+
return msm_hdmi_config_spd_infoframe(hdmi, buffer, len);
291+
case HDMI_INFOFRAME_TYPE_VENDOR:
292+
return msm_hdmi_config_hdmi_infoframe(hdmi, buffer, len);
200293
default:
201294
drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n", type);
202295
return 0;

0 commit comments

Comments
 (0)