Skip to content

Commit 55fb8ff

Browse files
Paloma Arellanolumag
authored andcommitted
drm/msm/dp: add VSC SDP support for YUV420 over DP
Add support to pack and send the VSC SDP packet for DP. This therefore allows the transmision of format information to the sinks which is needed for YUV420 support over DP. Changes in v5: - Slightly modify use of drm_dp_vsc_sdp_pack() - Remove dp_catalog NULL checks - Modify dp_utils_pack_sdp_header() to more clearly pack the header buffer - Move dp_utils_pack_sdp_header() inside of dp_catalog_panel_send_vsc_sdp to clearly show the relationship between the header buffer and the vsc_sdp struct - Due to the last point, remove the dp_utils_pack_vsc_sdp() function and only call drm_dp_vsc_sdp_pack() in dp_panel_setup_vsc_sdp_yuv_420() Changes in v4: - Remove struct msm_dp_sdp_with_parity - Use dp_utils_pack_sdp_header() to pack the SDP header and parity bytes into a buffer - Use this buffer when writing the VSC SDP data in dp_catalog_panel_send_vsc_sdp() - Write to all of the MMSS_DP_GENERIC0 registers instead of just the ones with non-zero values Changes in v3: - Create a new struct, msm_dp_sdp_with_parity, which holds the packing information for VSC SDP - Use drm_dp_vsc_sdp_pack() to pack the data into the new msm_dp_sdp_with_parity struct instead of specifically packing for YUV420 format - Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP data using the new msm_dp_sdp_with_parity struct Changes in v2: - Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID - Remove dp_sdp from the dp_catalog struct since this data is being allocated at the point used - Create a new function in dp_utils to pack the VSC SDP data into a buffer - Create a new function that packs the SDP header bytes into a buffer. This function is made generic so that it can be utilized by dp_audio header bytes into a buffer - Create a new function in dp_utils that takes the packed buffer and writes to the DP_GENERIC0_* registers - Split the dp_catalog_panel_config_vsc_sdp() function into two to disable/enable sending VSC SDP packets - Check the DP HW version using the original useage of dp_catalog_hw_revision() and correct the version checking logic - Rename dp_panel_setup_vsc_sdp() to dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that currently VSC SDP is only being set up to support YUV420 modes Signed-off-by: Paloma Arellano <quic_parellan@quicinc.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Patchwork: https://patchwork.freedesktop.org/patch/579636/ Link: https://lore.kernel.org/r/20240222194025.25329-14-quic_parellan@quicinc.com Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
1 parent 09b27a4 commit 55fb8ff

7 files changed

Lines changed: 195 additions & 0 deletions

File tree

drivers/gpu/drm/msm/dp/dp_catalog.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,99 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
892892
return 0;
893893
}
894894

895+
static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp)
896+
{
897+
struct dp_catalog_private *catalog;
898+
u32 header[2];
899+
u32 val;
900+
int i;
901+
902+
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
903+
904+
dp_utils_pack_sdp_header(&vsc_sdp->sdp_header, header);
905+
906+
dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
907+
dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
908+
909+
for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
910+
val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i + 2] << 16) |
911+
(vsc_sdp->db[i + 3] << 24));
912+
dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
913+
}
914+
}
915+
916+
static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
917+
{
918+
struct dp_catalog_private *catalog;
919+
u32 hw_revision;
920+
921+
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
922+
923+
hw_revision = dp_catalog_hw_revision(dp_catalog);
924+
if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= DP_HW_VERSION_1_0) {
925+
dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
926+
dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
927+
}
928+
}
929+
930+
void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp)
931+
{
932+
struct dp_catalog_private *catalog;
933+
u32 cfg, cfg2, misc;
934+
935+
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
936+
937+
cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
938+
cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
939+
misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
940+
941+
cfg |= GEN0_SDP_EN;
942+
dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
943+
944+
cfg2 |= GENERIC0_SDPSIZE_VALID;
945+
dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2);
946+
947+
dp_catalog_panel_send_vsc_sdp(dp_catalog, vsc_sdp);
948+
949+
/* indicates presence of VSC (BIT(6) of MISC1) */
950+
misc |= DP_MISC1_VSC_SDP;
951+
952+
drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=1\n");
953+
954+
pr_debug("misc settings = 0x%x\n", misc);
955+
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc);
956+
957+
dp_catalog_panel_update_sdp(dp_catalog);
958+
}
959+
960+
void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog)
961+
{
962+
struct dp_catalog_private *catalog;
963+
u32 cfg, cfg2, misc;
964+
965+
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
966+
967+
cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
968+
cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
969+
misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
970+
971+
cfg &= ~GEN0_SDP_EN;
972+
dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
973+
974+
cfg2 &= ~GENERIC0_SDPSIZE_VALID;
975+
dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2);
976+
977+
/* switch back to MSA */
978+
misc &= ~DP_MISC1_VSC_SDP;
979+
980+
drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=0\n");
981+
982+
pr_debug("misc settings = 0x%x\n", misc);
983+
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc);
984+
985+
dp_catalog_panel_update_sdp(dp_catalog);
986+
}
987+
895988
void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
896989
struct drm_display_mode *drm_mode)
897990
{

drivers/gpu/drm/msm/dp/dp_catalog.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <drm/drm_modes.h>
1010

11+
#include "dp_utils.h"
1112
#include "disp/msm_disp_snapshot.h"
1213

1314
/* interrupts */
@@ -29,6 +30,9 @@
2930

3031
#define DP_AUX_CFG_MAX_VALUE_CNT 3
3132

33+
#define DP_HW_VERSION_1_0 0x10000000
34+
#define DP_HW_VERSION_1_2 0x10020000
35+
3236
/* PHY AUX config registers */
3337
enum dp_phy_aux_config_type {
3438
PHY_AUX_CFG0,
@@ -120,6 +124,8 @@ u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog);
120124

121125
/* DP Panel APIs */
122126
int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog);
127+
void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp);
128+
void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog);
123129
void dp_catalog_dump_regs(struct dp_catalog *dp_catalog);
124130
void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
125131
struct drm_display_mode *drm_mode);

drivers/gpu/drm/msm/dp/dp_ctrl.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,8 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
20482048
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
20492049
phy = ctrl->phy;
20502050

2051+
dp_catalog_panel_disable_vsc_sdp(ctrl->catalog);
2052+
20512053
/* set dongle to D3 (power off) mode */
20522054
dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
20532055

@@ -2100,6 +2102,8 @@ void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
21002102
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
21012103
phy = ctrl->phy;
21022104

2105+
dp_catalog_panel_disable_vsc_sdp(ctrl->catalog);
2106+
21032107
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
21042108

21052109
dp_catalog_ctrl_reset(ctrl->catalog);

drivers/gpu/drm/msm/dp/dp_panel.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#include "dp_panel.h"
7+
#include "dp_utils.h"
78

89
#include <drm/drm_connector.h>
910
#include <drm/drm_edid.h>
@@ -288,6 +289,53 @@ void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable)
288289
dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode);
289290
}
290291

292+
static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel)
293+
{
294+
struct dp_catalog *catalog;
295+
struct dp_panel_private *panel;
296+
struct dp_display_mode *dp_mode;
297+
struct drm_dp_vsc_sdp vsc_sdp_data;
298+
struct dp_sdp vsc_sdp;
299+
ssize_t len;
300+
301+
if (!dp_panel) {
302+
DRM_ERROR("invalid input\n");
303+
return -EINVAL;
304+
}
305+
306+
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
307+
catalog = panel->catalog;
308+
dp_mode = &dp_panel->dp_mode;
309+
310+
memset(&vsc_sdp_data, 0, sizeof(vsc_sdp_data));
311+
312+
/* VSC SDP header as per table 2-118 of DP 1.4 specification */
313+
vsc_sdp_data.sdp_type = DP_SDP_VSC;
314+
vsc_sdp_data.revision = 0x05;
315+
vsc_sdp_data.length = 0x13;
316+
317+
/* VSC SDP Payload for DB16 */
318+
vsc_sdp_data.pixelformat = DP_PIXELFORMAT_YUV420;
319+
vsc_sdp_data.colorimetry = DP_COLORIMETRY_DEFAULT;
320+
321+
/* VSC SDP Payload for DB17 */
322+
vsc_sdp_data.bpc = dp_mode->bpp / 3;
323+
vsc_sdp_data.dynamic_range = DP_DYNAMIC_RANGE_CTA;
324+
325+
/* VSC SDP Payload for DB18 */
326+
vsc_sdp_data.content_type = DP_CONTENT_TYPE_GRAPHICS;
327+
328+
len = drm_dp_vsc_sdp_pack(&vsc_sdp_data, &vsc_sdp);
329+
if (len < 0) {
330+
DRM_ERROR("unable to pack vsc sdp\n");
331+
return len;
332+
}
333+
334+
dp_catalog_panel_enable_vsc_sdp(catalog, &vsc_sdp);
335+
336+
return 0;
337+
}
338+
291339
void dp_panel_dump_regs(struct dp_panel *dp_panel)
292340
{
293341
struct dp_catalog *catalog;
@@ -351,6 +399,10 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel)
351399
catalog->dp_active = data;
352400

353401
dp_catalog_panel_timing_cfg(catalog);
402+
403+
if (dp_panel->dp_mode.out_fmt_is_yuv_420)
404+
dp_panel_setup_vsc_sdp_yuv_420(dp_panel);
405+
354406
panel->panel_on = true;
355407

356408
return 0;

drivers/gpu/drm/msm/dp/dp_reg.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
#define DP_MISC0_SYNCHRONOUS_CLK (0x00000001)
143143
#define DP_MISC0_COLORIMETRY_CFG_SHIFT (0x00000001)
144144
#define DP_MISC0_TEST_BITS_DEPTH_SHIFT (0x00000005)
145+
#define DP_MISC1_VSC_SDP (0x00004000)
145146

146147
#define DP_MISC0_COLORIMERY_CFG_LEGACY_RGB (0)
147148
#define DP_MISC0_COLORIMERY_CFG_CEA_RGB (0x04)
@@ -204,9 +205,11 @@
204205
#define MMSS_DP_AUDIO_CTRL_RESET (0x00000214)
205206

206207
#define MMSS_DP_SDP_CFG (0x00000228)
208+
#define GEN0_SDP_EN (0x00020000)
207209
#define MMSS_DP_SDP_CFG2 (0x0000022C)
208210
#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230)
209211
#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234)
212+
#define GENERIC0_SDPSIZE_VALID (0x00010000)
210213

211214
#define MMSS_DP_AUDIO_STREAM_0 (0x00000240)
212215
#define MMSS_DP_AUDIO_STREAM_1 (0x00000244)

drivers/gpu/drm/msm/dp/dp_utils.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include "dp_utils.h"
99

10+
#define DP_SDP_HEADER_SIZE 8
11+
1012
u8 dp_utils_get_g0_value(u8 data)
1113
{
1214
u8 c[4];
@@ -71,3 +73,24 @@ u8 dp_utils_calculate_parity(u32 data)
7173

7274
return parity_byte;
7375
}
76+
77+
ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff)
78+
{
79+
size_t length;
80+
81+
length = sizeof(header_buff);
82+
if (length < DP_SDP_HEADER_SIZE)
83+
return -ENOSPC;
84+
85+
header_buff[0] = FIELD_PREP(HEADER_0_MASK, sdp_header->HB0) |
86+
FIELD_PREP(PARITY_0_MASK, dp_utils_calculate_parity(sdp_header->HB0)) |
87+
FIELD_PREP(HEADER_1_MASK, sdp_header->HB1) |
88+
FIELD_PREP(PARITY_1_MASK, dp_utils_calculate_parity(sdp_header->HB1));
89+
90+
header_buff[1] = FIELD_PREP(HEADER_2_MASK, sdp_header->HB2) |
91+
FIELD_PREP(PARITY_2_MASK, dp_utils_calculate_parity(sdp_header->HB2)) |
92+
FIELD_PREP(HEADER_3_MASK, sdp_header->HB3) |
93+
FIELD_PREP(PARITY_3_MASK, dp_utils_calculate_parity(sdp_header->HB3));
94+
95+
return length;
96+
}

drivers/gpu/drm/msm/dp/dp_utils.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#ifndef _DP_UTILS_H_
77
#define _DP_UTILS_H_
88

9+
#include <linux/bitfield.h>
10+
#include <linux/bits.h>
11+
#include <drm/display/drm_dp_helper.h>
12+
913
#define HEADER_BYTE_0_BIT 0
1014
#define PARITY_BYTE_0_BIT 8
1115
#define HEADER_BYTE_1_BIT 16
@@ -15,8 +19,18 @@
1519
#define HEADER_BYTE_3_BIT 16
1620
#define PARITY_BYTE_3_BIT 24
1721

22+
#define HEADER_0_MASK GENMASK(7, 0)
23+
#define PARITY_0_MASK GENMASK(15, 8)
24+
#define HEADER_1_MASK GENMASK(23, 16)
25+
#define PARITY_1_MASK GENMASK(31, 24)
26+
#define HEADER_2_MASK GENMASK(7, 0)
27+
#define PARITY_2_MASK GENMASK(15, 8)
28+
#define HEADER_3_MASK GENMASK(23, 16)
29+
#define PARITY_3_MASK GENMASK(31, 24)
30+
1831
u8 dp_utils_get_g0_value(u8 data);
1932
u8 dp_utils_get_g1_value(u8 data);
2033
u8 dp_utils_calculate_parity(u32 data);
34+
ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff);
2135

2236
#endif /* _DP_UTILS_H_ */

0 commit comments

Comments
 (0)