From d10f7117aa43b0b0d1c4b878afafb6d151da441d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:46 +0300 Subject: [PATCH 001/170] drm/edid: reset display info in drm_add_edid_modes() for NULL edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a NULL edid gets passed to drm_add_edid_modes(), we should probably also reset the display info. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/2ac1c55f94a08d5e72c0b518d956a11002ec85c1.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bc43e1b32092..1dea0e2f0cab 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5697,6 +5697,7 @@ static int drm_edid_connector_update(struct drm_connector *connector, u32 quirks; if (edid == NULL) { + drm_reset_display_info(connector); clear_eld(connector); return 0; } From 115fcf5899f7e0b0d3358a22a8cd76b1398642ee Mon Sep 17 00:00:00 2001 From: Lee Shawn C Date: Tue, 3 May 2022 12:23:47 +0300 Subject: [PATCH 002/170] drm/edid: check for HF-SCDB block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Find HF-SCDB information in CEA extensions block. And retrieve Max_TMDS_Character_Rate that support by sink device. v2: HF-SCDB and HF-VSDBS carry the same SCDS data. Reuse drm_parse_hdmi_forum_vsdb() to parse this packet. Cc: Jani Nikula Cc: Ville Syrjala Cc: Ankit Nautiyal Cc: intel-gfx Signed-off-by: Lee Shawn C Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/2bf7110cdb56d5dda311480787faf472c9802de4.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1dea0e2f0cab..fe527a0c50bc 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3471,6 +3471,7 @@ add_detailed_modes(struct drm_connector *connector, const struct edid *edid, #define EXT_VIDEO_CAPABILITY_BLOCK 0x00 #define EXT_VIDEO_DATA_BLOCK_420 0x0E #define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F +#define EXT_VIDEO_HF_SCDB_DATA_BLOCK 0x79 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) @@ -4402,6 +4403,20 @@ static bool cea_db_is_vcdb(const u8 *db) return true; } +static bool cea_db_is_hdmi_forum_scdb(const u8 *db) +{ + if (cea_db_tag(db) != USE_EXTENDED_TAG) + return false; + + if (cea_db_payload_len(db) < 7) + return false; + + if (cea_db_extended_tag(db) != EXT_VIDEO_HF_SCDB_DATA_BLOCK) + return false; + + return true; +} + static bool cea_db_is_y420cmdb(const u8 *db) { if (cea_db_tag(db) != USE_EXTENDED_TAG) @@ -5363,7 +5378,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, db); - if (cea_db_is_hdmi_forum_vsdb(db)) + if (cea_db_is_hdmi_forum_vsdb(db) || + cea_db_is_hdmi_forum_scdb(db)) drm_parse_hdmi_forum_vsdb(connector, db); if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, db); From d8cb49d203556707ff4c3aa05032c4fc7c3ff1a2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:48 +0300 Subject: [PATCH 003/170] drm/edid: rename HDMI Forum VSDB to SCDS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HDMI spec talks about SCDS, Sink Capability Data Structure, exposed via HF-VSDB or HF-SCDB. Rename VSDB to SCDS. Suggested-by: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/f8230e1893400e9a9c5829041a8ab36349182a54.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index fe527a0c50bc..18d05cbb2124 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5132,17 +5132,18 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, hdmi->y420_dc_modes = dc_mask; } -static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, - const u8 *hf_vsdb) +/* Sink Capability Data Structure */ +static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, + const u8 *hf_scds) { struct drm_display_info *display = &connector->display_info; struct drm_hdmi_info *hdmi = &display->hdmi; display->has_hdmi_infoframe = true; - if (hf_vsdb[6] & 0x80) { + if (hf_scds[6] & 0x80) { hdmi->scdc.supported = true; - if (hf_vsdb[6] & 0x40) + if (hf_scds[6] & 0x40) hdmi->scdc.read_request = true; } @@ -5155,9 +5156,9 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, * Lets check it out. */ - if (hf_vsdb[5]) { + if (hf_scds[5]) { /* max clock is 5000 KHz times block value */ - u32 max_tmds_clock = hf_vsdb[5] * 5000; + u32 max_tmds_clock = hf_scds[5] * 5000; struct drm_scdc *scdc = &hdmi->scdc; if (max_tmds_clock > 340000) { @@ -5170,42 +5171,42 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, scdc->scrambling.supported = true; /* Few sinks support scrambling for clocks < 340M */ - if ((hf_vsdb[6] & 0x8)) + if ((hf_scds[6] & 0x8)) scdc->scrambling.low_rates = true; } } - if (hf_vsdb[7]) { + if (hf_scds[7]) { u8 max_frl_rate; u8 dsc_max_frl_rate; u8 dsc_max_slices; struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap; DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n"); - max_frl_rate = (hf_vsdb[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; + max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes, &hdmi->max_frl_rate_per_lane); - hdmi_dsc->v_1p2 = hf_vsdb[11] & DRM_EDID_DSC_1P2; + hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2; if (hdmi_dsc->v_1p2) { - hdmi_dsc->native_420 = hf_vsdb[11] & DRM_EDID_DSC_NATIVE_420; - hdmi_dsc->all_bpp = hf_vsdb[11] & DRM_EDID_DSC_ALL_BPP; + hdmi_dsc->native_420 = hf_scds[11] & DRM_EDID_DSC_NATIVE_420; + hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP; - if (hf_vsdb[11] & DRM_EDID_DSC_16BPC) + if (hf_scds[11] & DRM_EDID_DSC_16BPC) hdmi_dsc->bpc_supported = 16; - else if (hf_vsdb[11] & DRM_EDID_DSC_12BPC) + else if (hf_scds[11] & DRM_EDID_DSC_12BPC) hdmi_dsc->bpc_supported = 12; - else if (hf_vsdb[11] & DRM_EDID_DSC_10BPC) + else if (hf_scds[11] & DRM_EDID_DSC_10BPC) hdmi_dsc->bpc_supported = 10; else hdmi_dsc->bpc_supported = 0; - dsc_max_frl_rate = (hf_vsdb[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; + dsc_max_frl_rate = (hf_scds[12] & DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4; drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes, &hdmi_dsc->max_frl_rate_per_lane); - hdmi_dsc->total_chunk_kbytes = hf_vsdb[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; + hdmi_dsc->total_chunk_kbytes = hf_scds[13] & DRM_EDID_DSC_TOTAL_CHUNK_KBYTES; - dsc_max_slices = hf_vsdb[12] & DRM_EDID_DSC_MAX_SLICES; + dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES; switch (dsc_max_slices) { case 1: hdmi_dsc->max_slices = 1; @@ -5243,7 +5244,7 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, } } - drm_parse_ycbcr420_deep_color_info(connector, hf_vsdb); + drm_parse_ycbcr420_deep_color_info(connector, hf_scds); } static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, @@ -5380,7 +5381,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, drm_parse_hdmi_vsdb_video(connector, db); if (cea_db_is_hdmi_forum_vsdb(db) || cea_db_is_hdmi_forum_scdb(db)) - drm_parse_hdmi_forum_vsdb(connector, db); + drm_parse_hdmi_forum_scds(connector, db); if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, db); if (cea_db_is_y420cmdb(db)) From 9d72b7e2d2ce3746950929a2c54171d183ea89f2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:49 +0300 Subject: [PATCH 004/170] drm/edid: clean up CTA data block tag definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add prefixed names, group, sort, add references. v2: - Updated references to CTA-861-H - s/CEA/CTA/ in data block macros Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/c66cc3adeb375f5e60d1a8f91b41580d8ab67442.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 65 ++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 18d05cbb2124..67eaa01f1d7c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3462,16 +3462,21 @@ add_detailed_modes(struct drm_connector *connector, const struct edid *edid, return closure.modes; } -#define AUDIO_BLOCK 0x01 -#define VIDEO_BLOCK 0x02 -#define VENDOR_BLOCK 0x03 -#define SPEAKER_BLOCK 0x04 -#define HDR_STATIC_METADATA_BLOCK 0x6 -#define USE_EXTENDED_TAG 0x07 -#define EXT_VIDEO_CAPABILITY_BLOCK 0x00 -#define EXT_VIDEO_DATA_BLOCK_420 0x0E -#define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F -#define EXT_VIDEO_HF_SCDB_DATA_BLOCK 0x79 +/* CTA-861-H Table 60 - CTA Tag Codes */ +#define CTA_DB_AUDIO 1 +#define CTA_DB_VIDEO 2 +#define CTA_DB_VENDOR 3 +#define CTA_DB_SPEAKER 4 +#define CTA_DB_EXTENDED_TAG 7 + +/* CTA-861-H Table 62 - CTA Extended Tag Codes */ +#define CTA_EXT_DB_VIDEO_CAP 0 +#define CTA_EXT_DB_VENDOR 1 +#define CTA_EXT_DB_HDR_STATIC_METADATA 6 +#define CTA_EXT_DB_420_VIDEO_DATA 14 +#define CTA_EXT_DB_420_VIDEO_CAP_MAP 15 +#define CTA_EXT_DB_HF_SCDB 0x79 + #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) @@ -4358,7 +4363,7 @@ cea_db_offsets(const u8 *cea, int *start, int *end) static bool cea_db_is_hdmi_vsdb(const u8 *db) { - if (cea_db_tag(db) != VENDOR_BLOCK) + if (cea_db_tag(db) != CTA_DB_VENDOR) return false; if (cea_db_payload_len(db) < 5) @@ -4369,7 +4374,7 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db) static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) { - if (cea_db_tag(db) != VENDOR_BLOCK) + if (cea_db_tag(db) != CTA_DB_VENDOR) return false; if (cea_db_payload_len(db) < 7) @@ -4380,7 +4385,7 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) static bool cea_db_is_microsoft_vsdb(const u8 *db) { - if (cea_db_tag(db) != VENDOR_BLOCK) + if (cea_db_tag(db) != CTA_DB_VENDOR) return false; if (cea_db_payload_len(db) != 21) @@ -4391,13 +4396,13 @@ static bool cea_db_is_microsoft_vsdb(const u8 *db) static bool cea_db_is_vcdb(const u8 *db) { - if (cea_db_tag(db) != USE_EXTENDED_TAG) + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) return false; if (cea_db_payload_len(db) != 2) return false; - if (cea_db_extended_tag(db) != EXT_VIDEO_CAPABILITY_BLOCK) + if (cea_db_extended_tag(db) != CTA_EXT_DB_VIDEO_CAP) return false; return true; @@ -4405,13 +4410,13 @@ static bool cea_db_is_vcdb(const u8 *db) static bool cea_db_is_hdmi_forum_scdb(const u8 *db) { - if (cea_db_tag(db) != USE_EXTENDED_TAG) + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) return false; if (cea_db_payload_len(db) < 7) return false; - if (cea_db_extended_tag(db) != EXT_VIDEO_HF_SCDB_DATA_BLOCK) + if (cea_db_extended_tag(db) != CTA_EXT_DB_HF_SCDB) return false; return true; @@ -4419,13 +4424,13 @@ static bool cea_db_is_hdmi_forum_scdb(const u8 *db) static bool cea_db_is_y420cmdb(const u8 *db) { - if (cea_db_tag(db) != USE_EXTENDED_TAG) + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) return false; if (!cea_db_payload_len(db)) return false; - if (cea_db_extended_tag(db) != EXT_VIDEO_CAP_BLOCK_Y420CMDB) + if (cea_db_extended_tag(db) != CTA_EXT_DB_420_VIDEO_CAP_MAP) return false; return true; @@ -4433,13 +4438,13 @@ static bool cea_db_is_y420cmdb(const u8 *db) static bool cea_db_is_y420vdb(const u8 *db) { - if (cea_db_tag(db) != USE_EXTENDED_TAG) + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) return false; if (!cea_db_payload_len(db)) return false; - if (cea_db_extended_tag(db) != EXT_VIDEO_DATA_BLOCK_420) + if (cea_db_extended_tag(db) != CTA_EXT_DB_420_VIDEO_DATA) return false; return true; @@ -4506,7 +4511,7 @@ add_cea_modes(struct drm_connector *connector, const struct edid *edid) db = &cea[i]; dbl = cea_db_payload_len(db); - if (cea_db_tag(db) == VIDEO_BLOCK) { + if (cea_db_tag(db) == CTA_DB_VIDEO) { video = db + 1; video_len = dbl; modes += do_cea_modes(connector, video, dbl); @@ -4580,10 +4585,10 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) static bool cea_db_is_hdmi_hdr_metadata_block(const u8 *db) { - if (cea_db_tag(db) != USE_EXTENDED_TAG) + if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) return false; - if (db[1] != HDR_STATIC_METADATA_BLOCK) + if (db[1] != CTA_EXT_DB_HDR_STATIC_METADATA) return false; if (cea_db_payload_len(db) < 3) @@ -4777,7 +4782,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, dbl = cea_db_payload_len(db); switch (cea_db_tag(db)) { - case AUDIO_BLOCK: + case CTA_DB_AUDIO: /* Audio Data Block, contains SADs */ sad_count = min(dbl / 3, 15 - total_sad_count); if (sad_count >= 1) @@ -4785,12 +4790,12 @@ static void drm_edid_to_eld(struct drm_connector *connector, &db[1], sad_count * 3); total_sad_count += sad_count; break; - case SPEAKER_BLOCK: + case CTA_DB_SPEAKER: /* Speaker Allocation Data Block */ if (dbl >= 1) eld[DRM_ELD_SPEAKER] = db[1]; break; - case VENDOR_BLOCK: + case CTA_DB_VENDOR: /* HDMI Vendor-Specific Data Block */ if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_audio(connector, db); @@ -4851,7 +4856,7 @@ int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) for_each_cea_db(cea, i, start, end) { const u8 *db = &cea[i]; - if (cea_db_tag(db) == AUDIO_BLOCK) { + if (cea_db_tag(db) == CTA_DB_AUDIO) { int j; dbl = cea_db_payload_len(db); @@ -4913,7 +4918,7 @@ int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb) for_each_cea_db(cea, i, start, end) { const u8 *db = &cea[i]; - if (cea_db_tag(db) == SPEAKER_BLOCK) { + if (cea_db_tag(db) == CTA_DB_SPEAKER) { dbl = cea_db_payload_len(db); /* Speaker Allocation Data Block */ @@ -5044,7 +5049,7 @@ bool drm_detect_monitor_audio(const struct edid *edid) goto end; for_each_cea_db(edid_ext, i, start_offset, end_offset) { - if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) { + if (cea_db_tag(&edid_ext[i]) == CTA_DB_AUDIO) { has_audio = true; for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3) DRM_DEBUG_KMS("CEA audio format %d\n", From 94afc5382669c3a201c5817c47b57a879b6dabce Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:50 +0300 Subject: [PATCH 005/170] drm/edid: add iterator for EDID base and extension blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an iterator abstraction for going through all the EDID blocks. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/ce02778b353b906c928268de9d7569d493a9be5d.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 67eaa01f1d7c..6d71b2b77639 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1599,6 +1599,54 @@ static const void *edid_extension_block_data(const struct edid *edid, int index) return edid_block_data(edid, index + 1); } +/* + * EDID base and extension block iterator. + * + * struct drm_edid_iter iter; + * const u8 *block; + * + * drm_edid_iter_begin(edid, &iter); + * drm_edid_iter_for_each(block, &iter) { + * // do stuff with block + * } + * drm_edid_iter_end(&iter); + */ +struct drm_edid_iter { + const struct edid *edid; + + /* Current block index. */ + int index; +}; + +static void drm_edid_iter_begin(const struct edid *edid, + struct drm_edid_iter *iter) +{ + memset(iter, 0, sizeof(*iter)); + + iter->edid = edid; +} + +static const void *__drm_edid_iter_next(struct drm_edid_iter *iter) +{ + const void *block = NULL; + + if (!iter->edid) + return NULL; + + if (iter->index < edid_block_count(iter->edid)) + block = edid_block_data(iter->edid, iter->index++); + + return block; +} + +#define drm_edid_iter_for_each(__block, __iter) \ + while (((__block) = __drm_edid_iter_next(__iter))) + +static void drm_edid_iter_end(struct drm_edid_iter *iter) +{ + memset(iter, 0, sizeof(*iter)); +} + static const u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; From aba5825439d7691343aa562dfeaf6616455bcb01 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:51 +0300 Subject: [PATCH 006/170] drm/edid: add iterator for CTA data blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an iterator for CTA Data Blocks across EDID CTA Extensions and DisplayID CTA Data Blocks. v2: Update references, note why we can trust displayid ranges (Ville) Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/37fdd2d9eabc73aaa9f95c56246dc47aea0e8e4e.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 202 ++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6d71b2b77639..da8f455b725e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4336,24 +4336,12 @@ out: return modes; } -static int -cea_db_payload_len(const u8 *db) -{ - return db[0] & 0x1f; -} - static int cea_db_extended_tag(const u8 *db) { return db[1]; } -static int -cea_db_tag(const u8 *db) -{ - return db[0] >> 5; -} - static int cea_revision(const u8 *cea) { @@ -4409,6 +4397,196 @@ cea_db_offsets(const u8 *cea, int *start, int *end) return 0; } +/* + * CTA Data Block iterator. + * + * Iterate through all CTA Data Blocks in both EDID CTA Extensions and DisplayID + * CTA Data Blocks. + * + * struct cea_db *db: + * struct cea_db_iter iter; + * + * cea_db_iter_edid_begin(edid, &iter); + * cea_db_iter_for_each(db, &iter) { + * // do stuff with db + * } + * cea_db_iter_end(&iter); + */ +struct cea_db_iter { + struct drm_edid_iter edid_iter; + struct displayid_iter displayid_iter; + + /* Current Data Block Collection. */ + const u8 *collection; + + /* Current Data Block index in current collection. */ + int index; + + /* End index in current collection. */ + int end; +}; + +/* CTA-861-H section 7.4 CTA Data BLock Collection */ +struct cea_db { + u8 tag_length; + u8 data[]; +} __packed; + +static int cea_db_tag(const void *_db) +{ + /* FIXME: Transition to passing struct cea_db * everywhere. */ + const struct cea_db *db = _db; + + return db->tag_length >> 5; +} + +static int cea_db_payload_len(const void *_db) +{ + /* FIXME: Transition to passing struct cea_db * everywhere. */ + const struct cea_db *db = _db; + + return db->tag_length & 0x1f; +} + +static const void *cea_db_data(const struct cea_db *db) +{ + return db->data; +} + +static void cea_db_iter_edid_begin(const struct edid *edid, struct cea_db_iter *iter) +{ + memset(iter, 0, sizeof(*iter)); + + drm_edid_iter_begin(edid, &iter->edid_iter); + displayid_iter_edid_begin(edid, &iter->displayid_iter); +} + +static const struct cea_db * +__cea_db_iter_current_block(const struct cea_db_iter *iter) +{ + const struct cea_db *db; + + if (!iter->collection) + return NULL; + + db = (const struct cea_db *)&iter->collection[iter->index]; + + if (iter->index + sizeof(*db) <= iter->end && + iter->index + sizeof(*db) + cea_db_payload_len(db) <= iter->end) + return db; + + return NULL; +} + +/* + * References: + * - VESA E-EDID v1.4 + * - CTA-861-H section 7.3.3 CTA Extension Version 3 + */ +static const void *__cea_db_iter_edid_next(struct cea_db_iter *iter) +{ + const u8 *ext; + + drm_edid_iter_for_each(ext, &iter->edid_iter) { + /* Only support CTA Extension revision 3+ */ + if (ext[0] != CEA_EXT || cea_revision(ext) < 3) + continue; + + iter->index = 4; + iter->end = ext[2]; + if (iter->end == 0) + iter->end = 127; + if (iter->end < 4 || iter->end > 127) + continue; + + return ext; + } + + return NULL; +} + +/* + * References: + * - DisplayID v1.3 Appendix C: CEA Data Block within a DisplayID Data Block + * - DisplayID v2.0 section 4.10 CTA DisplayID Data Block + * + * Note that the above do not specify any connection between DisplayID Data + * Block revision and CTA Extension versions. + */ +static const void *__cea_db_iter_displayid_next(struct cea_db_iter *iter) +{ + const struct displayid_block *block; + + displayid_iter_for_each(block, &iter->displayid_iter) { + if (block->tag != DATA_BLOCK_CTA) + continue; + + /* + * The displayid iterator has already verified the block bounds + * in displayid_iter_block(). + */ + iter->index = sizeof(*block); + iter->end = iter->index + block->num_bytes; + + return block; + } + + return NULL; +} + +static const struct cea_db *__cea_db_iter_next(struct cea_db_iter *iter) +{ + const struct cea_db *db; + + if (iter->collection) { + /* Current collection should always be valid. */ + db = __cea_db_iter_current_block(iter); + if (WARN_ON(!db)) { + iter->collection = NULL; + return NULL; + } + + /* Next block in CTA Data Block Collection */ + iter->index += sizeof(*db) + cea_db_payload_len(db); + + db = __cea_db_iter_current_block(iter); + if (db) + return db; + } + + for (;;) { + /* + * Find the next CTA Data Block Collection. First iterate all + * the EDID CTA Extensions, then all the DisplayID CTA blocks. + * + * Per DisplayID v1.3 Appendix B: DisplayID as an EDID + * Extension, it's recommended that DisplayID extensions are + * exposed after all of the CTA Extensions. + */ + iter->collection = __cea_db_iter_edid_next(iter); + if (!iter->collection) + iter->collection = __cea_db_iter_displayid_next(iter); + + if (!iter->collection) + return NULL; + + db = __cea_db_iter_current_block(iter); + if (db) + return db; + } +} + +#define cea_db_iter_for_each(__db, __iter) \ + while (((__db) = __cea_db_iter_next(__iter))) + +static void cea_db_iter_end(struct cea_db_iter *iter) +{ + displayid_iter_end(&iter->displayid_iter); + drm_edid_iter_end(&iter->edid_iter); + + memset(iter, 0, sizeof(*iter)); +} + static bool cea_db_is_hdmi_vsdb(const u8 *db) { if (cea_db_tag(db) != CTA_DB_VENDOR) From a9ec4fd004b84c26207a8cae41662c501c8a284b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:52 +0300 Subject: [PATCH 007/170] drm/edid: clean up cea_db_is_*() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract helpers for matching vendor data blocks and extended tags, and use them to simplify all the cea_db_is_*() functions. Take void pointer as parameter to allow transitional use for both u8 * and struct cea_db *. v2: Remove superfluous parens (Ville) Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/b6bb813afc35c763e744c6cdb4a787da3adf910b.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 127 ++++++++++++------------------------- 1 file changed, 40 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index da8f455b725e..b272671cf86c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4336,12 +4336,6 @@ out: return modes; } -static int -cea_db_extended_tag(const u8 *db) -{ - return db[1]; -} - static int cea_revision(const u8 *cea) { @@ -4453,6 +4447,22 @@ static const void *cea_db_data(const struct cea_db *db) return db->data; } +static bool cea_db_is_extended_tag(const struct cea_db *db, int tag) +{ + return cea_db_tag(db) == CTA_DB_EXTENDED_TAG && + cea_db_payload_len(db) >= 1 && + db->data[0] == tag; +} + +static bool cea_db_is_vendor(const struct cea_db *db, int vendor_oui) +{ + const u8 *data = cea_db_data(db); + + return cea_db_tag(db) == CTA_DB_VENDOR && + cea_db_payload_len(db) >= 3 && + oui(data[2], data[1], data[0]) == vendor_oui; +} + static void cea_db_iter_edid_begin(const struct edid *edid, struct cea_db_iter *iter) { memset(iter, 0, sizeof(*iter)); @@ -4587,93 +4597,50 @@ static void cea_db_iter_end(struct cea_db_iter *iter) memset(iter, 0, sizeof(*iter)); } -static bool cea_db_is_hdmi_vsdb(const u8 *db) +static bool cea_db_is_hdmi_vsdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_VENDOR) - return false; - - if (cea_db_payload_len(db) < 5) - return false; - - return oui(db[3], db[2], db[1]) == HDMI_IEEE_OUI; + return cea_db_is_vendor(db, HDMI_IEEE_OUI) && + cea_db_payload_len(db) >= 5; } -static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) +static bool cea_db_is_hdmi_forum_vsdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_VENDOR) - return false; - - if (cea_db_payload_len(db) < 7) - return false; - - return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI; + return cea_db_is_vendor(db, HDMI_FORUM_IEEE_OUI) && + cea_db_payload_len(db) >= 7; } -static bool cea_db_is_microsoft_vsdb(const u8 *db) +static bool cea_db_is_microsoft_vsdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_VENDOR) - return false; - - if (cea_db_payload_len(db) != 21) - return false; - - return oui(db[3], db[2], db[1]) == MICROSOFT_IEEE_OUI; + return cea_db_is_vendor(db, MICROSOFT_IEEE_OUI) && + cea_db_payload_len(db) == 21; } -static bool cea_db_is_vcdb(const u8 *db) +static bool cea_db_is_vcdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) - return false; - - if (cea_db_payload_len(db) != 2) - return false; - - if (cea_db_extended_tag(db) != CTA_EXT_DB_VIDEO_CAP) - return false; - - return true; + return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) && + cea_db_payload_len(db) == 2; } -static bool cea_db_is_hdmi_forum_scdb(const u8 *db) +static bool cea_db_is_hdmi_forum_scdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) - return false; - - if (cea_db_payload_len(db) < 7) - return false; - - if (cea_db_extended_tag(db) != CTA_EXT_DB_HF_SCDB) - return false; - - return true; + return cea_db_is_extended_tag(db, CTA_EXT_DB_HF_SCDB) && + cea_db_payload_len(db) >= 7; } -static bool cea_db_is_y420cmdb(const u8 *db) +static bool cea_db_is_y420cmdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) - return false; - - if (!cea_db_payload_len(db)) - return false; - - if (cea_db_extended_tag(db) != CTA_EXT_DB_420_VIDEO_CAP_MAP) - return false; - - return true; + return cea_db_is_extended_tag(db, CTA_EXT_DB_420_VIDEO_CAP_MAP); } -static bool cea_db_is_y420vdb(const u8 *db) +static bool cea_db_is_y420vdb(const void *db) { - if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) - return false; + return cea_db_is_extended_tag(db, CTA_EXT_DB_420_VIDEO_DATA); +} - if (!cea_db_payload_len(db)) - return false; - - if (cea_db_extended_tag(db) != CTA_EXT_DB_420_VIDEO_DATA) - return false; - - return true; +static bool cea_db_is_hdmi_hdr_metadata_block(const void *db) +{ + return cea_db_is_extended_tag(db, CTA_EXT_DB_HDR_STATIC_METADATA) && + cea_db_payload_len(db) >= 3; } #define for_each_cea_db(cea, i, start, end) \ @@ -4809,20 +4776,6 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) mode->clock = clock; } -static bool cea_db_is_hdmi_hdr_metadata_block(const u8 *db) -{ - if (cea_db_tag(db) != CTA_DB_EXTENDED_TAG) - return false; - - if (db[1] != CTA_EXT_DB_HDR_STATIC_METADATA) - return false; - - if (cea_db_payload_len(db) < 3) - return false; - - return true; -} - static uint8_t eotf_supported(const u8 *edid_ext) { return edid_ext[2] & From 537d9ed2f6c1dbfe8465365c2f74a855ffad5e6a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:53 +0300 Subject: [PATCH 008/170] drm/edid: convert add_cea_modes() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iterate through all CTA EDID extension blocks and DisplayID CTA data blocks to add CEA modes. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/dfa2d79db61d5eea543bef7aca7d80da3e71f99d.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 63 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b272671cf86c..5c3e2ed53012 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4689,46 +4689,41 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, static int add_cea_modes(struct drm_connector *connector, const struct edid *edid) { - const u8 *cea = drm_find_cea_extension(edid); - const u8 *db, *hdmi = NULL, *video = NULL; - u8 dbl, hdmi_len, video_len = 0; + const struct cea_db *db; + struct cea_db_iter iter; int modes = 0; - if (cea && cea_revision(cea) >= 3) { - int i, start, end; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + const u8 *hdmi = NULL, *video = NULL; + u8 hdmi_len = 0, video_len = 0; - if (cea_db_offsets(cea, &start, &end)) - return 0; + if (cea_db_tag(db) == CTA_DB_VIDEO) { + video = cea_db_data(db); + video_len = cea_db_payload_len(db); + modes += do_cea_modes(connector, video, video_len); + } else if (cea_db_is_hdmi_vsdb(db)) { + /* FIXME: Switch to use cea_db_data() */ + hdmi = (const u8 *)db; + hdmi_len = cea_db_payload_len(db); + } else if (cea_db_is_y420vdb(db)) { + const u8 *vdb420 = cea_db_data(db) + 1; - for_each_cea_db(cea, i, start, end) { - db = &cea[i]; - dbl = cea_db_payload_len(db); - - if (cea_db_tag(db) == CTA_DB_VIDEO) { - video = db + 1; - video_len = dbl; - modes += do_cea_modes(connector, video, dbl); - } else if (cea_db_is_hdmi_vsdb(db)) { - hdmi = db; - hdmi_len = dbl; - } else if (cea_db_is_y420vdb(db)) { - const u8 *vdb420 = &db[2]; - - /* Add 4:2:0(only) modes present in EDID */ - modes += do_y420vdb_modes(connector, - vdb420, - dbl - 1); - } + /* Add 4:2:0(only) modes present in EDID */ + modes += do_y420vdb_modes(connector, vdb420, + cea_db_payload_len(db) - 1); } - } - /* - * We parse the HDMI VSDB after having added the cea modes as we will - * be patching their flags when the sink supports stereo 3D. - */ - if (hdmi) - modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, - video_len); + /* + * We parse the HDMI VSDB after having added the cea modes as we + * will be patching their flags when the sink supports stereo + * 3D. + */ + if (hdmi) + modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, + video, video_len); + } + cea_db_iter_end(&iter); return modes; } From ed3173077d3fa6fd085960aa6347ec30f532bf31 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:54 +0300 Subject: [PATCH 009/170] drm/edid: convert drm_edid_to_speaker_allocation() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the cea db iterator for speaker allocation. We'll still stop at the first speaker data block, but not at the first CTA extension if that doesn't have the info. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/0b9e7f136854055a14b826097160fe0b43b9f3d1.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 47 ++++++++++++-------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5c3e2ed53012..7d6bf0b2bd9e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5069,42 +5069,25 @@ EXPORT_SYMBOL(drm_edid_to_sad); */ int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb) { + const struct cea_db *db; + struct cea_db_iter iter; int count = 0; - int i, start, end, dbl; - const u8 *cea; - cea = drm_find_cea_extension(edid); - if (!cea) { - DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); - return 0; - } - - if (cea_revision(cea) < 3) { - DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); - return 0; - } - - if (cea_db_offsets(cea, &start, &end)) { - DRM_DEBUG_KMS("SAD: invalid data block offsets\n"); - return -EPROTO; - } - - for_each_cea_db(cea, i, start, end) { - const u8 *db = &cea[i]; - - if (cea_db_tag(db) == CTA_DB_SPEAKER) { - dbl = cea_db_payload_len(db); - - /* Speaker Allocation Data Block */ - if (dbl == 3) { - *sadb = kmemdup(&db[1], dbl, GFP_KERNEL); - if (!*sadb) - return -ENOMEM; - count = dbl; - break; - } + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + if (cea_db_tag(db) == CTA_DB_SPEAKER && + cea_db_payload_len(db) == 3) { + *sadb = kmemdup(db->data, cea_db_payload_len(db), + GFP_KERNEL); + if (!*sadb) + return -ENOMEM; + count = cea_db_payload_len(db); + break; } } + cea_db_iter_end(&iter); + + DRM_DEBUG_KMS("Found %d Speaker Allocation Data Blocks\n", count); return count; } From b07debc2a8ce7324c85479a28d145eaa05382286 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:55 +0300 Subject: [PATCH 010/170] drm/edid: convert drm_edid_to_sad() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the cea db iterator for short audio descriptors. We'll still stop at the first audio data block, but not at the first CTA Extension if that doesn't have the info. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/237e4b1de1567903d37ce1d1bb830020b8fd6690.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7d6bf0b2bd9e..1ea27278652b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5007,40 +5007,21 @@ static void drm_edid_to_eld(struct drm_connector *connector, */ int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) { + const struct cea_db *db; + struct cea_db_iter iter; int count = 0; - int i, start, end, dbl; - const u8 *cea; - - cea = drm_find_cea_extension(edid); - if (!cea) { - DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); - return 0; - } - - if (cea_revision(cea) < 3) { - DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); - return 0; - } - - if (cea_db_offsets(cea, &start, &end)) { - DRM_DEBUG_KMS("SAD: invalid data block offsets\n"); - return -EPROTO; - } - - for_each_cea_db(cea, i, start, end) { - const u8 *db = &cea[i]; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { int j; - dbl = cea_db_payload_len(db); - - count = dbl / 3; /* SAD is 3B */ + count = cea_db_payload_len(db) / 3; /* SAD is 3B */ *sads = kcalloc(count, sizeof(**sads), GFP_KERNEL); if (!*sads) return -ENOMEM; for (j = 0; j < count; j++) { - const u8 *sad = &db[1 + j * 3]; + const u8 *sad = &db->data[j * 3]; (*sads)[j].format = (sad[0] & 0x78) >> 3; (*sads)[j].channels = sad[0] & 0x7; @@ -5050,6 +5031,9 @@ int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) break; } } + cea_db_iter_end(&iter); + + DRM_DEBUG_KMS("Found %d Short Audio Descriptors\n", count); return count; } From 4ce08703a8c4be77b060aefd14eda272f50a45e4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:56 +0300 Subject: [PATCH 011/170] drm/edid: convert drm_detect_hdmi_monitor() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iterate through all CTA data blocks, not just the first CTA extension. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/b867e7b628189d2f8fa7eac5b9aa701892724711.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1ea27278652b..ca594d502941 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5131,27 +5131,24 @@ EXPORT_SYMBOL(drm_av_sync_delay); */ bool drm_detect_hdmi_monitor(const struct edid *edid) { - const u8 *edid_ext; - int i; - int start_offset, end_offset; - - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return false; - - if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) - return false; + const struct cea_db *db; + struct cea_db_iter iter; + bool hdmi = false; /* * Because HDMI identifier is in Vendor Specific Block, * search it from all data blocks of CEA extension. */ - for_each_cea_db(edid_ext, i, start_offset, end_offset) { - if (cea_db_is_hdmi_vsdb(&edid_ext[i])) - return true; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + if (cea_db_is_hdmi_vsdb(db)) { + hdmi = true; + break; + } } + cea_db_iter_end(&iter); - return false; + return hdmi; } EXPORT_SYMBOL(drm_detect_hdmi_monitor); From 9975af040a04ba9aef33f3ef1ca4e8f04c7223dd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:57 +0300 Subject: [PATCH 012/170] drm/edid: convert drm_detect_monitor_audio() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iterate through all CEA data blocks. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a7f0c380da9526f8dd6f758d7a748bca7b4da6ce.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ca594d502941..3433d9fa4799 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5166,10 +5166,10 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor); */ bool drm_detect_monitor_audio(const struct edid *edid) { + const struct cea_db *db; + struct cea_db_iter iter; const u8 *edid_ext; - int i, j; bool has_audio = false; - int start_offset, end_offset; edid_ext = drm_find_cea_extension(edid); if (!edid_ext) @@ -5183,18 +5183,21 @@ bool drm_detect_monitor_audio(const struct edid *edid) goto end; } - if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) - goto end; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + if (cea_db_tag(db) == CTA_DB_AUDIO) { + const u8 *data = cea_db_data(db); + int i; - for_each_cea_db(edid_ext, i, start_offset, end_offset) { - if (cea_db_tag(&edid_ext[i]) == CTA_DB_AUDIO) { - has_audio = true; - for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3) + for (i = 0; i < cea_db_payload_len(db); i += 3) DRM_DEBUG_KMS("CEA audio format %d\n", - (edid_ext[i + j] >> 3) & 0xf); - goto end; + (data[i] >> 3) & 0xf); + has_audio = true; + break; } } + cea_db_iter_end(&iter); + end: return has_audio; } From dfc0312596561ac462308fae32130a0c580b7ac1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:58 +0300 Subject: [PATCH 013/170] drm/edid: convert drm_parse_cea_ext() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iterate through all CTA data blocks across all CTA Extensions and DisplayID data blocks. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/7400792525c13f58652f288b891d6057637ed4c8.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3433d9fa4799..98b2e6164468 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5497,8 +5497,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector, const struct edid *edid) { struct drm_display_info *info = &connector->display_info; + const struct cea_db *db; + struct cea_db_iter iter; const u8 *edid_ext; - int i, start, end; edid_ext = drm_find_cea_extension(edid); if (!edid_ext) @@ -5517,26 +5518,26 @@ static void drm_parse_cea_ext(struct drm_connector *connector, info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; } - if (cea_db_offsets(edid_ext, &start, &end)) - return; - - for_each_cea_db(edid_ext, i, start, end) { - const u8 *db = &edid_ext[i]; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + /* FIXME: convert parsers to use struct cea_db */ + const u8 *data = (const u8 *)db; if (cea_db_is_hdmi_vsdb(db)) - drm_parse_hdmi_vsdb_video(connector, db); + drm_parse_hdmi_vsdb_video(connector, data); if (cea_db_is_hdmi_forum_vsdb(db) || cea_db_is_hdmi_forum_scdb(db)) - drm_parse_hdmi_forum_scds(connector, db); + drm_parse_hdmi_forum_scds(connector, data); if (cea_db_is_microsoft_vsdb(db)) - drm_parse_microsoft_vsdb(connector, db); + drm_parse_microsoft_vsdb(connector, data); if (cea_db_is_y420cmdb(db)) - drm_parse_y420cmdb_bitmap(connector, db); + drm_parse_y420cmdb_bitmap(connector, data); if (cea_db_is_vcdb(db)) - drm_parse_vcdb(connector, db); + drm_parse_vcdb(connector, data); if (cea_db_is_hdmi_hdr_metadata_block(db)) - drm_parse_hdr_metadata_block(connector, db); + drm_parse_hdr_metadata_block(connector, data); } + cea_db_iter_end(&iter); } static From 37852141965d467a4ae118139b6eee266e7d953c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:23:59 +0300 Subject: [PATCH 014/170] drm/edid: convert drm_edid_to_eld() to use cea db iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iterate through all CTA data blocks across all CTA extensions and DisplayID data blocks. This may gather more data than before, and if there's duplicated data, some is overwritten by whichever comes last. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/8bdc67aa731857111eddd08a9c192d41d40b5f5a.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 64 +++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 98b2e6164468..77986895e501 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4911,12 +4911,12 @@ static void clear_eld(struct drm_connector *connector) static void drm_edid_to_eld(struct drm_connector *connector, const struct edid *edid) { + const struct cea_db *db; + struct cea_db_iter iter; uint8_t *eld = connector->eld; const u8 *cea; - const u8 *db; int total_sad_count = 0; int mnl; - int dbl; clear_eld(connector); @@ -4942,43 +4942,37 @@ static void drm_edid_to_eld(struct drm_connector *connector, eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0]; eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1]; - if (cea_revision(cea) >= 3) { - int i, start, end; + cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_for_each(db, &iter) { + const u8 *data = cea_db_data(db); + int len = cea_db_payload_len(db); int sad_count; - if (cea_db_offsets(cea, &start, &end)) { - start = 0; - end = 0; - } - - for_each_cea_db(cea, i, start, end) { - db = &cea[i]; - dbl = cea_db_payload_len(db); - - switch (cea_db_tag(db)) { - case CTA_DB_AUDIO: - /* Audio Data Block, contains SADs */ - sad_count = min(dbl / 3, 15 - total_sad_count); - if (sad_count >= 1) - memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)], - &db[1], sad_count * 3); - total_sad_count += sad_count; - break; - case CTA_DB_SPEAKER: - /* Speaker Allocation Data Block */ - if (dbl >= 1) - eld[DRM_ELD_SPEAKER] = db[1]; - break; - case CTA_DB_VENDOR: - /* HDMI Vendor-Specific Data Block */ - if (cea_db_is_hdmi_vsdb(db)) - drm_parse_hdmi_vsdb_audio(connector, db); - break; - default: - break; - } + switch (cea_db_tag(db)) { + case CTA_DB_AUDIO: + /* Audio Data Block, contains SADs */ + sad_count = min(len / 3, 15 - total_sad_count); + if (sad_count >= 1) + memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)], + data, sad_count * 3); + total_sad_count += sad_count; + break; + case CTA_DB_SPEAKER: + /* Speaker Allocation Data Block */ + if (len >= 1) + eld[DRM_ELD_SPEAKER] = data[0]; + break; + case CTA_DB_VENDOR: + /* HDMI Vendor-Specific Data Block */ + if (cea_db_is_hdmi_vsdb(db)) + drm_parse_hdmi_vsdb_audio(connector, (const u8 *)db); + break; + default: + break; } } + cea_db_iter_end(&iter); + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= total_sad_count << DRM_ELD_SAD_COUNT_SHIFT; if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || From 2af243444f9100639451b11d311982279e00cc16 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:24:00 +0300 Subject: [PATCH 015/170] drm/edid: sunset the old unused cea data block iterators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All CTA data block iteration has now been converted to the new cea db iterators. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a5b35ed0e711bd874f76ae87ee0b70150d0a77c4.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 45 -------------------------------------- 1 file changed, 45 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 77986895e501..208b1efb490d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4349,48 +4349,6 @@ cea_revision(const u8 *cea) return cea[1]; } -static int -cea_db_offsets(const u8 *cea, int *start, int *end) -{ - /* DisplayID CTA extension blocks and top-level CEA EDID - * block header definitions differ in the following bytes: - * 1) Byte 2 of the header specifies length differently, - * 2) Byte 3 is only present in the CEA top level block. - * - * The different definitions for byte 2 follow. - * - * DisplayID CTA extension block defines byte 2 as: - * Number of payload bytes - * - * CEA EDID block defines byte 2 as: - * Byte number (decimal) within this block where the 18-byte - * DTDs begin. If no non-DTD data is present in this extension - * block, the value should be set to 04h (the byte after next). - * If set to 00h, there are no DTDs present in this block and - * no non-DTD data. - */ - if (cea[0] == DATA_BLOCK_CTA) { - /* - * for_each_displayid_db() has already verified - * that these stay within expected bounds. - */ - *start = 3; - *end = *start + cea[2]; - } else if (cea[0] == CEA_EXT) { - /* Data block offset in CEA extension block */ - *start = 4; - *end = cea[2]; - if (*end == 0) - *end = 127; - if (*end < 4 || *end > 127) - return -ERANGE; - } else { - return -EOPNOTSUPP; - } - - return 0; -} - /* * CTA Data Block iterator. * @@ -4643,9 +4601,6 @@ static bool cea_db_is_hdmi_hdr_metadata_block(const void *db) cea_db_payload_len(db) >= 3; } -#define for_each_cea_db(cea, i, start, end) \ - for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) - static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, const u8 *db) { From 49a62a2923e523e5359219ed54d643c60f3374f8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:24:01 +0300 Subject: [PATCH 016/170] drm/edid: restore some type safety to cea_db_*() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the transition, we accepted a void pointer for a poor C programmer's version of polymorphism. Switch the functions to use struct cea_db * to regain some more type safety. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/c6ad496cdadea1bb598711a65ef536f4a43b74a7.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 208b1efb490d..bc12ede8694c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4384,11 +4384,8 @@ struct cea_db { u8 data[]; } __packed; -static int cea_db_tag(const void *_db) +static int cea_db_tag(const struct cea_db *db) { - /* FIXME: Transition to passing struct cea_db * everywhere. */ - const struct cea_db *db = _db; - return db->tag_length >> 5; } @@ -4555,47 +4552,47 @@ static void cea_db_iter_end(struct cea_db_iter *iter) memset(iter, 0, sizeof(*iter)); } -static bool cea_db_is_hdmi_vsdb(const void *db) +static bool cea_db_is_hdmi_vsdb(const struct cea_db *db) { return cea_db_is_vendor(db, HDMI_IEEE_OUI) && cea_db_payload_len(db) >= 5; } -static bool cea_db_is_hdmi_forum_vsdb(const void *db) +static bool cea_db_is_hdmi_forum_vsdb(const struct cea_db *db) { return cea_db_is_vendor(db, HDMI_FORUM_IEEE_OUI) && cea_db_payload_len(db) >= 7; } -static bool cea_db_is_microsoft_vsdb(const void *db) +static bool cea_db_is_microsoft_vsdb(const struct cea_db *db) { return cea_db_is_vendor(db, MICROSOFT_IEEE_OUI) && cea_db_payload_len(db) == 21; } -static bool cea_db_is_vcdb(const void *db) +static bool cea_db_is_vcdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_VIDEO_CAP) && cea_db_payload_len(db) == 2; } -static bool cea_db_is_hdmi_forum_scdb(const void *db) +static bool cea_db_is_hdmi_forum_scdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_HF_SCDB) && cea_db_payload_len(db) >= 7; } -static bool cea_db_is_y420cmdb(const void *db) +static bool cea_db_is_y420cmdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_420_VIDEO_CAP_MAP); } -static bool cea_db_is_y420vdb(const void *db) +static bool cea_db_is_y420vdb(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_420_VIDEO_DATA); } -static bool cea_db_is_hdmi_hdr_metadata_block(const void *db) +static bool cea_db_is_hdmi_hdr_metadata_block(const struct cea_db *db) { return cea_db_is_extended_tag(db, CTA_EXT_DB_HDR_STATIC_METADATA) && cea_db_payload_len(db) >= 3; From 705bec3eca9b712fe006b7e4d6b4cd4dc6b57d36 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:24:02 +0300 Subject: [PATCH 017/170] drm/edid: detect basic audio in all CEA extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert drm_find_cea_extension() to EDID block iterator in basic audio detection. Detect basic audio in all CEA extensions. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/59481d0397de4b91b3e6ea665882334e92538f40.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bc12ede8694c..3b18a6e501df 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5112,17 +5112,21 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor); */ bool drm_detect_monitor_audio(const struct edid *edid) { + struct drm_edid_iter edid_iter; const struct cea_db *db; struct cea_db_iter iter; const u8 *edid_ext; bool has_audio = false; - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - goto end; - - has_audio = (edid_ext[0] == CEA_EXT && - (edid_ext[3] & EDID_BASIC_AUDIO) != 0); + drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_for_each(edid_ext, &edid_iter) { + if (edid_ext[0] == CEA_EXT) { + has_audio = edid_ext[3] & EDID_BASIC_AUDIO; + if (has_audio) + break; + } + } + drm_edid_iter_end(&edid_iter); if (has_audio) { DRM_DEBUG_KMS("Monitor has basic audio support\n"); From 8db73897698ccb4eb70ab103245372569ff5a5ec Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 5 May 2022 13:52:42 +0300 Subject: [PATCH 018/170] drm/edid: detect color formats and CTA revision in all CTA extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert drm_find_cea_extension() to EDID block iterator in color format and CTA revision detection. Detect them in all CTA extensions. Also parse CTA Data Blocks in DisplayID even if there's no CTA EDID extension. v2: - Don't assume DRM_COLOR_FORMAT_RGB444 support if there's only DisplayID CTA Data Blocks (Ville) Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220505105242.1198521-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3b18a6e501df..8d737322145c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5447,26 +5447,31 @@ static void drm_parse_cea_ext(struct drm_connector *connector, const struct edid *edid) { struct drm_display_info *info = &connector->display_info; + struct drm_edid_iter edid_iter; const struct cea_db *db; struct cea_db_iter iter; const u8 *edid_ext; - edid_ext = drm_find_cea_extension(edid); - if (!edid_ext) - return; + drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_for_each(edid_ext, &edid_iter) { + if (edid_ext[0] != CEA_EXT) + continue; - info->cea_rev = edid_ext[1]; + if (!info->cea_rev) + info->cea_rev = edid_ext[1]; - /* The existence of a CEA block should imply RGB support */ - info->color_formats = DRM_COLOR_FORMAT_RGB444; + if (info->cea_rev != edid_ext[1]) + DRM_DEBUG_KMS("CEA extension version mismatch %u != %u\n", + info->cea_rev, edid_ext[1]); - /* CTA DisplayID Data Block does not have byte #3 */ - if (edid_ext[0] == CEA_EXT) { + /* The existence of a CTA extension should imply RGB support */ + info->color_formats = DRM_COLOR_FORMAT_RGB444; if (edid_ext[3] & EDID_CEA_YCRCB444) info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; if (edid_ext[3] & EDID_CEA_YCRCB422) info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; } + drm_edid_iter_end(&edid_iter); cea_db_iter_edid_begin(edid, &iter); cea_db_iter_for_each(db, &iter) { From 58304630b830a1c27457ce2e3a0912555b43d03e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:24:04 +0300 Subject: [PATCH 019/170] drm/edid: skip CTA extension scan in drm_edid_to_eld() just for CTA rev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DisplayID CTA data block version does not necessarily match the CTA revision. Simplify by postponing drm_edid_to_eld() slightly, and reusing the CTA revision extracted by drm_parse_cea_ext(). By not bailing out early in drm_edid_to_eld() we may end up filling meaningless data to the ELD. However, the main decision for audio is not the ELD, but rather drm_detect_monitor_audio() called by drivers. (Arguably a future cleanup could do that in drm_add_edid_modes() and cache the result in the connector.) Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/163ebbfd765066acbfc267256fb3b67fc711a78d.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8d737322145c..2e52be67eadf 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4863,10 +4863,10 @@ static void clear_eld(struct drm_connector *connector) static void drm_edid_to_eld(struct drm_connector *connector, const struct edid *edid) { + const struct drm_display_info *info = &connector->display_info; const struct cea_db *db; struct cea_db_iter iter; uint8_t *eld = connector->eld; - const u8 *cea; int total_sad_count = 0; int mnl; @@ -4875,16 +4875,10 @@ static void drm_edid_to_eld(struct drm_connector *connector, if (!edid) return; - cea = drm_find_cea_extension(edid); - if (!cea) { - DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); - return; - } - mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); - eld[DRM_ELD_CEA_EDID_VER_MNL] = cea[1] << DRM_ELD_CEA_EDID_VER_SHIFT; + eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT; eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D; @@ -5821,8 +5815,6 @@ static int drm_edid_connector_update(struct drm_connector *connector, return 0; } - drm_edid_to_eld(connector, edid); - /* * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. * To avoid multiple parsing of same block, lets parse that map @@ -5830,6 +5822,9 @@ static int drm_edid_connector_update(struct drm_connector *connector, */ quirks = drm_add_display_info(connector, edid); + /* Depends on info->cea_rev set by drm_add_display_info() above */ + drm_edid_to_eld(connector, edid); + /* * EDID spec says modes should be preferred in this order: * - preferred detailed mode From 6ff1c19f5f28dbc396462032dcbfdb8b64795415 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 3 May 2022 12:24:05 +0300 Subject: [PATCH 020/170] drm/edid: sunset drm_find_cea_extension() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert drm_find_cea_extension() to a predicate function to check if the EDID has a CTA extension or a DisplayID CTA data block. This is mainly to avoid adding new users that only find the first CTA extension. Cc: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a5bf228942e6bd0fc70d5cf7a14c249a14a7afcd.1651569697.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2e52be67eadf..47d121e99201 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3558,30 +3558,29 @@ const u8 *drm_find_edid_extension(const struct edid *edid, return edid_ext; } -static const u8 *drm_find_cea_extension(const struct edid *edid) +/* Return true if the EDID has a CTA extension or a DisplayID CTA data block */ +static bool drm_edid_has_cta_extension(const struct edid *edid) { const struct displayid_block *block; struct displayid_iter iter; - const u8 *cea; int ext_index = 0; + bool found = false; /* Look for a top level CEA extension block */ - /* FIXME: make callers iterate through multiple CEA ext blocks? */ - cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); - if (cea) - return cea; + if (drm_find_edid_extension(edid, CEA_EXT, &ext_index)) + return true; /* CEA blocks can also be found embedded in a DisplayID block */ displayid_iter_edid_begin(edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_CTA) { - cea = (const u8 *)block; + found = true; break; } } displayid_iter_end(&iter); - return cea; + return found; } static __always_inline const struct drm_display_mode *cea_mode_for_vic(u8 vic) @@ -3854,8 +3853,8 @@ add_alternate_cea_modes(struct drm_connector *connector, const struct edid *edid LIST_HEAD(list); int modes = 0; - /* Don't add CEA modes if the CEA extension block is missing */ - if (!drm_find_cea_extension(edid)) + /* Don't add CTA modes if the CTA extension block is missing */ + if (!drm_edid_has_cta_extension(edid)) return 0; /* From d792ec62ae1260df2e54dc41103aad3b19bad948 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 5 May 2022 16:13:45 +0800 Subject: [PATCH 021/170] drm/nouveau/gr/gf100-: Clean up some inconsistent indenting Eliminate the follow smatch warning: drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c:1925 gf100_gr_oneinit_tiles() warn: inconsistent indenting. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220505081345.89762-1-jiapeng.chong@linux.alibaba.com --- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 397ff4fe9df8..f16eabf4f642 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1922,8 +1922,8 @@ gf100_gr_oneinit_tiles(struct gf100_gr *gr) for (i = 0; i < gr->gpc_nr; i++) { init_frac[i] = gr->tpc_nr[gpc_map[i]] * gr->gpc_nr * mul_factor; - init_err[i] = i * gr->tpc_max * mul_factor - comm_denom/2; - run_err[i] = init_frac[i] + init_err[i]; + init_err[i] = i * gr->tpc_max * mul_factor - comm_denom/2; + run_err[i] = init_frac[i] + init_err[i]; } for (i = 0; i < gr->tpc_total;) { From 69ed3dd6be9cf5d75252940b9a927dff4bab7860 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Tue, 19 Apr 2022 09:08:48 +0800 Subject: [PATCH 022/170] drm/bridge: nwl-dsi: Set PHY mode in nwl_dsi_mode_set() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Northwest Logic MIPI DSI host controller embedded in i.MX8qxp works with a Mixel MIPI DPHY + LVDS PHY combo to support either a MIPI DSI display or a LVDS display. So, this patch calls phy_set_mode() from nwl_dsi_mode_set() to set PHY mode to MIPI DPHY explicitly. Cc: Guido Günther Cc: Robert Chiras Cc: Martin Kepplinger Cc: Andrzej Hajda Cc: Neil Armstrong Cc: Laurent Pinchart Cc: Jonas Karlman Cc: Jernej Skrabec Cc: David Airlie Cc: Daniel Vetter Cc: NXP Linux Team Signed-off-by: Liu Ying Acked-by: Robert Foss Reviewed-by: Guido Günther Signed-off-by: Guido Günther Link: https://patchwork.freedesktop.org/patch/msgid/20220419010852.452169-2-victor.liu@nxp.com --- drivers/gpu/drm/bridge/nwl-dsi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index ad74e6558eb3..d83111be4829 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -665,6 +665,12 @@ static int nwl_dsi_mode_set(struct nwl_dsi *dsi) return ret; } + ret = phy_set_mode(dsi->phy, PHY_MODE_MIPI_DPHY); + if (ret < 0) { + DRM_DEV_ERROR(dev, "Failed to set DSI phy mode: %d\n", ret); + goto uninit_phy; + } + ret = phy_configure(dsi->phy, phy_cfg); if (ret < 0) { DRM_DEV_ERROR(dev, "Failed to configure DSI phy: %d\n", ret); From 16c8d76abe83d75b578d72ee22d25a52c764e14a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 4 May 2022 03:26:01 +0200 Subject: [PATCH 023/170] dt-bindings: display: bridge: ldb: Fill in reg property Add missing reg and reg-names properties for both 'LDB_CTRL' and 'LVDS_CTRL' registers. Fixes: 463db5c2ed4ae ("drm: bridge: ldb: Implement simple Freescale i.MX8MP LDB bridge") Signed-off-by: Marek Vasut Cc: Laurent Pinchart Cc: Lucas Stach Cc: Maxime Ripard Cc: Peng Fan Cc: Rob Herring Cc: Robby Cai Cc: Robert Foss Cc: Sam Ravnborg Cc: Thomas Zimmermann Cc: devicetree@vger.kernel.org To: dri-devel@lists.freedesktop.org Reviewed-by: Rob Herring Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220504012601.423644-1-marex@denx.de --- .../bindings/display/bridge/fsl,ldb.yaml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/fsl,ldb.yaml b/Documentation/devicetree/bindings/display/bridge/fsl,ldb.yaml index 77f174eee424..2ebaa43eb62e 100644 --- a/Documentation/devicetree/bindings/display/bridge/fsl,ldb.yaml +++ b/Documentation/devicetree/bindings/display/bridge/fsl,ldb.yaml @@ -24,6 +24,15 @@ properties: clock-names: const: ldb + reg: + minItems: 2 + maxItems: 2 + + reg-names: + items: + - const: ldb + - const: lvds + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -56,10 +65,15 @@ examples: #include blk-ctrl { - bridge { + #address-cells = <1>; + #size-cells = <1>; + + bridge@5c { compatible = "fsl,imx8mp-ldb"; clocks = <&clk IMX8MP_CLK_MEDIA_LDB>; clock-names = "ldb"; + reg = <0x5c 0x4>, <0x128 0x4>; + reg-names = "ldb", "lvds"; ports { #address-cells = <1>; From 0b752df77633cc4c3606a6187e3ad37ad6925c15 Mon Sep 17 00:00:00 2001 From: Ren Zhijie Date: Sat, 7 May 2022 18:09:10 +0800 Subject: [PATCH 024/170] drm/rockchip: Fix Kconfig dependencies for display-port encoders The DP-helper module has been replaced by the display-helper module. So the driver have to select it. Reported-by: Hulk Robot Fixes: 1e0f66420b13("drm/display: Introduce a DRM display-helper module") Signed-off-by: Ren Zhijie Reviewed-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220507100910.93705-1-renzhijie2@huawei.com --- drivers/gpu/drm/rockchip/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 5afab49dc4f2..53c2d9980d48 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -2,7 +2,6 @@ config DRM_ROCKCHIP tristate "DRM Support for Rockchip" depends on DRM && ROCKCHIP_IOMMU - select DRM_DISPLAY_HELPER if ROCKCHIP_ANALOGIX_DP select DRM_GEM_CMA_HELPER select DRM_KMS_HELPER select DRM_PANEL @@ -38,6 +37,7 @@ config ROCKCHIP_VOP2 config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver" depends on ROCKCHIP_VOP + select DRM_DISPLAY_HELPER select DRM_DISPLAY_DP_HELPER help This selects support for Rockchip SoC specific extensions @@ -47,6 +47,8 @@ config ROCKCHIP_ANALOGIX_DP config ROCKCHIP_CDN_DP bool "Rockchip cdn DP" depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m) + select DRM_DISPLAY_HELPER + select DRM_DISPLAY_DP_HELPER help This selects support for Rockchip SoC specific extensions for the cdn DP driver. If you want to enable Dp on From 813bb91da10bb6638dfadad73f2f0a5f9883946b Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 6 May 2022 07:26:59 +0800 Subject: [PATCH 025/170] drm/rockchip: remove unneeded semicolon from vop2 driver Eliminate the following coccicheck warning: ./drivers/gpu/drm/rockchip/rockchip_drm_vop2.c:1476:2-3: Unneeded semicolon Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220505232659.4405-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 0b49fed16535..7f9d88634a77 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1473,7 +1473,7 @@ static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, default: drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id); return; - }; + } dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD; From f0eaf60c67738da8aae786bda74a2fffeca6d7cc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 May 2022 12:10:44 +0100 Subject: [PATCH 026/170] drm/rockchip: Fix spelling mistake "aligened" -> "aligned" There is a spelling mistake in a drm_err message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220505111044.374174-1-colin.i.king@gmail.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7f9d88634a77..774d8bee22b1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1202,7 +1202,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, */ stride = (fb->pitches[0] << 3) / bpp; if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270)) - drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligened\n", + drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n", vp->id, win->data->name, stride); rb_swap = vop2_afbc_rb_swap(fb->format->format); From 3507932390bbfcf7c69dff9843f1c9da6ed4b861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 18 Feb 2022 10:05:40 +0100 Subject: [PATCH 027/170] drm/ttm: move default BO destructor into VMWGFX v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's the only driver using this. v2: use BUG_ON() in vmw_bo_create() as suggested by Zack Signed-off-by: Christian König Reviewed-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20220329110243.6335-5-christian.koenig@amd.com --- drivers/gpu/drm/ttm/ttm_bo.c | 9 +-------- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 10 +++++++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 75d308ec173d..296af2b89951 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -44,12 +44,6 @@ #include "ttm_module.h" -/* default destructor */ -static void ttm_bo_default_destroy(struct ttm_buffer_object *bo) -{ - kfree(bo); -} - static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, struct ttm_placement *placement) { @@ -936,8 +930,7 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, bool locked; int ret; - bo->destroy = destroy ? destroy : ttm_bo_default_destroy; - + bo->destroy = destroy; kref_init(&bo->kref); INIT_LIST_HEAD(&bo->ddestroy); bo->bdev = bdev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index eb94433067ba..85a66014c2b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -393,6 +393,12 @@ void vmw_bo_bo_free(struct ttm_buffer_object *bo) kfree(vmw_bo); } +/* default destructor */ +static void vmw_bo_default_destroy(struct ttm_buffer_object *bo) +{ + kfree(bo); +} + /** * vmw_bo_create_kernel - Create a pinned BO for internal kernel use. * @@ -425,7 +431,7 @@ int vmw_bo_create_kernel(struct vmw_private *dev_priv, unsigned long size, ret = ttm_bo_init_reserved(&dev_priv->bdev, bo, size, ttm_bo_type_kernel, placement, 0, - &ctx, NULL, NULL, NULL); + &ctx, NULL, NULL, vmw_bo_default_destroy); if (unlikely(ret)) goto error_free; @@ -448,6 +454,8 @@ int vmw_bo_create(struct vmw_private *vmw, { int ret; + BUG_ON(!bo_free); + *p_bo = kmalloc(sizeof(**p_bo), GFP_KERNEL); if (unlikely(!*p_bo)) { DRM_ERROR("Failed to allocate a buffer.\n"); From 6c01aa13894fa0049ea8c96c271318ca353a77f1 Mon Sep 17 00:00:00 2001 From: Yuanzheng Song Date: Thu, 28 Apr 2022 06:39:24 +0000 Subject: [PATCH 028/170] dma-buf: add the name field to the table header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'cat /sys/kernel/debug/dma_buf/bufinfo' will print the Dma-buf Objects' information when the CONFIG_DEBUG_FS=y. However, the printed table header information does not contain the name field. So we need to add the name field to the table header and use the '' to replace the empty buf_obj->name. Signed-off-by: Yuanzheng Song Reviewed-by: Christian König Signed-off-by: Sumit Semwal Link: https://patchwork.freedesktop.org/patch/msgid/20220428063924.3570409-1-songyuanzheng@huawei.com --- drivers/dma-buf/dma-buf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 79795857be3e..a2f9a1815e38 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1351,7 +1351,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) return ret; seq_puts(s, "\nDma-buf Objects:\n"); - seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n", + seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\tname\n", "size", "flags", "mode", "count", "ino"); list_for_each_entry(buf_obj, &db_list.head, list_node) { @@ -1368,7 +1368,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) file_count(buf_obj->file), buf_obj->exp_name, file_inode(buf_obj->file)->i_ino, - buf_obj->name ?: ""); + buf_obj->name ?: ""); spin_unlock(&buf_obj->name_lock); dma_resv_describe(buf_obj->resv, s); From e090532246fe17609b08ba0a862428867426dc95 Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Fri, 29 Apr 2022 05:51:45 +0000 Subject: [PATCH 029/170] drm/bridge: simplify the return expression of ps8640_bridge_host_attach Simplify the return expression. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20220429055145.3852271-1-chi.minghao@zte.com.cn --- drivers/gpu/drm/bridge/parade-ps8640.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index edb939b14c04..e2467e58b5b7 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -542,7 +542,6 @@ static int ps8640_bridge_host_attach(struct device *dev, struct ps8640 *ps_bridg struct device_node *in_ep, *dsi_node; struct mipi_dsi_device *dsi; struct mipi_dsi_host *host; - int ret; const struct mipi_dsi_device_info info = { .type = "ps8640", .channel = 0, .node = NULL, @@ -577,11 +576,7 @@ static int ps8640_bridge_host_attach(struct device *dev, struct ps8640 *ps_bridg dsi->format = MIPI_DSI_FMT_RGB888; dsi->lanes = NUM_MIPI_LANES; - ret = devm_mipi_dsi_attach(dev, dsi); - if (ret) - return ret; - - return 0; + return devm_mipi_dsi_attach(dev, dsi); } static int ps8640_probe(struct i2c_client *client) From 047de3f17a8321065c32ee3f6272a6dba16d6bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 9 May 2022 09:47:12 +0200 Subject: [PATCH 030/170] drm/amdgpu: switch DM to atomic fence helpers v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives us the standard atomic implicit and explicit fencing rules. v2: move the wait to amdgpu_dm_atomic_commit_tail Signed-off-by: Christian König Reviewed-by: Daniel Vetter Cc: Harry Wentland Cc: Nicholas Kazlauskas Cc: Roman Li Cc: Qingqing Zhuo Cc: Jude Shih Cc: Wayne Lin Cc: Rodrigo Siqueira Link: https://patchwork.freedesktop.org/patch/msgid/20220509074712.163899-1-christian.koenig@amd.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a6880dd9c0bb..f9ce8cb45e6d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -83,6 +83,7 @@ #include #include #include +#include #if defined(CONFIG_DRM_AMD_DC_DCN) #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" @@ -7627,6 +7628,10 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, goto error_unpin; } + r = drm_gem_plane_helper_prepare_fb(plane, new_state); + if (unlikely(r != 0)) + goto error_unpin; + amdgpu_bo_unreserve(rbo); afb->address = amdgpu_bo_gpu_offset(rbo); @@ -9160,7 +9165,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc)); int planes_count = 0, vpos, hpos; - long r; unsigned long flags; struct amdgpu_bo *abo; uint32_t target_vblank, last_flip_vblank; @@ -9235,18 +9239,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, } abo = gem_to_amdgpu_bo(fb->obj[0]); - - /* - * Wait for all fences on this FB. Do limited wait to avoid - * deadlock during GPU reset when this fence will not signal - * but we hold reservation lock for the BO. - */ - r = dma_resv_wait_timeout(abo->tbo.base.resv, - DMA_RESV_USAGE_WRITE, false, - msecs_to_jiffies(5000)); - if (unlikely(r <= 0)) - DRM_ERROR("Waiting for fences timed out!"); - fill_dc_plane_info_and_addr( dm->adev, new_plane_state, afb->tiling_flags, @@ -9591,9 +9583,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; int crtc_disable_count = 0; bool mode_set_reset_required = false; + int r; trace_amdgpu_dm_atomic_commit_tail_begin(state); + r = drm_atomic_helper_wait_for_fences(dev, state, false); + if (unlikely(r)) + DRM_ERROR("Waiting for fences timed out!"); + drm_atomic_helper_update_legacy_modeset_state(dev, state); dm_state = dm_atomic_get_new_state(state); From 5e3f1e7729ec7a99e145e9d8ed58963d86cdfb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 10 May 2022 12:52:05 +0200 Subject: [PATCH 031/170] drm/amdgpu: fix start calculation in amdgpu_vram_mgr_new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still need to calculate a virtual start address for the resource to aid checking of it is visible or not. Only matters on small BAR systems, but better save than sorry. Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Arunpravin Paneer Selvam Link: https://patchwork.freedesktop.org/patch/msgid/20220510113649.879821-1-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 22 +++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 49e4092f447f..51d9d3a4456c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -496,17 +496,23 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, list_splice_tail(trim_list, &vres->blocks); } - list_for_each_entry(block, &vres->blocks, link) + vres->base.start = 0; + list_for_each_entry(block, &vres->blocks, link) { + unsigned long start; + + start = amdgpu_vram_mgr_block_start(block) + + amdgpu_vram_mgr_block_size(block); + start >>= PAGE_SHIFT; + + if (start > vres->base.num_pages) + start -= vres->base.num_pages; + else + start = 0; + vres->base.start = max(vres->base.start, start); + vis_usage += amdgpu_vram_mgr_vis_size(adev, block); - - block = amdgpu_vram_mgr_first_block(&vres->blocks); - if (!block) { - r = -EINVAL; - goto error_fini; } - vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT; - if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks)) vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS; From 708d19d9f362766147cab79eccae60912c6d3068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 10 May 2022 13:26:46 +0200 Subject: [PATCH 032/170] drm/amdgpu: move internal vram_mgr function into the C file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to have those in the header. Signed-off-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Arunpravin Paneer Selvam Link: https://patchwork.freedesktop.org/patch/msgid/20220510113649.879821-2-christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 29 ++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 27 ------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 51d9d3a4456c..7a5e8a7b4a1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -50,6 +50,35 @@ to_amdgpu_device(struct amdgpu_vram_mgr *mgr) return container_of(mgr, struct amdgpu_device, mman.vram_mgr); } +static inline struct drm_buddy_block * +amdgpu_vram_mgr_first_block(struct list_head *list) +{ + return list_first_entry_or_null(list, struct drm_buddy_block, link); +} + +static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) +{ + struct drm_buddy_block *block; + u64 start, size; + + block = amdgpu_vram_mgr_first_block(head); + if (!block) + return false; + + while (head != block->link.next) { + start = amdgpu_vram_mgr_block_start(block); + size = amdgpu_vram_mgr_block_size(block); + + block = list_entry(block->link.next, struct drm_buddy_block, link); + if (start + size != amdgpu_vram_mgr_block_start(block)) + return false; + } + + return true; +} + + + /** * DOC: mem_info_vram_total * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h index 9a2db87186c7..4b267bf1c5db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h @@ -53,33 +53,6 @@ static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block) return PAGE_SIZE << drm_buddy_block_order(block); } -static inline struct drm_buddy_block * -amdgpu_vram_mgr_first_block(struct list_head *list) -{ - return list_first_entry_or_null(list, struct drm_buddy_block, link); -} - -static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) -{ - struct drm_buddy_block *block; - u64 start, size; - - block = amdgpu_vram_mgr_first_block(head); - if (!block) - return false; - - while (head != block->link.next) { - start = amdgpu_vram_mgr_block_start(block); - size = amdgpu_vram_mgr_block_size(block); - - block = list_entry(block->link.next, struct drm_buddy_block, link); - if (start + size != amdgpu_vram_mgr_block_start(block)) - return false; - } - - return true; -} - static inline struct amdgpu_vram_mgr_resource * to_amdgpu_vram_mgr_resource(struct ttm_resource *res) { From 7454a7e72b3c679ddb723a9e79be65b62d4412f5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 5 May 2022 19:26:10 +0200 Subject: [PATCH 033/170] MAINTAINERS: Add simpledrm driver co-maintainer Thomas asked me to serve as co-maintainer for the simpledrm driver. Signed-off-by: Javier Martinez Canillas Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220505172610.338299-1-javierm@redhat.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1a04950c1a8f..bfe43560f9d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6389,6 +6389,7 @@ F: include/uapi/drm/savage_drm.h DRM DRIVER FOR SIMPLE FRAMEBUFFERS M: Thomas Zimmermann +M: Javier Martinez Canillas L: dri-devel@lists.freedesktop.org S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc From dbb3cd0c81c28e38f8e3528d1cea4d9c0c6c7317 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 9 May 2022 15:08:46 +0200 Subject: [PATCH 034/170] drm/todo: Add entry for converting kselftests to kunit Many of the kselftests in DRM can be converted to kunit tests instead, since that framework is more suitable for unit testing. Suggested-by: Maxime Ripard Signed-off-by: Javier Martinez Canillas Acked-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220509130846.694397-1-javierm@redhat.com --- Documentation/gpu/todo.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 10bfb50908d1..513b20ccef1e 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -617,6 +617,17 @@ Contact: Javier Martinez Canillas Level: Intermediate +Convert Kernel Selftests (kselftest) to KUnit tests when appropriate +-------------------------------------------------------------------- + +Many of the `Kselftest `_ +tests in DRM could be converted to Kunit tests instead, since that framework +is more suitable for unit testing. + +Contact: Javier Martinez Canillas + +Level: Starter + Enable trinity for DRM ---------------------- From aebeb02dfccb61d6930112aede2db3db5b8e974e Mon Sep 17 00:00:00 2001 From: Jayshri Pawar Date: Mon, 11 Apr 2022 16:06:06 +0200 Subject: [PATCH 035/170] drm/bridge: cdns-dsi: Add support for pre_enable and post_enable control functions. Add support for pre_enable and post_enable drm bridge control functions. Making sure that host to be prepared before panel is powered up, for the panels like TC358762. Signed-off-by: Jayshri Pawar Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220411140606.15654-1-jpawar@cadence.com --- drivers/gpu/drm/bridge/cdns-dsi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index 829e1a144656..20bece84ff8c 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -462,6 +462,7 @@ struct cdns_dsi { struct reset_control *dsi_p_rst; struct clk *dsi_sys_clk; bool link_initialized; + bool phy_initialized; struct phy *dphy; }; @@ -711,11 +712,21 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge) pm_runtime_put(dsi->base.dev); } +static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge) +{ + struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); + struct cdns_dsi *dsi = input_to_dsi(input); + + pm_runtime_put(dsi->base.dev); +} + static void cdns_dsi_hs_init(struct cdns_dsi *dsi) { struct cdns_dsi_output *output = &dsi->output; u32 status; + if (dsi->phy_initialized) + return; /* * Power all internal DPHY blocks down and maintain their reset line * asserted before changing the DPHY config. @@ -739,6 +750,7 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi) writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN | DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB, dsi->regs + MCTL_DPHY_CFG0); + dsi->phy_initialized = true; } static void cdns_dsi_init_link(struct cdns_dsi *dsi) @@ -914,11 +926,25 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge) writel(tmp, dsi->regs + MCTL_MAIN_EN); } +static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge); + struct cdns_dsi *dsi = input_to_dsi(input); + + if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0)) + return; + + cdns_dsi_init_link(dsi); + cdns_dsi_hs_init(dsi); +} + static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = { .attach = cdns_dsi_bridge_attach, .mode_valid = cdns_dsi_bridge_mode_valid, .disable = cdns_dsi_bridge_disable, + .pre_enable = cdns_dsi_bridge_pre_enable, .enable = cdns_dsi_bridge_enable, + .post_disable = cdns_dsi_bridge_post_disable, }; static int cdns_dsi_attach(struct mipi_dsi_host *host, From 0f6e2fff575bb14abcb014fa02a9267351f55576 Mon Sep 17 00:00:00 2001 From: Melissa Wen Date: Fri, 29 Apr 2022 18:33:30 -0100 Subject: [PATCH 036/170] MAINTAINERS: add Melissa to V3D maintainers I've been contributing to v3d through improvements, reviews, testing, debugging, etc. So, I'm adding myself as a co-maintainer of the V3D driver. Signed-off-by: Melissa Wen Acked-by: Juan A. Suarez Acked-by: Iago Toral Quiroga Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220429193317.ol3u4e5jpt5jucox@mail.igalia.com --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index bfe43560f9d5..11da16bfa123 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6719,6 +6719,7 @@ F: drivers/gpu/drm/omapdrm/ DRM DRIVERS FOR V3D M: Emma Anholt +M: Melissa Wen S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml From 3064debaf55e1bc8f191871ca5f82697ef4c0951 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Wed, 4 May 2022 15:40:24 +0200 Subject: [PATCH 037/170] drm/mgag200: Add FB_DAMAGE_CLIPS support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver does support damage clips, but doesn't advertise it. So when running gnome/wayland on Matrox hardware, the full frame is copied to the slow Matrox memory, which leads to very poor performances. Add drm_plane_enable_fb_damage_clips() to advertise this capability to userspace. With this patch, gnome/wayland becomes usable on Matrox GPU. Suggested-by: Jonas Ådahl Signed-off-by: Jocelyn Falempe Reviewed-by: Lyude Paul Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220504134026.283417-2-jfalempe@redhat.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index abde7655477d..a77da57f1022 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1121,6 +1121,8 @@ int mgag200_modeset_init(struct mga_device *mdev) return ret; } + drm_plane_enable_fb_damage_clips(&pipe->plane); + /* FIXME: legacy gamma tables; convert to CRTC state */ drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); From c48a363016349352dac7e66cd1e823f73bff1fc4 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Wed, 4 May 2022 15:40:25 +0200 Subject: [PATCH 038/170] drm/mgag200: Optimize damage clips When there are multiple damage clips, previous code merged them into one big rectangle. As the Matrox memory is very slow, it's faster to copy each damage clip. Signed-off-by: Jocelyn Falempe Reviewed-by: Lyude Paul Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220504134026.283417-2-jfalempe@redhat.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index a77da57f1022..294a53b95c61 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -855,10 +855,6 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, dst += drm_fb_clip_offset(fb->pitches[0], fb->format, clip); drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, clip); - - /* Always scanout image at VRAM offset 0 */ - mgag200_set_startadd(mdev, (u32)0); - mgag200_set_offset(mdev, fb); } static void @@ -913,6 +909,10 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]); + /* Always scanout image at VRAM offset 0 */ + mgag200_set_startadd(mdev, (u32)0); + mgag200_set_offset(mdev, fb); + mutex_unlock(&mdev->rmmio_lock); } @@ -969,14 +969,20 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); struct drm_framebuffer *fb = state->fb; struct drm_rect damage; + struct drm_atomic_helper_damage_iter iter; if (!fb) return; mutex_lock(&mdev->rmmio_lock); - if (drm_atomic_helper_damage_merged(old_state, state, &damage)) + drm_atomic_helper_damage_iter_init(&iter, old_state, state); + drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]); + } + /* Always scanout image at VRAM offset 0 */ + mgag200_set_startadd(mdev, (u32)0); + mgag200_set_offset(mdev, fb); mutex_unlock(&mdev->rmmio_lock); } From d2addf89c5abf4024574d42000313175c6e074fc Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Wed, 4 May 2022 15:40:26 +0200 Subject: [PATCH 039/170] drm/mgag200: Warn once if trying to set start address on broken hardware. Some MGA200 hardware is broken and can't use a start address > 0. v2: Warn if startaddr is not 0, and hw doesn't support it. (instead of removing MGAG200_FLAG_HW_BUG_NO_STARTADD) Signed-off-by: Jocelyn Falempe Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220504134026.283417-4-jfalempe@redhat.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 294a53b95c61..dec744d0bee2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -223,6 +223,9 @@ static void mgag200_set_startadd(struct mga_device *mdev, startadd = offset / 8; + if (startadd > 0) + drm_WARN_ON_ONCE(dev, mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD); + /* * Can't store addresses any higher than that, but we also * don't have more than 16 MiB of memory, so it should be fine. From d7fd32ecce914686756dedf586c8573e71f975a4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 29 Apr 2022 22:56:43 +0200 Subject: [PATCH 040/170] drm/bridge: tc358767: Factor out DSI and DPI RX enablement Factor out register programming to configure the chip video RX side for reception of video data from DSI or DPI. This is particularly useful in the (e)DP output mode, where the video data can be received from either DPI or DSI. While only the former is supported in (e)DP output mode so far, this patch is added in preparation for addition of the later. There is a change in the order or register programming in case of the DSI-to-DPI mode. The DSI RX side is now programmed and enabled all in one place after the output mode has been configured. Before this change, the DSI RX has been programmed before the output mode has been set and only enabled afterward. The order makes no difference however, since the DSI RX is only enabled at the end either way. Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220429205644.245480-1-marex@denx.de --- drivers/gpu/drm/bridge/tc358767.c | 94 +++++++++++++++++-------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 485717c8f0b4..e72dd5cd9700 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1247,10 +1247,59 @@ static int tc_main_link_disable(struct tc_data *tc) return regmap_write(tc->regmap, DP0CTL, 0); } +static int tc_dsi_rx_enable(struct tc_data *tc) +{ + u32 value; + int ret; + + regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 3); + regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 3); + regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 3); + regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 3); + regmap_write(tc->regmap, PPI_D0S_ATMR, 0); + regmap_write(tc->regmap, PPI_D1S_ATMR, 0); + regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE); + regmap_write(tc->regmap, PPI_LPTXTIMECNT, LPX_PERIOD); + + value = ((LANEENABLE_L0EN << tc->dsi_lanes) - LANEENABLE_L0EN) | + LANEENABLE_CLEN; + regmap_write(tc->regmap, PPI_LANEENABLE, value); + regmap_write(tc->regmap, DSI_LANEENABLE, value); + + /* Set input interface */ + value = DP0_AUDSRC_NO_INPUT; + if (tc_test_pattern) + value |= DP0_VIDSRC_COLOR_BAR; + else + value |= DP0_VIDSRC_DSI_RX; + ret = regmap_write(tc->regmap, SYSCTRL, value); + if (ret) + return ret; + + usleep_range(120, 150); + + regmap_write(tc->regmap, PPI_STARTPPI, PPI_START_FUNCTION); + regmap_write(tc->regmap, DSI_STARTDSI, DSI_RX_START); + + return 0; +} + +static int tc_dpi_rx_enable(struct tc_data *tc) +{ + u32 value; + + /* Set input interface */ + value = DP0_AUDSRC_NO_INPUT; + if (tc_test_pattern) + value |= DP0_VIDSRC_COLOR_BAR; + else + value |= DP0_VIDSRC_DPI_RX; + return regmap_write(tc->regmap, SYSCTRL, value); +} + static int tc_dpi_stream_enable(struct tc_data *tc) { int ret; - u32 value; dev_dbg(tc->dev, "enable video stream\n"); @@ -1277,20 +1326,6 @@ static int tc_dpi_stream_enable(struct tc_data *tc) if (ret) return ret; - regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D0S_ATMR, 0); - regmap_write(tc->regmap, PPI_D1S_ATMR, 0); - regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE); - regmap_write(tc->regmap, PPI_LPTXTIMECNT, LPX_PERIOD); - - value = ((LANEENABLE_L0EN << tc->dsi_lanes) - LANEENABLE_L0EN) | - LANEENABLE_CLEN; - regmap_write(tc->regmap, PPI_LANEENABLE, value); - regmap_write(tc->regmap, DSI_LANEENABLE, value); - ret = tc_set_common_video_mode(tc, &tc->mode); if (ret) return ret; @@ -1299,22 +1334,7 @@ static int tc_dpi_stream_enable(struct tc_data *tc) if (ret) return ret; - /* Set input interface */ - value = DP0_AUDSRC_NO_INPUT; - if (tc_test_pattern) - value |= DP0_VIDSRC_COLOR_BAR; - else - value |= DP0_VIDSRC_DSI_RX; - ret = regmap_write(tc->regmap, SYSCTRL, value); - if (ret) - return ret; - - usleep_range(120, 150); - - regmap_write(tc->regmap, PPI_STARTPPI, PPI_START_FUNCTION); - regmap_write(tc->regmap, DSI_STARTDSI, DSI_RX_START); - - return 0; + return tc_dsi_rx_enable(tc); } static int tc_dpi_stream_disable(struct tc_data *tc) @@ -1370,19 +1390,11 @@ static int tc_edp_stream_enable(struct tc_data *tc) usleep_range(500, 1000); value |= VID_EN; ret = regmap_write(tc->regmap, DP0CTL, value); - if (ret) - return ret; - /* Set input interface */ - value = DP0_AUDSRC_NO_INPUT; - if (tc_test_pattern) - value |= DP0_VIDSRC_COLOR_BAR; - else - value |= DP0_VIDSRC_DPI_RX; - ret = regmap_write(tc->regmap, SYSCTRL, value); if (ret) return ret; - return 0; + /* Set input interface */ + return tc_dpi_rx_enable(tc); } static int tc_edp_stream_disable(struct tc_data *tc) From 3080c21a043abc83e56da9bb5942eb3f4b92c90e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 29 Apr 2022 22:56:44 +0200 Subject: [PATCH 041/170] drm/bridge: tc358767: Add DSI-to-(e)DP mode support Implement DSI-to-e(DP) mode, which is a mix of currently supported DSI-to-DPI and DPI-to-(e)DP modes. The input side is configured as either DSI or DPI, the DP AUX channel is registered for both input side options, and the DSI host is attached for both DPI and (e)DP output side options. One notable detail is that the DSI-to-(e)DP mode requires the Pixel PLL to be always enabled, which is not needed for DPI-to-(e)DP mode which gets the matching clock direct from DPI Pixel Clock instead. Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220429205644.245480-2-marex@denx.de --- drivers/gpu/drm/bridge/tc358767.c | 40 +++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index e72dd5cd9700..798da0e4d086 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -309,6 +309,9 @@ struct tc_data { /* do we have IRQ */ bool have_irq; + /* Input connector type, DSI and not DPI. */ + bool input_connector_dsi; + /* HPD pin number (0 or 1) or -ENODEV */ int hpd_pin; }; @@ -1353,8 +1356,18 @@ static int tc_edp_stream_enable(struct tc_data *tc) dev_dbg(tc->dev, "enable video stream\n"); - /* PXL PLL setup */ - if (tc_test_pattern) { + /* + * Pixel PLL must be enabled for DSI input mode and test pattern. + * + * Per TC9595XBG datasheet Revision 0.1 2018-12-27 Figure 4.18 + * "Clock Mode Selection and Clock Sources", either Pixel PLL + * or DPI_PCLK supplies StrmClk. DPI_PCLK is only available in + * case valid Pixel Clock are supplied to the chip DPI input. + * In case built-in test pattern is desired OR DSI input mode + * is used, DPI_PCLK is not available and thus Pixel PLL must + * be used instead. + */ + if (tc->input_connector_dsi || tc_test_pattern) { ret = tc_pxl_pll_en(tc, clk_get_rate(tc->refclk), 1000 * tc->mode.clock); if (ret) @@ -1394,7 +1407,10 @@ static int tc_edp_stream_enable(struct tc_data *tc) return ret; /* Set input interface */ - return tc_dpi_rx_enable(tc); + if (tc->input_connector_dsi) + return tc_dsi_rx_enable(tc); + else + return tc_dpi_rx_enable(tc); } static int tc_edp_stream_disable(struct tc_data *tc) @@ -2004,14 +2020,18 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc) mode |= BIT(endpoint.port); } - if (mode == mode_dpi_to_edp || mode == mode_dpi_to_dp) + if (mode == mode_dpi_to_edp || mode == mode_dpi_to_dp) { + tc->input_connector_dsi = false; return tc_probe_edp_bridge_endpoint(tc); - else if (mode == mode_dsi_to_dpi) + } else if (mode == mode_dsi_to_dpi) { + tc->input_connector_dsi = true; return tc_probe_dpi_bridge_endpoint(tc); - else if (mode == mode_dsi_to_edp || mode == mode_dsi_to_dp) - dev_warn(dev, "The mode DSI-to-(e)DP is not supported!\n"); - else - dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode); + } else if (mode == mode_dsi_to_edp || mode == mode_dsi_to_dp) { + tc->input_connector_dsi = true; + return tc_probe_edp_bridge_endpoint(tc); + } + + dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode); return -EINVAL; } @@ -2149,7 +2169,7 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) i2c_set_clientdata(client, tc); - if (tc->bridge.type == DRM_MODE_CONNECTOR_DPI) { /* DPI output */ + if (tc->input_connector_dsi) { /* DSI input */ ret = tc_mipi_dsi_host_attach(tc); if (ret) { drm_bridge_remove(&tc->bridge); From 3367aa7d74d240261de2543ddb35531ccad9d884 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 11 May 2022 13:30:39 +0200 Subject: [PATCH 042/170] fbdev: Restart conflicting fb removal loop when unregistering devices Drivers that want to remove registered conflicting framebuffers prior to register their own framebuffer, call to remove_conflicting_framebuffers(). This function takes the registration_lock mutex, to prevent a race when drivers register framebuffer devices. But if a conflicting framebuffer device is found, the underlaying platform device is unregistered and this will lead to the platform driver .remove callback to be called. Which in turn will call to unregister_framebuffer() that takes the same lock. To prevent this, a struct fb_info.forced_out field was used as indication to unregister_framebuffer() whether the mutex has to be grabbed or not. But this could be unsafe, since the fbdev core is making assumptions about what drivers may or may not do in their .remove callbacks. Allowing to run these callbacks with the registration_lock held can cause deadlocks, since the fbdev core has no control over what drivers do in their removal path. A better solution is to drop the lock before platform_device_unregister(), so unregister_framebuffer() can take it when called from the fbdev driver. The lock is acquired again after the device has been unregistered and at this point the removal loop can be restarted. Since the conflicting framebuffer device has already been removed, the loop would just finish when no more conflicting framebuffers are found. Suggested-by: Daniel Vetter Signed-off-by: Javier Martinez Canillas Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220511113039.1252432-1-javierm@redhat.com --- drivers/video/fbdev/core/fbmem.c | 22 +++++++++++++++------- include/linux/fb.h | 1 - 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index b445a7a00def..2fda5917c212 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1555,6 +1555,7 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, { int i; +restart_removal: /* check all firmware fbs and kick off if the base addr overlaps */ for_each_registered_fb(i) { struct apertures_struct *gen_aper; @@ -1587,12 +1588,23 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, pr_warn("fb%d: no device set\n", i); do_unregister_framebuffer(registered_fb[i]); } else if (dev_is_platform(device)) { - registered_fb[i]->forced_out = true; + /* + * Drop the lock because if the device is unregistered, its + * driver will call to unregister_framebuffer(), that takes + * this lock. + */ + mutex_unlock(®istration_lock); platform_device_unregister(to_platform_device(device)); + mutex_lock(®istration_lock); } else { pr_warn("fb%d: cannot remove device\n", i); do_unregister_framebuffer(registered_fb[i]); } + /* + * Restart the removal loop now that the device has been + * unregistered and its associated framebuffer gone. + */ + goto restart_removal; } } } @@ -1899,13 +1911,9 @@ EXPORT_SYMBOL(register_framebuffer); void unregister_framebuffer(struct fb_info *fb_info) { - bool forced_out = fb_info->forced_out; - - if (!forced_out) - mutex_lock(®istration_lock); + mutex_lock(®istration_lock); do_unregister_framebuffer(fb_info); - if (!forced_out) - mutex_unlock(®istration_lock); + mutex_unlock(®istration_lock); } EXPORT_SYMBOL(unregister_framebuffer); diff --git a/include/linux/fb.h b/include/linux/fb.h index 69c67c70fa78..bbe1e4571899 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -511,7 +511,6 @@ struct fb_info { } *apertures; bool skip_vt_switch; /* no VT switch on suspend/resume required */ - bool forced_out; /* set when being removed by another driver */ }; static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { From fa0e256450f27a7d85f65c63f05e6897954a1d53 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 5 May 2022 14:04:18 +0200 Subject: [PATCH 043/170] fbdev: vesafb: Allow to be built if COMPILE_TEST is enabled The driver has runtime but no build time dependency with X86, so it can be built for testing purposes if the COMPILE_TEST option is enabled. This is useful to have more build coverage and make sure that the driver is not affected by changes that could cause build regressions. Signed-off-by: Javier Martinez Canillas Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220505120419.314136-1-javierm@redhat.com --- drivers/video/fbdev/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index f2a6b81e45c4..bd849013f16f 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -616,7 +616,7 @@ config FB_UVESA config FB_VESA bool "VESA VGA graphics support" - depends on (FB = y) && X86 + depends on (FB = y) && (X86 || COMPILE_TEST) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT From be982415fc2e953ad49e59b204f2d0e64953eb5f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:00 +0300 Subject: [PATCH 044/170] drm/edid: use else-if in CTA extension parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only one of the conditions can be true. Suggested-by: Ville Syrjälä Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/3a7ba2217134b0ab4c4c72e4333231a4e0616e88.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 47d121e99201..efc1999b9573 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5473,16 +5473,16 @@ static void drm_parse_cea_ext(struct drm_connector *connector, if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, data); - if (cea_db_is_hdmi_forum_vsdb(db) || - cea_db_is_hdmi_forum_scdb(db)) + else if (cea_db_is_hdmi_forum_vsdb(db) || + cea_db_is_hdmi_forum_scdb(db)) drm_parse_hdmi_forum_scds(connector, data); - if (cea_db_is_microsoft_vsdb(db)) + else if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, data); - if (cea_db_is_y420cmdb(db)) + else if (cea_db_is_y420cmdb(db)) drm_parse_y420cmdb_bitmap(connector, data); - if (cea_db_is_vcdb(db)) + else if (cea_db_is_vcdb(db)) drm_parse_vcdb(connector, data); - if (cea_db_is_hdmi_hdr_metadata_block(db)) + else if (cea_db_is_hdmi_hdr_metadata_block(db)) drm_parse_hdr_metadata_block(connector, data); } cea_db_iter_end(&iter); From ab1747ccf052976465db7c5a7e1301a50f290db0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:01 +0300 Subject: [PATCH 045/170] drm/edid: convert drm_for_each_detailed_block() to edid iter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have an iterator for this, use it. It does include the base block, but its tag is 0 and will be skipped. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/a68718819a3dbfbdaaaddca7f73afa5ac6b33d07.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index efc1999b9573..dcef92c8887a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2574,6 +2574,8 @@ vtb_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure) static void drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *closure) { + struct drm_edid_iter edid_iter; + const u8 *ext; int i; if (edid == NULL) @@ -2582,9 +2584,8 @@ drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *clos for (i = 0; i < EDID_DETAILED_TIMINGS; i++) cb(&(edid->detailed_timings[i]), closure); - for (i = 0; i < edid_extension_block_count(edid); i++) { - const u8 *ext = edid_extension_block_data(edid, i); - + drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_for_each(ext, &edid_iter) { switch (*ext) { case CEA_EXT: cea_for_each_detailed_block(ext, cb, closure); @@ -2596,6 +2597,7 @@ drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *clos break; } } + drm_edid_iter_end(&edid_iter); } static void From e4ccf9a777d30d60c60f729b1d5c9bc9e3ea46e3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:02 +0300 Subject: [PATCH 046/170] drm/edid: add struct drm_edid container Introduce new opaque type struct drm_edid to encapsulate the EDID data and the size allocated for it. The contents will be private to drm_edid.c. There are a number of reasons for adding a container around struct edid: * struct edid is a raw blob pointer to data that usually originates outside of the kernel. Its size is contained within the structure. * There's no way to attach meta information (such as allocated memory size) to struct edid. * Validation of the EDID blob and its size become crucial, and it's spread all over the subsystem, with varying levels of accuracy. * HDMI Forum has introduced an HF-EEODB extension that defines an override EDID size within an EDID extension. The size allocated for an EDID depends on whether the allocator understands the HF-EEODB extension. Given a struct edid *, it's impossible to know how much memory was actually allocated for it. There are also some reasons for making the container type struct drm_edid opaque and private to drm_edid.c: * Have only one place for creating and parsing the EDID, to avoid duplicating bugs. * Prepare for reading a pure DisplayID 2.0 from its own DDC address, and adding it within the same struct drm_edid container, transparently, and for all drivers. * With the idea that the drm_edid objects are immutable during their lifetimes, it will be possible to refcount them and reduce EDID copying everywhere (this is left for future work). Initially, just add the type. In follow-up, we'll start converting the guts of drm_edid.c to use it, and finally add interfaces around it. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/f3ecabd8a219aea678ad00f7bcdecf77b27b3c78.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index dcef92c8887a..480fd9fbe412 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1567,6 +1567,15 @@ static const struct drm_display_mode edid_4k_modes[] = { /*** DDC fetch and block validation ***/ +/* + * The opaque EDID type, internal to drm_edid.c. + */ +struct drm_edid { + /* Size allocated for edid */ + size_t size; + const struct edid *edid; +}; + static int edid_extension_block_count(const struct edid *edid) { return edid->extensions; From 22a27e0532d06968afc265a3b91fbdc5a773169a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:03 +0300 Subject: [PATCH 047/170] drm/edid: start propagating drm_edid to lower levels We'll need to propagate drm_edid everywhere. This is a clunky start, but a start nonetheless. We'll eventually convert all of the EDID parsing to struct drm_edid. Initially, we'll just create the struct drm_edid in stack. This will be the compat layer for legacy struct edid code. In the future, we'll have EDID read return drm_edid objects. v2: Add legacy init helper. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/000452fddedbaf7f473ac25d4dde2502e60b8e39.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 480fd9fbe412..f48f1f1a1fa7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1608,6 +1608,24 @@ static const void *edid_extension_block_data(const struct edid *edid, int index) return edid_block_data(edid, index + 1); } +/* + * Initializer helper for legacy interfaces, where we have no choice but to + * trust edid size. Not for general purpose use. + */ +static const struct drm_edid *drm_edid_legacy_init(struct drm_edid *drm_edid, + const struct edid *edid) +{ + if (!edid) + return NULL; + + memset(drm_edid, 0, sizeof(*drm_edid)); + + drm_edid->edid = edid; + drm_edid->size = edid_size(edid); + + return drm_edid; +} + /* * EDID base and extension block iterator. * @@ -5814,17 +5832,20 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, } static int drm_edid_connector_update(struct drm_connector *connector, - const struct edid *edid) + const struct drm_edid *drm_edid) { + const struct edid *edid; int num_modes = 0; u32 quirks; - if (edid == NULL) { + if (!drm_edid) { drm_reset_display_info(connector); clear_eld(connector); return 0; } + edid = drm_edid->edid; + /* * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. * To avoid multiple parsing of same block, lets parse that map @@ -5890,13 +5911,16 @@ static int drm_edid_connector_update(struct drm_connector *connector, */ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) { + struct drm_edid drm_edid; + if (edid && !drm_edid_is_valid(edid)) { drm_warn(connector->dev, "%s: EDID invalid.\n", connector->name); edid = NULL; } - return drm_edid_connector_update(connector, edid); + return drm_edid_connector_update(connector, + drm_edid_legacy_init(&drm_edid, edid)); } EXPORT_SYMBOL(drm_add_edid_modes); From e42192b4c345a807d8df034f178d5846e1c97ad1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 May 2022 12:21:04 +0300 Subject: [PATCH 048/170] drm/edid: keep propagating drm_edid to display info We'll need to propagate drm_edid everywhere. v3: Update comment to refer to update_display_info() (Ankit) v2: Use drm_edid_legacy_init() Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20220511092104.4179637-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 50 +++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f48f1f1a1fa7..e89afa04d5ab 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2437,13 +2437,13 @@ EXPORT_SYMBOL(drm_edid_duplicate); /** * edid_get_quirks - return quirk flags for a given EDID - * @edid: EDID to process + * @drm_edid: EDID to process * * This tells subsequent routines what fixes they need to apply. */ -static u32 edid_get_quirks(const struct edid *edid) +static u32 edid_get_quirks(const struct drm_edid *drm_edid) { - u32 panel_id = edid_extract_panel_id(edid); + u32 panel_id = edid_extract_panel_id(drm_edid->edid); const struct edid_quirk *quirk; int i; @@ -5466,7 +5466,7 @@ static void drm_parse_microsoft_vsdb(struct drm_connector *connector, } static void drm_parse_cea_ext(struct drm_connector *connector, - const struct edid *edid) + const struct drm_edid *drm_edid) { struct drm_display_info *info = &connector->display_info; struct drm_edid_iter edid_iter; @@ -5474,7 +5474,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, struct cea_db_iter iter; const u8 *edid_ext; - drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_begin(drm_edid->edid, &edid_iter); drm_edid_iter_for_each(edid_ext, &edid_iter) { if (edid_ext[0] != CEA_EXT) continue; @@ -5495,7 +5495,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, } drm_edid_iter_end(&edid_iter); - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid->edid, &iter); cea_db_iter_for_each(db, &iter) { /* FIXME: convert parsers to use struct cea_db */ const u8 *data = (const u8 *)db; @@ -5541,16 +5541,15 @@ void get_monitor_range(const struct detailed_timing *timing, monitor_range->max_vfreq = range->max_vfreq; } -static -void drm_get_monitor_range(struct drm_connector *connector, - const struct edid *edid) +static void drm_get_monitor_range(struct drm_connector *connector, + const struct drm_edid *drm_edid) { struct drm_display_info *info = &connector->display_info; - if (!version_greater(edid, 1, 1)) + if (!version_greater(drm_edid->edid, 1, 1)) return; - drm_for_each_detailed_block(edid, get_monitor_range, + drm_for_each_detailed_block(drm_edid->edid, get_monitor_range, &info->monitor_range); DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n", @@ -5610,12 +5609,13 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector, info->mso_stream_count, info->mso_pixel_overlap); } -static void drm_update_mso(struct drm_connector *connector, const struct edid *edid) +static void drm_update_mso(struct drm_connector *connector, + const struct drm_edid *drm_edid) { const struct displayid_block *block; struct displayid_iter iter; - displayid_iter_edid_begin(edid, &iter); + displayid_iter_edid_begin(drm_edid->edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC) drm_parse_vesa_mso_data(connector, block); @@ -5654,18 +5654,20 @@ drm_reset_display_info(struct drm_connector *connector) info->mso_pixel_overlap = 0; } -u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid) +static u32 update_display_info(struct drm_connector *connector, + const struct drm_edid *drm_edid) { struct drm_display_info *info = &connector->display_info; + const struct edid *edid = drm_edid->edid; - u32 quirks = edid_get_quirks(edid); + u32 quirks = edid_get_quirks(drm_edid); drm_reset_display_info(connector); info->width_mm = edid->width_cm * 10; info->height_mm = edid->height_cm * 10; - drm_get_monitor_range(connector, edid); + drm_get_monitor_range(connector, drm_edid); if (edid->revision < 3) goto out; @@ -5674,7 +5676,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi goto out; info->color_formats |= DRM_COLOR_FORMAT_RGB444; - drm_parse_cea_ext(connector, edid); + drm_parse_cea_ext(connector, drm_edid); /* * Digital sink with "DFP 1.x compliant TMDS" according to EDID 1.3? @@ -5727,7 +5729,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; - drm_update_mso(connector, edid); + drm_update_mso(connector, drm_edid); out: if (quirks & EDID_QUIRK_NON_DESKTOP) { @@ -5739,6 +5741,14 @@ out: return quirks; } +u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid) +{ + struct drm_edid drm_edid; + + return update_display_info(connector, + drm_edid_legacy_init(&drm_edid, edid)); +} + static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, struct displayid_detailed_timings_1 *timings, bool type_7) @@ -5851,9 +5861,9 @@ static int drm_edid_connector_update(struct drm_connector *connector, * To avoid multiple parsing of same block, lets parse that map * from sink info, before parsing CEA modes. */ - quirks = drm_add_display_info(connector, edid); + quirks = update_display_info(connector, drm_edid); - /* Depends on info->cea_rev set by drm_add_display_info() above */ + /* Depends on info->cea_rev set by update_display_info() above */ drm_edid_to_eld(connector, edid); /* From a2f9790dcffe2dd0b363607fd215e5b81a0de57a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 May 2022 12:23:49 +0300 Subject: [PATCH 049/170] drm/edid: propagate drm_edid to drm_edid_to_eld() We'll need to propagate drm_edid everywhere. v3: Rebase Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20220511092349.4186498-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index e89afa04d5ab..92a65ccbd730 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4883,13 +4883,13 @@ static void clear_eld(struct drm_connector *connector) /* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink - * @edid: EDID to parse + * @drm_edid: EDID to parse * * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. */ static void drm_edid_to_eld(struct drm_connector *connector, - const struct edid *edid) + const struct drm_edid *drm_edid) { const struct drm_display_info *info = &connector->display_info; const struct cea_db *db; @@ -4900,10 +4900,10 @@ static void drm_edid_to_eld(struct drm_connector *connector, clear_eld(connector); - if (!edid) + if (!drm_edid) return; - mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); + mnl = get_monitor_name(drm_edid->edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT; @@ -4911,12 +4911,12 @@ static void drm_edid_to_eld(struct drm_connector *connector, eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D; - eld[DRM_ELD_MANUFACTURER_NAME0] = edid->mfg_id[0]; - eld[DRM_ELD_MANUFACTURER_NAME1] = edid->mfg_id[1]; - eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0]; - eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1]; + eld[DRM_ELD_MANUFACTURER_NAME0] = drm_edid->edid->mfg_id[0]; + eld[DRM_ELD_MANUFACTURER_NAME1] = drm_edid->edid->mfg_id[1]; + eld[DRM_ELD_PRODUCT_CODE0] = drm_edid->edid->prod_code[0]; + eld[DRM_ELD_PRODUCT_CODE1] = drm_edid->edid->prod_code[1]; - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid->edid, &iter); cea_db_iter_for_each(db, &iter) { const u8 *data = cea_db_data(db); int len = cea_db_payload_len(db); @@ -5864,7 +5864,7 @@ static int drm_edid_connector_update(struct drm_connector *connector, quirks = update_display_info(connector, drm_edid); /* Depends on info->cea_rev set by update_display_info() above */ - drm_edid_to_eld(connector, edid); + drm_edid_to_eld(connector, drm_edid); /* * EDID spec says modes should be preferred in this order: From 40f71f5b239291357dbee3dc1c6ace83a373f44e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 11 May 2022 12:26:50 +0300 Subject: [PATCH 050/170] drm/edid: convert drm_edid_connector_update() to drm_edid fully We'll need to propagate drm_edid everywhere. v3: s/edid/drm_edid/ in comment too (Ankit) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/20220511092650.4193330-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 97 ++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 92a65ccbd730..9f1e5856aa77 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3253,16 +3253,16 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) } } -static int -add_inferred_modes(struct drm_connector *connector, const struct edid *edid) +static int add_inferred_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) { struct detailed_mode_closure closure = { .connector = connector, - .edid = edid, + .edid = drm_edid->edid, }; - if (version_greater(edid, 1, 0)) - drm_for_each_detailed_block(edid, do_inferred_modes, &closure); + if (version_greater(drm_edid->edid, 1, 0)) + drm_for_each_detailed_block(drm_edid->edid, do_inferred_modes, &closure); return closure.modes; } @@ -3312,10 +3312,11 @@ do_established_modes(const struct detailed_timing *timing, void *c) * bitmap of the supported "established modes" list (defined above). Tease them * out and add them to the global modes list. */ -static int -add_established_modes(struct drm_connector *connector, const struct edid *edid) +static int add_established_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) { struct drm_device *dev = connector->dev; + const struct edid *edid = drm_edid->edid; unsigned long est_bits = edid->established_timings.t1 | (edid->established_timings.t2 << 8) | ((edid->established_timings.mfg_rsvd & 0x80) << 9); @@ -3338,7 +3339,7 @@ add_established_modes(struct drm_connector *connector, const struct edid *edid) } if (version_greater(edid, 1, 0)) - drm_for_each_detailed_block(edid, do_established_modes, + drm_for_each_detailed_block(drm_edid->edid, do_established_modes, &closure); return modes + closure.modes; @@ -3373,28 +3374,28 @@ do_standard_modes(const struct detailed_timing *timing, void *c) * using the appropriate standard (DMT, GTF, or CVT). Grab them from EDID and * add them to the list. */ -static int -add_standard_modes(struct drm_connector *connector, const struct edid *edid) +static int add_standard_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) { int i, modes = 0; struct detailed_mode_closure closure = { .connector = connector, - .edid = edid, + .edid = drm_edid->edid, }; for (i = 0; i < EDID_STD_TIMINGS; i++) { struct drm_display_mode *newmode; - newmode = drm_mode_std(connector, edid, - &edid->standard_timings[i]); + newmode = drm_mode_std(connector, drm_edid->edid, + &drm_edid->edid->standard_timings[i]); if (newmode) { drm_mode_probed_add(connector, newmode); modes++; } } - if (version_greater(edid, 1, 0)) - drm_for_each_detailed_block(edid, do_standard_modes, + if (version_greater(drm_edid->edid, 1, 0)) + drm_for_each_detailed_block(drm_edid->edid, do_standard_modes, &closure); /* XXX should also look for standard codes in VTB blocks */ @@ -3466,15 +3467,15 @@ do_cvt_mode(const struct detailed_timing *timing, void *c) } static int -add_cvt_modes(struct drm_connector *connector, const struct edid *edid) +add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { struct detailed_mode_closure closure = { .connector = connector, - .edid = edid, + .edid = drm_edid->edid, }; - if (version_greater(edid, 1, 2)) - drm_for_each_detailed_block(edid, do_cvt_mode, &closure); + if (version_greater(drm_edid->edid, 1, 2)) + drm_for_each_detailed_block(drm_edid->edid, do_cvt_mode, &closure); /* XXX should also look for CVT codes in VTB blocks */ @@ -3516,25 +3517,24 @@ do_detailed_mode(const struct detailed_timing *timing, void *c) /* * add_detailed_modes - Add modes from detailed timings * @connector: attached connector - * @edid: EDID block to scan + * @drm_edid: EDID block to scan * @quirks: quirks to apply */ -static int -add_detailed_modes(struct drm_connector *connector, const struct edid *edid, - u32 quirks) +static int add_detailed_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid, u32 quirks) { struct detailed_mode_closure closure = { .connector = connector, - .edid = edid, + .edid = drm_edid->edid, .preferred = true, .quirks = quirks, }; - if (closure.preferred && !version_greater(edid, 1, 3)) + if (closure.preferred && !version_greater(drm_edid->edid, 1, 3)) closure.preferred = - (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); + (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); - drm_for_each_detailed_block(edid, do_detailed_mode, &closure); + drm_for_each_detailed_block(drm_edid->edid, do_detailed_mode, &closure); return closure.modes; } @@ -3588,7 +3588,7 @@ const u8 *drm_find_edid_extension(const struct edid *edid, } /* Return true if the EDID has a CTA extension or a DisplayID CTA data block */ -static bool drm_edid_has_cta_extension(const struct edid *edid) +static bool drm_edid_has_cta_extension(const struct drm_edid *drm_edid) { const struct displayid_block *block; struct displayid_iter iter; @@ -3596,11 +3596,11 @@ static bool drm_edid_has_cta_extension(const struct edid *edid) bool found = false; /* Look for a top level CEA extension block */ - if (drm_find_edid_extension(edid, CEA_EXT, &ext_index)) + if (drm_find_edid_extension(drm_edid->edid, CEA_EXT, &ext_index)) return true; /* CEA blocks can also be found embedded in a DisplayID block */ - displayid_iter_edid_begin(edid, &iter); + displayid_iter_edid_begin(drm_edid->edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_CTA) { found = true; @@ -3874,8 +3874,8 @@ static bool drm_valid_hdmi_vic(u8 vic) return vic > 0 && vic < ARRAY_SIZE(edid_4k_modes); } -static int -add_alternate_cea_modes(struct drm_connector *connector, const struct edid *edid) +static int add_alternate_cea_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) { struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *tmp; @@ -3883,7 +3883,7 @@ add_alternate_cea_modes(struct drm_connector *connector, const struct edid *edid int modes = 0; /* Don't add CTA modes if the CTA extension block is missing */ - if (!drm_edid_has_cta_extension(edid)) + if (!drm_edid_has_cta_extension(drm_edid)) return 0; /* @@ -4666,14 +4666,14 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, hdmi->y420_cmdb_map = map; } -static int -add_cea_modes(struct drm_connector *connector, const struct edid *edid) +static int add_cea_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) { const struct cea_db *db; struct cea_db_iter iter; int modes = 0; - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid->edid, &iter); cea_db_iter_for_each(db, &iter) { const u8 *hdmi = NULL, *video = NULL; u8 hdmi_len = 0, video_len = 0; @@ -5824,13 +5824,13 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, } static int add_displayid_detailed_modes(struct drm_connector *connector, - const struct edid *edid) + const struct drm_edid *drm_edid) { const struct displayid_block *block; struct displayid_iter iter; int num_modes = 0; - displayid_iter_edid_begin(edid, &iter); + displayid_iter_edid_begin(drm_edid->edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) @@ -5844,7 +5844,6 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, static int drm_edid_connector_update(struct drm_connector *connector, const struct drm_edid *drm_edid) { - const struct edid *edid; int num_modes = 0; u32 quirks; @@ -5854,8 +5853,6 @@ static int drm_edid_connector_update(struct drm_connector *connector, return 0; } - edid = drm_edid->edid; - /* * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. * To avoid multiple parsing of same block, lets parse that map @@ -5880,15 +5877,15 @@ static int drm_edid_connector_update(struct drm_connector *connector, * * XXX order for additional mode types in extension blocks? */ - num_modes += add_detailed_modes(connector, edid, quirks); - num_modes += add_cvt_modes(connector, edid); - num_modes += add_standard_modes(connector, edid); - num_modes += add_established_modes(connector, edid); - num_modes += add_cea_modes(connector, edid); - num_modes += add_alternate_cea_modes(connector, edid); - num_modes += add_displayid_detailed_modes(connector, edid); - if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) - num_modes += add_inferred_modes(connector, edid); + num_modes += add_detailed_modes(connector, drm_edid, quirks); + num_modes += add_cvt_modes(connector, drm_edid); + num_modes += add_standard_modes(connector, drm_edid); + num_modes += add_established_modes(connector, drm_edid); + num_modes += add_cea_modes(connector, drm_edid); + num_modes += add_alternate_cea_modes(connector, drm_edid); + num_modes += add_displayid_detailed_modes(connector, drm_edid); + if (drm_edid->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) + num_modes += add_inferred_modes(connector, drm_edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); From dd0f4470a849d07081a2036f89d2c41264383985 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:07 +0300 Subject: [PATCH 051/170] drm/edid: convert struct detailed_mode_closure to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/da4c927cd973766568a79ef044254fff20317e7f.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9f1e5856aa77..d85f9eb301bd 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -96,7 +96,7 @@ static int oui(u8 first, u8 second, u8 third) struct detailed_mode_closure { struct drm_connector *connector; - const struct edid *edid; + const struct drm_edid *drm_edid; bool preferred; u32 quirks; int modes; @@ -3226,25 +3226,25 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) return; closure->modes += drm_dmt_modes_for_range(closure->connector, - closure->edid, + closure->drm_edid->edid, timing); - if (!version_greater(closure->edid, 1, 1)) + if (!version_greater(closure->drm_edid->edid, 1, 1)) return; /* GTF not defined yet */ switch (range->flags) { case 0x02: /* secondary gtf, XXX could do more */ case 0x00: /* default gtf */ closure->modes += drm_gtf_modes_for_range(closure->connector, - closure->edid, + closure->drm_edid->edid, timing); break; case 0x04: /* cvt, only in 1.4+ */ - if (!version_greater(closure->edid, 1, 3)) + if (!version_greater(closure->drm_edid->edid, 1, 3)) break; closure->modes += drm_cvt_modes_for_range(closure->connector, - closure->edid, + closure->drm_edid->edid, timing); break; case 0x01: /* just the ranges, no formula */ @@ -3258,7 +3258,7 @@ static int add_inferred_modes(struct drm_connector *connector, { struct detailed_mode_closure closure = { .connector = connector, - .edid = drm_edid->edid, + .drm_edid = drm_edid, }; if (version_greater(drm_edid->edid, 1, 0)) @@ -3323,7 +3323,7 @@ static int add_established_modes(struct drm_connector *connector, int i, modes = 0; struct detailed_mode_closure closure = { .connector = connector, - .edid = edid, + .drm_edid = drm_edid, }; for (i = 0; i <= EDID_EST_TIMINGS; i++) { @@ -3351,7 +3351,6 @@ do_standard_modes(const struct detailed_timing *timing, void *c) struct detailed_mode_closure *closure = c; const struct detailed_non_pixel *data = &timing->data.other_data; struct drm_connector *connector = closure->connector; - const struct edid *edid = closure->edid; int i; if (!is_display_descriptor(timing, EDID_DETAIL_STD_MODES)) @@ -3361,7 +3360,7 @@ do_standard_modes(const struct detailed_timing *timing, void *c) const struct std_timing *std = &data->data.timings[i]; struct drm_display_mode *newmode; - newmode = drm_mode_std(connector, edid, std); + newmode = drm_mode_std(connector, closure->drm_edid->edid, std); if (newmode) { drm_mode_probed_add(connector, newmode); closure->modes++; @@ -3380,7 +3379,7 @@ static int add_standard_modes(struct drm_connector *connector, int i, modes = 0; struct detailed_mode_closure closure = { .connector = connector, - .edid = drm_edid->edid, + .drm_edid = drm_edid, }; for (i = 0; i < EDID_STD_TIMINGS; i++) { @@ -3471,7 +3470,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) { struct detailed_mode_closure closure = { .connector = connector, - .edid = drm_edid->edid, + .drm_edid = drm_edid, }; if (version_greater(drm_edid->edid, 1, 2)) @@ -3494,7 +3493,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c) return; newmode = drm_mode_detailed(closure->connector->dev, - closure->edid, timing, + closure->drm_edid->edid, timing, closure->quirks); if (!newmode) return; @@ -3525,7 +3524,7 @@ static int add_detailed_modes(struct drm_connector *connector, { struct detailed_mode_closure closure = { .connector = connector, - .edid = drm_edid->edid, + .drm_edid = drm_edid, .preferred = true, .quirks = quirks, }; From f0d080ff429129b16332f17a906ad2123d9c6317 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:08 +0300 Subject: [PATCH 052/170] drm/edid: convert drm_mode_detailed() to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/6e4625d529ee4bfb2f6ebbfef5fb707d65a0554d.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d85f9eb301bd..91cca4279e3f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2928,7 +2928,7 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode, * drm_display_mode. */ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, - const struct edid *edid, + const struct drm_edid *drm_edid, const struct detailed_timing *timing, u32 quirks) { @@ -3016,8 +3016,8 @@ set_size: } if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { - mode->width_mm = edid->width_cm * 10; - mode->height_mm = edid->height_cm * 10; + mode->width_mm = drm_edid->edid->width_cm * 10; + mode->height_mm = drm_edid->edid->height_cm * 10; } mode->type = DRM_MODE_TYPE_DRIVER; @@ -3493,7 +3493,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c) return; newmode = drm_mode_detailed(closure->connector->dev, - closure->drm_edid->edid, timing, + closure->drm_edid, timing, closure->quirks); if (!newmode) return; From 084c7a7c7a0a0cab35d959e1b14d45a0c6221f49 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:09 +0300 Subject: [PATCH 053/170] drm/edid: convert drm_dmt_modes_for_range() to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/a8f393263225321e74f1e2884e81b3346d1adf20.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 91cca4279e3f..0741c7c5cf48 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3121,16 +3121,16 @@ static bool valid_inferred_mode(const struct drm_connector *connector, return ok; } -static int -drm_dmt_modes_for_range(struct drm_connector *connector, const struct edid *edid, - const struct detailed_timing *timing) +static int drm_dmt_modes_for_range(struct drm_connector *connector, + const struct drm_edid *drm_edid, + const struct detailed_timing *timing) { int i, modes = 0; struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { - if (mode_in_range(drm_dmt_modes + i, edid, timing) && + if (mode_in_range(drm_dmt_modes + i, drm_edid->edid, timing) && valid_inferred_mode(connector, drm_dmt_modes + i)) { newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); if (newmode) { @@ -3226,7 +3226,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) return; closure->modes += drm_dmt_modes_for_range(closure->connector, - closure->drm_edid->edid, + closure->drm_edid, timing); if (!version_greater(closure->drm_edid->edid, 1, 1)) From a77f7c89e62c6dfe405a64995812746f27adc510 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:10 +0300 Subject: [PATCH 054/170] drm/edid: convert drm_gtf_modes_for_range() to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/b50377ce67fd3cee6628ea5865c80fa0fa7da990.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0741c7c5cf48..4a25676cddf9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3156,9 +3156,9 @@ void drm_mode_fixup_1366x768(struct drm_display_mode *mode) } } -static int -drm_gtf_modes_for_range(struct drm_connector *connector, const struct edid *edid, - const struct detailed_timing *timing) +static int drm_gtf_modes_for_range(struct drm_connector *connector, + const struct drm_edid *drm_edid, + const struct detailed_timing *timing) { int i, modes = 0; struct drm_display_mode *newmode; @@ -3172,7 +3172,7 @@ drm_gtf_modes_for_range(struct drm_connector *connector, const struct edid *edid return modes; drm_mode_fixup_1366x768(newmode); - if (!mode_in_range(newmode, edid, timing) || + if (!mode_in_range(newmode, drm_edid->edid, timing) || !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; @@ -3236,7 +3236,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) case 0x02: /* secondary gtf, XXX could do more */ case 0x00: /* default gtf */ closure->modes += drm_gtf_modes_for_range(closure->connector, - closure->drm_edid->edid, + closure->drm_edid, timing); break; case 0x04: /* cvt, only in 1.4+ */ From 7428bfbdb7c4dc7323e6b6f0e327c3587e479e16 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:11 +0300 Subject: [PATCH 055/170] drm/edid: convert drm_cvt_modes_for_range() to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/c2c251a504933debacf78e1382ae665ae490ed40.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4a25676cddf9..2503e3510b8c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3185,14 +3185,14 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector, return modes; } -static int -drm_cvt_modes_for_range(struct drm_connector *connector, const struct edid *edid, - const struct detailed_timing *timing) +static int drm_cvt_modes_for_range(struct drm_connector *connector, + const struct drm_edid *drm_edid, + const struct detailed_timing *timing) { int i, modes = 0; struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; - bool rb = drm_monitor_supports_rb(edid); + bool rb = drm_monitor_supports_rb(drm_edid->edid); for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; @@ -3202,7 +3202,7 @@ drm_cvt_modes_for_range(struct drm_connector *connector, const struct edid *edid return modes; drm_mode_fixup_1366x768(newmode); - if (!mode_in_range(newmode, edid, timing) || + if (!mode_in_range(newmode, drm_edid->edid, timing) || !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; @@ -3244,7 +3244,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) break; closure->modes += drm_cvt_modes_for_range(closure->connector, - closure->drm_edid->edid, + closure->drm_edid, timing); break; case 0x01: /* just the ranges, no formula */ From 67d87fac86dd4a04cc62dc0eddfb7c74ace4666d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:12 +0300 Subject: [PATCH 056/170] drm/edid: convert drm_mode_std() and children to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/9fb970d108a8bb666b87a590c74f480e0fd81cc8.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 52 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2503e3510b8c..08d41ef21680 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2673,11 +2673,11 @@ find_gtf2(const struct detailed_timing *descriptor, void *data) /* Secondary GTF curve kicks in above some break frequency */ static int -drm_gtf2_hbreak(const struct edid *edid) +drm_gtf2_hbreak(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.hfreq_start_khz) != 12); @@ -2685,11 +2685,11 @@ drm_gtf2_hbreak(const struct edid *edid) } static int -drm_gtf2_2c(const struct edid *edid) +drm_gtf2_2c(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.c) != 13); @@ -2697,11 +2697,11 @@ drm_gtf2_2c(const struct edid *edid) } static int -drm_gtf2_m(const struct edid *edid) +drm_gtf2_m(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.m) != 14); @@ -2709,11 +2709,11 @@ drm_gtf2_m(const struct edid *edid) } static int -drm_gtf2_k(const struct edid *edid) +drm_gtf2_k(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.k) != 16); @@ -2721,11 +2721,11 @@ drm_gtf2_k(const struct edid *edid) } static int -drm_gtf2_2j(const struct edid *edid) +drm_gtf2_2j(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.j) != 17); @@ -2733,12 +2733,14 @@ drm_gtf2_2j(const struct edid *edid) } /* Get standard timing level (CVT/GTF/DMT). */ -static int standard_timing_level(const struct edid *edid) +static int standard_timing_level(const struct drm_edid *drm_edid) { + const struct edid *edid = drm_edid->edid; + if (edid->revision >= 2) { if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) return LEVEL_CVT; - if (drm_gtf2_hbreak(edid)) + if (drm_gtf2_hbreak(drm_edid)) return LEVEL_GTF2; if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) return LEVEL_GTF; @@ -2770,9 +2772,9 @@ static int drm_mode_hsync(const struct drm_display_mode *mode) * Take the standard timing params (in this case width, aspect, and refresh) * and convert them into a real mode using CVT/GTF/DMT. */ -static struct drm_display_mode * -drm_mode_std(struct drm_connector *connector, const struct edid *edid, - const struct std_timing *t) +static struct drm_display_mode *drm_mode_std(struct drm_connector *connector, + const struct drm_edid *drm_edid, + const struct std_timing *t) { struct drm_device *dev = connector->dev; struct drm_display_mode *m, *mode = NULL; @@ -2782,7 +2784,7 @@ drm_mode_std(struct drm_connector *connector, const struct edid *edid, >> EDID_TIMING_ASPECT_SHIFT; unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) >> EDID_TIMING_VFREQ_SHIFT; - int timing_level = standard_timing_level(edid); + int timing_level = standard_timing_level(drm_edid); if (bad_std_timing(t->hsize, t->vfreq_aspect)) return NULL; @@ -2793,7 +2795,7 @@ drm_mode_std(struct drm_connector *connector, const struct edid *edid, vrefresh_rate = vfreq + 60; /* the vdisplay is calculated based on the aspect ratio */ if (aspect_ratio == 0) { - if (edid->revision < 3) + if (drm_edid->edid->revision < 3) vsize = hsize; else vsize = (hsize * 10) / 16; @@ -2836,7 +2838,7 @@ drm_mode_std(struct drm_connector *connector, const struct edid *edid, } /* check whether it can be found in default mode table */ - if (drm_monitor_supports_rb(edid)) { + if (drm_monitor_supports_rb(drm_edid->edid)) { mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, true); if (mode) @@ -2862,14 +2864,14 @@ drm_mode_std(struct drm_connector *connector, const struct edid *edid, mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); if (!mode) return NULL; - if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) { + if (drm_mode_hsync(mode) > drm_gtf2_hbreak(drm_edid)) { drm_mode_destroy(dev, mode); mode = drm_gtf_mode_complex(dev, hsize, vsize, vrefresh_rate, 0, 0, - drm_gtf2_m(edid), - drm_gtf2_2c(edid), - drm_gtf2_k(edid), - drm_gtf2_2j(edid)); + drm_gtf2_m(drm_edid), + drm_gtf2_2c(drm_edid), + drm_gtf2_k(drm_edid), + drm_gtf2_2j(drm_edid)); } break; case LEVEL_CVT: @@ -3360,7 +3362,7 @@ do_standard_modes(const struct detailed_timing *timing, void *c) const struct std_timing *std = &data->data.timings[i]; struct drm_display_mode *newmode; - newmode = drm_mode_std(connector, closure->drm_edid->edid, std); + newmode = drm_mode_std(connector, closure->drm_edid, std); if (newmode) { drm_mode_probed_add(connector, newmode); closure->modes++; @@ -3385,7 +3387,7 @@ static int add_standard_modes(struct drm_connector *connector, for (i = 0; i < EDID_STD_TIMINGS; i++) { struct drm_display_mode *newmode; - newmode = drm_mode_std(connector, drm_edid->edid, + newmode = drm_mode_std(connector, drm_edid, &drm_edid->edid->standard_timings[i]); if (newmode) { drm_mode_probed_add(connector, newmode); From 874d98eed71ae678ab364d4c16060955b8b245ae Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:13 +0300 Subject: [PATCH 057/170] drm/edid: convert mode_in_range() and drm_monitor_supports_rb() to drm_edid We'll need to propagate drm_edid everywhere. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/aac7dd14ce8c266491e9dfae12cad00fecdcd2e3.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 08d41ef21680..7461d5df9e0a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2645,16 +2645,16 @@ is_rb(const struct detailed_timing *descriptor, void *data) /* EDID 1.4 defines this explicitly. For EDID 1.3, we guess, badly. */ static bool -drm_monitor_supports_rb(const struct edid *edid) +drm_monitor_supports_rb(const struct drm_edid *drm_edid) { - if (edid->revision >= 4) { + if (drm_edid->edid->revision >= 4) { bool ret = false; - drm_for_each_detailed_block(edid, is_rb, &ret); + drm_for_each_detailed_block(drm_edid->edid, is_rb, &ret); return ret; } - return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0); + return ((drm_edid->edid->input & DRM_EDID_INPUT_DIGITAL) != 0); } static void @@ -2838,7 +2838,7 @@ static struct drm_display_mode *drm_mode_std(struct drm_connector *connector, } /* check whether it can be found in default mode table */ - if (drm_monitor_supports_rb(drm_edid->edid)) { + if (drm_monitor_supports_rb(drm_edid)) { mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, true); if (mode) @@ -3077,10 +3077,11 @@ range_pixel_clock(const struct edid *edid, const u8 *t) return t[9] * 10000 + 5001; } -static bool -mode_in_range(const struct drm_display_mode *mode, const struct edid *edid, - const struct detailed_timing *timing) +static bool mode_in_range(const struct drm_display_mode *mode, + const struct drm_edid *drm_edid, + const struct detailed_timing *timing) { + const struct edid *edid = drm_edid->edid; u32 max_clock; const u8 *t = (const u8 *)timing; @@ -3099,7 +3100,7 @@ mode_in_range(const struct drm_display_mode *mode, const struct edid *edid, if (t[13] && mode->hdisplay > 8 * (t[13] + (256 * (t[12]&0x3)))) return false; - if (mode_is_rb(mode) && !drm_monitor_supports_rb(edid)) + if (mode_is_rb(mode) && !drm_monitor_supports_rb(drm_edid)) return false; return true; @@ -3132,7 +3133,7 @@ static int drm_dmt_modes_for_range(struct drm_connector *connector, struct drm_device *dev = connector->dev; for (i = 0; i < ARRAY_SIZE(drm_dmt_modes); i++) { - if (mode_in_range(drm_dmt_modes + i, drm_edid->edid, timing) && + if (mode_in_range(drm_dmt_modes + i, drm_edid, timing) && valid_inferred_mode(connector, drm_dmt_modes + i)) { newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); if (newmode) { @@ -3174,7 +3175,7 @@ static int drm_gtf_modes_for_range(struct drm_connector *connector, return modes; drm_mode_fixup_1366x768(newmode); - if (!mode_in_range(newmode, drm_edid->edid, timing) || + if (!mode_in_range(newmode, drm_edid, timing) || !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; @@ -3194,7 +3195,7 @@ static int drm_cvt_modes_for_range(struct drm_connector *connector, int i, modes = 0; struct drm_display_mode *newmode; struct drm_device *dev = connector->dev; - bool rb = drm_monitor_supports_rb(drm_edid->edid); + bool rb = drm_monitor_supports_rb(drm_edid); for (i = 0; i < ARRAY_SIZE(extra_modes); i++) { const struct minimode *m = &extra_modes[i]; @@ -3204,7 +3205,7 @@ static int drm_cvt_modes_for_range(struct drm_connector *connector, return modes; drm_mode_fixup_1366x768(newmode); - if (!mode_in_range(newmode, drm_edid->edid, timing) || + if (!mode_in_range(newmode, drm_edid, timing) || !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; From 2c54f87cf2fb99826ded617fd0484e688ecfe882 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:14 +0300 Subject: [PATCH 058/170] drm/edid: convert get_monitor_name() to drm_edid We'll need to propagate drm_edid everywhere. v2: Drop incorrect NULL name check (Dan Carpenter) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/c940aad14f323ef3a7907a0fb534011deb1589a9.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7461d5df9e0a..ce6f163e3c79 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4830,15 +4830,15 @@ monitor_name(const struct detailed_timing *timing, void *data) *res = timing->data.other_data.data.str.str; } -static int get_monitor_name(const struct edid *edid, char name[13]) +static int get_monitor_name(const struct drm_edid *drm_edid, char name[13]) { const char *edid_name = NULL; int mnl; - if (!edid || !name) + if (!drm_edid || !name) return 0; - drm_for_each_detailed_block(edid, monitor_name, &edid_name); + drm_for_each_detailed_block(drm_edid->edid, monitor_name, &edid_name); for (mnl = 0; edid_name && mnl < 13; mnl++) { if (edid_name[mnl] == 0x0a) break; @@ -4858,14 +4858,22 @@ static int get_monitor_name(const struct edid *edid, char name[13]) */ void drm_edid_get_monitor_name(const struct edid *edid, char *name, int bufsize) { - int name_length; - char buf[13]; + int name_length = 0; if (bufsize <= 0) return; - name_length = min(get_monitor_name(edid, buf), bufsize - 1); - memcpy(name, buf, name_length); + if (edid) { + char buf[13]; + struct drm_edid drm_edid = { + .edid = edid, + .size = edid_size(edid), + }; + + name_length = min(get_monitor_name(&drm_edid, buf), bufsize - 1); + memcpy(name, buf, name_length); + } + name[name_length] = '\0'; } EXPORT_SYMBOL(drm_edid_get_monitor_name); @@ -4905,7 +4913,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, if (!drm_edid) return; - mnl = get_monitor_name(drm_edid->edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); + mnl = get_monitor_name(drm_edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT; From 45aa2336fa6dbfa73d9081f75a4b813e747a55aa Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:15 +0300 Subject: [PATCH 059/170] drm/edid: convert drm_for_each_detailed_block() to drm_edid We'll need to propagate drm_edid everywhere. v2: Fix checkpatch warning on superfluous parens Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/bfd06d64235393012b2f3626d5764350de5f5321.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ce6f163e3c79..c311e0b9c65d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2598,20 +2598,20 @@ vtb_for_each_detailed_block(const u8 *ext, detailed_cb *cb, void *closure) cb((const struct detailed_timing *)(det_base + 18 * i), closure); } -static void -drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *closure) +static void drm_for_each_detailed_block(const struct drm_edid *drm_edid, + detailed_cb *cb, void *closure) { struct drm_edid_iter edid_iter; const u8 *ext; int i; - if (edid == NULL) + if (!drm_edid) return; for (i = 0; i < EDID_DETAILED_TIMINGS; i++) - cb(&(edid->detailed_timings[i]), closure); + cb(&drm_edid->edid->detailed_timings[i], closure); - drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_begin(drm_edid->edid, &edid_iter); drm_edid_iter_for_each(ext, &edid_iter) { switch (*ext) { case CEA_EXT: @@ -2650,7 +2650,7 @@ drm_monitor_supports_rb(const struct drm_edid *drm_edid) if (drm_edid->edid->revision >= 4) { bool ret = false; - drm_for_each_detailed_block(drm_edid->edid, is_rb, &ret); + drm_for_each_detailed_block(drm_edid, is_rb, &ret); return ret; } @@ -2677,7 +2677,7 @@ drm_gtf2_hbreak(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.hfreq_start_khz) != 12); @@ -2689,7 +2689,7 @@ drm_gtf2_2c(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.c) != 13); @@ -2701,7 +2701,7 @@ drm_gtf2_m(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.m) != 14); @@ -2713,7 +2713,7 @@ drm_gtf2_k(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.k) != 16); @@ -2725,7 +2725,7 @@ drm_gtf2_2j(const struct drm_edid *drm_edid) { const struct detailed_timing *descriptor = NULL; - drm_for_each_detailed_block(drm_edid->edid, find_gtf2, &descriptor); + drm_for_each_detailed_block(drm_edid, find_gtf2, &descriptor); BUILD_BUG_ON(offsetof(typeof(*descriptor), data.other_data.data.range.formula.gtf2.j) != 17); @@ -3265,7 +3265,7 @@ static int add_inferred_modes(struct drm_connector *connector, }; if (version_greater(drm_edid->edid, 1, 0)) - drm_for_each_detailed_block(drm_edid->edid, do_inferred_modes, &closure); + drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure); return closure.modes; } @@ -3342,7 +3342,7 @@ static int add_established_modes(struct drm_connector *connector, } if (version_greater(edid, 1, 0)) - drm_for_each_detailed_block(drm_edid->edid, do_established_modes, + drm_for_each_detailed_block(drm_edid, do_established_modes, &closure); return modes + closure.modes; @@ -3397,7 +3397,7 @@ static int add_standard_modes(struct drm_connector *connector, } if (version_greater(drm_edid->edid, 1, 0)) - drm_for_each_detailed_block(drm_edid->edid, do_standard_modes, + drm_for_each_detailed_block(drm_edid, do_standard_modes, &closure); /* XXX should also look for standard codes in VTB blocks */ @@ -3477,7 +3477,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) }; if (version_greater(drm_edid->edid, 1, 2)) - drm_for_each_detailed_block(drm_edid->edid, do_cvt_mode, &closure); + drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure); /* XXX should also look for CVT codes in VTB blocks */ @@ -3536,7 +3536,7 @@ static int add_detailed_modes(struct drm_connector *connector, closure.preferred = (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); - drm_for_each_detailed_block(drm_edid->edid, do_detailed_mode, &closure); + drm_for_each_detailed_block(drm_edid, do_detailed_mode, &closure); return closure.modes; } @@ -4838,7 +4838,7 @@ static int get_monitor_name(const struct drm_edid *drm_edid, char name[13]) if (!drm_edid || !name) return 0; - drm_for_each_detailed_block(drm_edid->edid, monitor_name, &edid_name); + drm_for_each_detailed_block(drm_edid, monitor_name, &edid_name); for (mnl = 0; edid_name && mnl < 13; mnl++) { if (edid_name[mnl] == 0x0a) break; @@ -5559,7 +5559,7 @@ static void drm_get_monitor_range(struct drm_connector *connector, if (!version_greater(drm_edid->edid, 1, 1)) return; - drm_for_each_detailed_block(drm_edid->edid, get_monitor_range, + drm_for_each_detailed_block(drm_edid, get_monitor_range, &info->monitor_range); DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n", From bba4b6470b02c2d9a5074a40cff7246d3356f460 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:16 +0300 Subject: [PATCH 060/170] drm/edid: add drm_edid helper for drm_edid_to_sad() We'll need to propagate drm_edid everywhere. v2: Handle NULL EDID pointer (Ville, CI) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/14aa1e44caa2e9c1b54c2f2a471d2fd7d3f62d5d.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c311e0b9c65d..1e4228aa10fd 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4972,24 +4972,14 @@ static void drm_edid_to_eld(struct drm_connector *connector, drm_eld_size(eld), total_sad_count); } -/** - * drm_edid_to_sad - extracts SADs from EDID - * @edid: EDID to parse - * @sads: pointer that will be set to the extracted SADs - * - * Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it. - * - * Note: The returned pointer needs to be freed using kfree(). - * - * Return: The number of found SADs or negative number on error. - */ -int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) +static int _drm_edid_to_sad(const struct drm_edid *drm_edid, + struct cea_sad **sads) { const struct cea_db *db; struct cea_db_iter iter; int count = 0; - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { int j; @@ -5015,6 +5005,24 @@ int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) return count; } + +/** + * drm_edid_to_sad - extracts SADs from EDID + * @edid: EDID to parse + * @sads: pointer that will be set to the extracted SADs + * + * Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it. + * + * Note: The returned pointer needs to be freed using kfree(). + * + * Return: The number of found SADs or negative number on error. + */ +int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) +{ + struct drm_edid drm_edid; + + return _drm_edid_to_sad(drm_edid_legacy_init(&drm_edid, edid), sads); +} EXPORT_SYMBOL(drm_edid_to_sad); /** From 027034511c6a1e3ea96122f7626b89b6d339ed49 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:17 +0300 Subject: [PATCH 061/170] drm/edid: add drm_edid helper for drm_edid_to_speaker_allocation() We'll need to propagate drm_edid everywhere.' v2: Handle NULL EDID pointer (Ville, CI) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/770d095c93274969c4b86480e07044e16a7b5760.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1e4228aa10fd..4e7811c2eb07 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5025,25 +5025,14 @@ int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads) } EXPORT_SYMBOL(drm_edid_to_sad); -/** - * drm_edid_to_speaker_allocation - extracts Speaker Allocation Data Blocks from EDID - * @edid: EDID to parse - * @sadb: pointer to the speaker block - * - * Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it. - * - * Note: The returned pointer needs to be freed using kfree(). - * - * Return: The number of found Speaker Allocation Blocks or negative number on - * error. - */ -int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb) +static int _drm_edid_to_speaker_allocation(const struct drm_edid *drm_edid, + u8 **sadb) { const struct cea_db *db; struct cea_db_iter iter; int count = 0; - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_SPEAKER && cea_db_payload_len(db) == 3) { @@ -5061,6 +5050,26 @@ int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb) return count; } + +/** + * drm_edid_to_speaker_allocation - extracts Speaker Allocation Data Blocks from EDID + * @edid: EDID to parse + * @sadb: pointer to the speaker block + * + * Looks for CEA EDID block and extracts the Speaker Allocation Data Block from it. + * + * Note: The returned pointer needs to be freed using kfree(). + * + * Return: The number of found Speaker Allocation Blocks or negative number on + * error. + */ +int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb) +{ + struct drm_edid drm_edid; + + return _drm_edid_to_speaker_allocation(drm_edid_legacy_init(&drm_edid, edid), + sadb); +} EXPORT_SYMBOL(drm_edid_to_speaker_allocation); /** From 3176d0925027727ec37e388e9363f124c2c52ae9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:18 +0300 Subject: [PATCH 062/170] drm/edid: add drm_edid helper for drm_detect_hdmi_monitor() We'll need to propagate drm_edid everywhere. v2: Handle NULL EDID pointer (Ville, CI) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/2fbee0d7b544b44ef0866bb154beefac5d260bec.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 41 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 4e7811c2eb07..ad5e372f046b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5113,6 +5113,28 @@ int drm_av_sync_delay(struct drm_connector *connector, } EXPORT_SYMBOL(drm_av_sync_delay); +static bool _drm_detect_hdmi_monitor(const struct drm_edid *drm_edid) +{ + const struct cea_db *db; + struct cea_db_iter iter; + bool hdmi = false; + + /* + * Because HDMI identifier is in Vendor Specific Block, + * search it from all data blocks of CEA extension. + */ + cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + cea_db_iter_for_each(db, &iter) { + if (cea_db_is_hdmi_vsdb(db)) { + hdmi = true; + break; + } + } + cea_db_iter_end(&iter); + + return hdmi; +} + /** * drm_detect_hdmi_monitor - detect whether monitor is HDMI * @edid: monitor EDID information @@ -5126,24 +5148,9 @@ EXPORT_SYMBOL(drm_av_sync_delay); */ bool drm_detect_hdmi_monitor(const struct edid *edid) { - const struct cea_db *db; - struct cea_db_iter iter; - bool hdmi = false; + struct drm_edid drm_edid; - /* - * Because HDMI identifier is in Vendor Specific Block, - * search it from all data blocks of CEA extension. - */ - cea_db_iter_edid_begin(edid, &iter); - cea_db_iter_for_each(db, &iter) { - if (cea_db_is_hdmi_vsdb(db)) { - hdmi = true; - break; - } - } - cea_db_iter_end(&iter); - - return hdmi; + return _drm_detect_hdmi_monitor(drm_edid_legacy_init(&drm_edid, edid)); } EXPORT_SYMBOL(drm_detect_hdmi_monitor); From 0c057877cbdf261efa7874474f48c715cd6401ba Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:19 +0300 Subject: [PATCH 063/170] drm/edid: add drm_edid helper for drm_detect_monitor_audio() We'll need to propagate drm_edid everywhere. v2: Handle NULL EDID pointer (Ville, CI) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/ea33244c473ace1bc72a7e87f97580f00705a683.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ad5e372f046b..f3f31534b78b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5154,19 +5154,7 @@ bool drm_detect_hdmi_monitor(const struct edid *edid) } EXPORT_SYMBOL(drm_detect_hdmi_monitor); -/** - * drm_detect_monitor_audio - check monitor audio capability - * @edid: EDID block to scan - * - * Monitor should have CEA extension block. - * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic - * audio' only. If there is any audio extension block and supported - * audio format, assume at least 'basic audio' support, even if 'basic - * audio' is not defined in EDID. - * - * Return: True if the monitor supports audio, false otherwise. - */ -bool drm_detect_monitor_audio(const struct edid *edid) +static bool _drm_detect_monitor_audio(const struct drm_edid *drm_edid) { struct drm_edid_iter edid_iter; const struct cea_db *db; @@ -5174,7 +5162,7 @@ bool drm_detect_monitor_audio(const struct edid *edid) const u8 *edid_ext; bool has_audio = false; - drm_edid_iter_begin(edid, &edid_iter); + drm_edid_iter_begin(drm_edid ? drm_edid->edid : NULL, &edid_iter); drm_edid_iter_for_each(edid_ext, &edid_iter) { if (edid_ext[0] == CEA_EXT) { has_audio = edid_ext[3] & EDID_BASIC_AUDIO; @@ -5189,7 +5177,7 @@ bool drm_detect_monitor_audio(const struct edid *edid) goto end; } - cea_db_iter_edid_begin(edid, &iter); + cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { const u8 *data = cea_db_data(db); @@ -5207,6 +5195,25 @@ bool drm_detect_monitor_audio(const struct edid *edid) end: return has_audio; } + +/** + * drm_detect_monitor_audio - check monitor audio capability + * @edid: EDID block to scan + * + * Monitor should have CEA extension block. + * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic + * audio' only. If there is any audio extension block and supported + * audio format, assume at least 'basic audio' support, even if 'basic + * audio' is not defined in EDID. + * + * Return: True if the monitor supports audio, false otherwise. + */ +bool drm_detect_monitor_audio(const struct edid *edid) +{ + struct drm_edid drm_edid; + + return _drm_detect_monitor_audio(drm_edid_legacy_init(&drm_edid, edid)); +} EXPORT_SYMBOL(drm_detect_monitor_audio); From 5e87b2e5171621ff00ec197c9af15bc3aa405b6b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:20 +0300 Subject: [PATCH 064/170] drm/edid: convert cea_db_iter_edid_begin() to drm_edid We'll need to propagate drm_edid everywhere. v2: Handle NULL drm_edid Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/7d9f060815086e1e4ea037dbfb9fd8ad54d1f25e.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index f3f31534b78b..16eaf9acf8be 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4448,12 +4448,13 @@ static bool cea_db_is_vendor(const struct cea_db *db, int vendor_oui) oui(data[2], data[1], data[0]) == vendor_oui; } -static void cea_db_iter_edid_begin(const struct edid *edid, struct cea_db_iter *iter) +static void cea_db_iter_edid_begin(const struct drm_edid *drm_edid, + struct cea_db_iter *iter) { memset(iter, 0, sizeof(*iter)); - drm_edid_iter_begin(edid, &iter->edid_iter); - displayid_iter_edid_begin(edid, &iter->displayid_iter); + drm_edid_iter_begin(drm_edid ? drm_edid->edid : NULL, &iter->edid_iter); + displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter->displayid_iter); } static const struct cea_db * @@ -4675,7 +4676,7 @@ static int add_cea_modes(struct drm_connector *connector, struct cea_db_iter iter; int modes = 0; - cea_db_iter_edid_begin(drm_edid->edid, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { const u8 *hdmi = NULL, *video = NULL; u8 hdmi_len = 0, video_len = 0; @@ -4926,7 +4927,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, eld[DRM_ELD_PRODUCT_CODE0] = drm_edid->edid->prod_code[0]; eld[DRM_ELD_PRODUCT_CODE1] = drm_edid->edid->prod_code[1]; - cea_db_iter_edid_begin(drm_edid->edid, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { const u8 *data = cea_db_data(db); int len = cea_db_payload_len(db); @@ -4979,7 +4980,7 @@ static int _drm_edid_to_sad(const struct drm_edid *drm_edid, struct cea_db_iter iter; int count = 0; - cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { int j; @@ -5032,7 +5033,7 @@ static int _drm_edid_to_speaker_allocation(const struct drm_edid *drm_edid, struct cea_db_iter iter; int count = 0; - cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_SPEAKER && cea_db_payload_len(db) == 3) { @@ -5123,7 +5124,7 @@ static bool _drm_detect_hdmi_monitor(const struct drm_edid *drm_edid) * Because HDMI identifier is in Vendor Specific Block, * search it from all data blocks of CEA extension. */ - cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_is_hdmi_vsdb(db)) { hdmi = true; @@ -5177,7 +5178,7 @@ static bool _drm_detect_monitor_audio(const struct drm_edid *drm_edid) goto end; } - cea_db_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { const u8 *data = cea_db_data(db); @@ -5536,7 +5537,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, } drm_edid_iter_end(&edid_iter); - cea_db_iter_edid_begin(drm_edid->edid, &iter); + cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { /* FIXME: convert parsers to use struct cea_db */ const u8 *data = (const u8 *)db; From bbded689680f0f2e65d4a57d0dfa654671052d56 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:21 +0300 Subject: [PATCH 065/170] drm/edid: convert drm_edid_iter_begin() to drm_edid We'll need to propagate drm_edid everywhere. v2: Rebase Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/24dfb5fd9026ebef573bb55b368b94e56cae5cec.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 16eaf9acf8be..08fb6b0bb748 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1632,36 +1632,36 @@ static const struct drm_edid *drm_edid_legacy_init(struct drm_edid *drm_edid, * struct drm_edid_iter iter; * const u8 *block; * - * drm_edid_iter_begin(edid, &iter); + * drm_edid_iter_begin(drm_edid, &iter); * drm_edid_iter_for_each(block, &iter) { * // do stuff with block * } * drm_edid_iter_end(&iter); */ struct drm_edid_iter { - const struct edid *edid; + const struct drm_edid *drm_edid; /* Current block index. */ int index; }; -static void drm_edid_iter_begin(const struct edid *edid, +static void drm_edid_iter_begin(const struct drm_edid *drm_edid, struct drm_edid_iter *iter) { memset(iter, 0, sizeof(*iter)); - iter->edid = edid; + iter->drm_edid = drm_edid; } static const void *__drm_edid_iter_next(struct drm_edid_iter *iter) { const void *block = NULL; - if (!iter->edid) + if (!iter->drm_edid) return NULL; - if (iter->index < edid_block_count(iter->edid)) - block = edid_block_data(iter->edid, iter->index++); + if (iter->index < edid_block_count(iter->drm_edid->edid)) + block = edid_block_data(iter->drm_edid->edid, iter->index++); return block; } @@ -2611,7 +2611,7 @@ static void drm_for_each_detailed_block(const struct drm_edid *drm_edid, for (i = 0; i < EDID_DETAILED_TIMINGS; i++) cb(&drm_edid->edid->detailed_timings[i], closure); - drm_edid_iter_begin(drm_edid->edid, &edid_iter); + drm_edid_iter_begin(drm_edid, &edid_iter); drm_edid_iter_for_each(ext, &edid_iter) { switch (*ext) { case CEA_EXT: @@ -4453,7 +4453,7 @@ static void cea_db_iter_edid_begin(const struct drm_edid *drm_edid, { memset(iter, 0, sizeof(*iter)); - drm_edid_iter_begin(drm_edid ? drm_edid->edid : NULL, &iter->edid_iter); + drm_edid_iter_begin(drm_edid, &iter->edid_iter); displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter->displayid_iter); } @@ -5163,7 +5163,7 @@ static bool _drm_detect_monitor_audio(const struct drm_edid *drm_edid) const u8 *edid_ext; bool has_audio = false; - drm_edid_iter_begin(drm_edid ? drm_edid->edid : NULL, &edid_iter); + drm_edid_iter_begin(drm_edid, &edid_iter); drm_edid_iter_for_each(edid_ext, &edid_iter) { if (edid_ext[0] == CEA_EXT) { has_audio = edid_ext[3] & EDID_BASIC_AUDIO; @@ -5516,7 +5516,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, struct cea_db_iter iter; const u8 *edid_ext; - drm_edid_iter_begin(drm_edid->edid, &edid_iter); + drm_edid_iter_begin(drm_edid, &edid_iter); drm_edid_iter_for_each(edid_ext, &edid_iter) { if (edid_ext[0] != CEA_EXT) continue; From c7b2dee4308b74391734ac675e66e6856a077f77 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:22 +0300 Subject: [PATCH 066/170] drm/edid: add drm_edid helper for drm_update_tile_info() We'll need to propagate drm_edid everywhere. v2: Handle NULL EDID pointer (Ville, CI) Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/5b36683b656446a4d9a172d4dca1cf9aca08a48b.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 08fb6b0bb748..30c33fdc52fc 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6364,15 +6364,15 @@ static void drm_parse_tiled_block(struct drm_connector *connector, } } -void drm_update_tile_info(struct drm_connector *connector, - const struct edid *edid) +static void _drm_update_tile_info(struct drm_connector *connector, + const struct drm_edid *drm_edid) { const struct displayid_block *block; struct displayid_iter iter; connector->has_tile = false; - displayid_iter_edid_begin(edid, &iter); + displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TILED_DISPLAY) drm_parse_tiled_block(connector, block); @@ -6384,3 +6384,11 @@ void drm_update_tile_info(struct drm_connector *connector, connector->tile_group = NULL; } } + +void drm_update_tile_info(struct drm_connector *connector, + const struct edid *edid) +{ + struct drm_edid drm_edid; + + _drm_update_tile_info(connector, drm_edid_legacy_init(&drm_edid, edid)); +} From d9ba1b4cbb2989c919198832f4ebd6eb8ba94da0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:23 +0300 Subject: [PATCH 067/170] drm/displayid: convert to drm_edid We'll need to propagate drm_edid everywhere. v2: Rebase Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/a52a6882e87a4bb6b1670918f3aba13f9b52f6de.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_displayid.c | 16 ++++++++-------- drivers/gpu/drm/drm_edid.c | 17 ++++++++++------- include/drm/drm_displayid.h | 6 +++--- include/drm/drm_edid.h | 6 ++++-- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 32da557b960f..38ea8203df45 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -33,11 +33,11 @@ static int validate_displayid(const u8 *displayid, int length, int idx) return 0; } -static const u8 *drm_find_displayid_extension(const struct edid *edid, +static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, int *length, int *idx, int *ext_index) { - const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); + const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index); const struct displayid_header *base; int ret; @@ -58,12 +58,12 @@ static const u8 *drm_find_displayid_extension(const struct edid *edid, return displayid; } -void displayid_iter_edid_begin(const struct edid *edid, +void displayid_iter_edid_begin(const struct drm_edid *drm_edid, struct displayid_iter *iter) { memset(iter, 0, sizeof(*iter)); - iter->edid = edid; + iter->drm_edid = drm_edid; } static const struct displayid_block * @@ -88,7 +88,7 @@ __displayid_iter_next(struct displayid_iter *iter) { const struct displayid_block *block; - if (!iter->edid) + if (!iter->drm_edid) return NULL; if (iter->section) { @@ -96,7 +96,7 @@ __displayid_iter_next(struct displayid_iter *iter) block = displayid_iter_block(iter); if (WARN_ON(!block)) { iter->section = NULL; - iter->edid = NULL; + iter->drm_edid = NULL; return NULL; } @@ -109,12 +109,12 @@ __displayid_iter_next(struct displayid_iter *iter) } for (;;) { - iter->section = drm_find_displayid_extension(iter->edid, + iter->section = drm_find_displayid_extension(iter->drm_edid, &iter->length, &iter->idx, &iter->ext_index); if (!iter->section) { - iter->edid = NULL; + iter->drm_edid = NULL; return NULL; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 30c33fdc52fc..99d9eec27ca8 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3563,10 +3563,13 @@ static int add_detailed_modes(struct drm_connector *connector, /* * Search EDID for CEA extension block. + * + * FIXME: Prefer not returning pointers to raw EDID data. */ -const u8 *drm_find_edid_extension(const struct edid *edid, +const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index) { + const struct edid *edid = drm_edid ? drm_edid->edid : NULL; const u8 *edid_ext = NULL; int i; @@ -3598,11 +3601,11 @@ static bool drm_edid_has_cta_extension(const struct drm_edid *drm_edid) bool found = false; /* Look for a top level CEA extension block */ - if (drm_find_edid_extension(drm_edid->edid, CEA_EXT, &ext_index)) + if (drm_find_edid_extension(drm_edid, CEA_EXT, &ext_index)) return true; /* CEA blocks can also be found embedded in a DisplayID block */ - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_CTA) { found = true; @@ -4454,7 +4457,7 @@ static void cea_db_iter_edid_begin(const struct drm_edid *drm_edid, memset(iter, 0, sizeof(*iter)); drm_edid_iter_begin(drm_edid, &iter->edid_iter); - displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter->displayid_iter); + displayid_iter_edid_begin(drm_edid, &iter->displayid_iter); } static const struct cea_db * @@ -5657,7 +5660,7 @@ static void drm_update_mso(struct drm_connector *connector, const struct displayid_block *block; struct displayid_iter iter; - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC) drm_parse_vesa_mso_data(connector, block); @@ -5872,7 +5875,7 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, struct displayid_iter iter; int num_modes = 0; - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) @@ -6372,7 +6375,7 @@ static void _drm_update_tile_info(struct drm_connector *connector, connector->has_tile = false; - displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TILED_DISPLAY) drm_parse_tiled_block(connector, block); diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h index 7ffbd9f7bfc7..49649eb8447e 100644 --- a/include/drm/drm_displayid.h +++ b/include/drm/drm_displayid.h @@ -25,7 +25,7 @@ #include #include -struct edid; +struct drm_edid; #define VESA_IEEE_OUI 0x3a0292 @@ -141,7 +141,7 @@ struct displayid_vesa_vendor_specific_block { /* DisplayID iteration */ struct displayid_iter { - const struct edid *edid; + const struct drm_edid *drm_edid; const u8 *section; int length; @@ -149,7 +149,7 @@ struct displayid_iter { int ext_index; }; -void displayid_iter_edid_begin(const struct edid *edid, +void displayid_iter_edid_begin(const struct drm_edid *drm_edid, struct displayid_iter *iter); const struct displayid_block * __displayid_iter_next(struct displayid_iter *iter); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c3204a58fb09..c61e75ab8f63 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -28,6 +28,7 @@ #include struct drm_device; +struct drm_edid; struct i2c_adapter; #define EDID_LENGTH 128 @@ -578,8 +579,9 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, struct drm_display_mode * drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); -const u8 *drm_find_edid_extension(const struct edid *edid, + +/* Interface based on struct drm_edid */ +const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index); - #endif /* __DRM_EDID_H__ */ From d0edd3c1a7e859a5899c26e2906e80f4ac798fa9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:24 +0300 Subject: [PATCH 068/170] drm/edid: convert version_greater() to drm_edid We'll need to propagate drm_edid everywhere. Also make version_greater() a function for type safety. Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/f1835a86294b392d075570001ed9009a48352670.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 99d9eec27ca8..929fc0e46751 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -45,10 +45,6 @@ #include "drm_crtc_internal.h" -#define version_greater(edid, maj, min) \ - (((edid)->version > (maj)) || \ - ((edid)->version == (maj) && (edid)->revision > (min))) - static int oui(u8 first, u8 second, u8 third) { return (first << 16) | (second << 8) | third; @@ -1576,6 +1572,15 @@ struct drm_edid { const struct edid *edid; }; +static bool version_greater(const struct drm_edid *drm_edid, + u8 version, u8 revision) +{ + const struct edid *edid = drm_edid->edid; + + return edid->version > version || + (edid->version == version && edid->revision > revision); +} + static int edid_extension_block_count(const struct edid *edid) { return edid->extensions; @@ -3232,7 +3237,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) closure->drm_edid, timing); - if (!version_greater(closure->drm_edid->edid, 1, 1)) + if (!version_greater(closure->drm_edid, 1, 1)) return; /* GTF not defined yet */ switch (range->flags) { @@ -3243,7 +3248,7 @@ do_inferred_modes(const struct detailed_timing *timing, void *c) timing); break; case 0x04: /* cvt, only in 1.4+ */ - if (!version_greater(closure->drm_edid->edid, 1, 3)) + if (!version_greater(closure->drm_edid, 1, 3)) break; closure->modes += drm_cvt_modes_for_range(closure->connector, @@ -3264,7 +3269,7 @@ static int add_inferred_modes(struct drm_connector *connector, .drm_edid = drm_edid, }; - if (version_greater(drm_edid->edid, 1, 0)) + if (version_greater(drm_edid, 1, 0)) drm_for_each_detailed_block(drm_edid, do_inferred_modes, &closure); return closure.modes; @@ -3341,7 +3346,7 @@ static int add_established_modes(struct drm_connector *connector, } } - if (version_greater(edid, 1, 0)) + if (version_greater(drm_edid, 1, 0)) drm_for_each_detailed_block(drm_edid, do_established_modes, &closure); @@ -3396,7 +3401,7 @@ static int add_standard_modes(struct drm_connector *connector, } } - if (version_greater(drm_edid->edid, 1, 0)) + if (version_greater(drm_edid, 1, 0)) drm_for_each_detailed_block(drm_edid, do_standard_modes, &closure); @@ -3476,7 +3481,7 @@ add_cvt_modes(struct drm_connector *connector, const struct drm_edid *drm_edid) .drm_edid = drm_edid, }; - if (version_greater(drm_edid->edid, 1, 2)) + if (version_greater(drm_edid, 1, 2)) drm_for_each_detailed_block(drm_edid, do_cvt_mode, &closure); /* XXX should also look for CVT codes in VTB blocks */ @@ -3532,7 +3537,7 @@ static int add_detailed_modes(struct drm_connector *connector, .quirks = quirks, }; - if (closure.preferred && !version_greater(drm_edid->edid, 1, 3)) + if (closure.preferred && !version_greater(drm_edid, 1, 3)) closure.preferred = (drm_edid->edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING); @@ -5591,7 +5596,7 @@ static void drm_get_monitor_range(struct drm_connector *connector, { struct drm_display_info *info = &connector->display_info; - if (!version_greater(drm_edid->edid, 1, 1)) + if (!version_greater(drm_edid, 1, 1)) return; drm_for_each_detailed_block(drm_edid, get_monitor_range, From d0956e2c520c9d730979a9669f27a77d40acac13 Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Wed, 11 May 2022 07:35:14 -0400 Subject: [PATCH 069/170] dt-bindings: display: panel: feiyang, fy07024di26a30d: make reset gpio optional Some implementations do not use the reset signal, instead tying it to dvdd. Make the reset gpio optional to permit this. Signed-off-by: Peter Geis Acked-by: Rob Herring Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220511113517.4172962-2-pgwipeout@gmail.com --- .../bindings/display/panel/feiyang,fy07024di26a30d.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml b/Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml index 95acf9e96f1c..1cf84c8dd85e 100644 --- a/Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml +++ b/Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml @@ -35,7 +35,6 @@ required: - reg - avdd-supply - dvdd-supply - - reset-gpios additionalProperties: false From de5db71e4c8c35ed5e92006e3064ce9230881ece Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Wed, 11 May 2022 07:35:15 -0400 Subject: [PATCH 070/170] drm/panel: feiyang-fy07024di26a30d: make reset gpio optional Some implementations do not use the reset signal, instead tying it to dvdd. Make the reset gpio optional to permit this. Signed-off-by: Peter Geis Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220511113517.4172962-3-pgwipeout@gmail.com --- drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index a9cd7135cb51..ee61d60eceae 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -209,7 +209,7 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->avdd), "Couldn't get avdd regulator\n"); - ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); + ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset), "Couldn't get our reset GPIO\n"); From 98526c5bbe3267d447ddd076b685439e3e1396c6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 9 May 2022 12:05:05 +0300 Subject: [PATCH 071/170] drm/rockchip: vop2: unlock on error path in vop2_crtc_atomic_enable() This error path needs an unlock before returning. Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver") Signed-off-by: Dan Carpenter Acked-by: Sascha Hauer Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/YnjZQRV9lpub2ET8@kili --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 774d8bee22b1..44838ad04c79 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1524,6 +1524,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, if (ret < 0) { drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n", vp->id, ret); + vop2_unlock(vop2); return; } From b6415bd7386bcf9d2e0d6ee1d4ef4186e7a87b24 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 11 May 2022 20:31:23 +0200 Subject: [PATCH 072/170] drm: Always warn if user-defined modes are not supported Print a warning if a user-specifed display mode is not supported by the display pipeline. Users specified the display mode on the kernel command line with the use of the video= parameter. Setting an unsupported mode will leave the console blank, so we should at least let the user know why. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220511183125.14294-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_modes.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 14b746f7ba97..40b7b245e98c 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1328,6 +1328,10 @@ void drm_mode_prune_invalid(struct drm_device *dev, list_for_each_entry_safe(mode, t, mode_list, head) { if (mode->status != MODE_OK) { list_del(&mode->head); + if (mode->type & DRM_MODE_TYPE_USERDEF) { + drm_warn(dev, "User-defined mode not supported: " + DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + } if (verbose) { drm_mode_debug_printmodeline(mode); DRM_DEBUG_KMS("Not using %s mode: %s\n", From b959eb4f5b7ea49b47e95c9047d33d1b1cf81057 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 11 May 2022 20:31:24 +0200 Subject: [PATCH 073/170] drm/client: Look for command-line modes first When picking a mode, first look for modes that have been specified by the user on the kernel's command line. Only if that fails, use the existing heuristic of picking a nearby mode from it's various parameters. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220511183125.14294-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_client_modeset.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index e6346a67cd98..b777faa87f04 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -165,6 +165,17 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector) struct drm_display_mode *mode; bool prefer_non_interlace; + /* + * Find a user-defined mode. If the user gave us a valid + * mode on the kernel command line, it will show up in this + * list. + */ + + list_for_each_entry(mode, &connector->modes, head) { + if (mode->type & DRM_MODE_TYPE_USERDEF) + return mode; + } + cmdline_mode = &connector->cmdline_mode; if (cmdline_mode->specified == false) return NULL; From 0facdaa249c4e97346bc0b49c893e4a1d336b7dd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 11 May 2022 20:31:25 +0200 Subject: [PATCH 074/170] drm/client: Don't add new command-line mode Don't add a mode for the kernel's command-line parameters from within the DRM client code. Doing so can result in an unusable display. If there's no compatible command-line mode, the client will use one of the connector's preferred modes. All mode creation and validation has to be performed by the connector. When clients run, the connector's fill_modes callback has already processed the kernel parameters and validated each mode before adding it. The connector's mode list does not contain invalid modes. v2: * grammar in commit message (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220511183125.14294-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_client_modeset.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index b777faa87f04..48e6ce16439f 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -158,8 +158,7 @@ drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int return NULL; } -static struct drm_display_mode * -drm_connector_pick_cmdline_mode(struct drm_connector *connector) +static struct drm_display_mode *drm_connector_pick_cmdline_mode(struct drm_connector *connector) { struct drm_cmdline_mode *cmdline_mode; struct drm_display_mode *mode; @@ -180,11 +179,10 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector) if (cmdline_mode->specified == false) return NULL; - /* attempt to find a matching mode in the list of modes - * we have gotten so far, if not add a CVT mode that conforms + /* + * Attempt to find a matching mode in the list of modes we + * have gotten so far. */ - if (cmdline_mode->rb || cmdline_mode->margins) - goto create_mode; prefer_non_interlace = !cmdline_mode->interlace; again: @@ -218,12 +216,7 @@ again: goto again; } -create_mode: - mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode); - if (mode) - list_add(&mode->head, &connector->modes); - - return mode; + return NULL; } static bool drm_connector_enabled(struct drm_connector *connector, bool strict) From c577b2f43e80d707870a74de0fd726c51b206956 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Fri, 13 May 2022 10:49:00 +0200 Subject: [PATCH 075/170] drm/mgag200: Enable atomic gamma lut update Add support for atomic update of gamma lut. With this patch the "Night light" feature of gnome3 is working properly on mgag200. v2: - Add a default linear gamma function - renamed functions with mgag200 prefix - use format's 4cc code instead of bit depth - use better interpolation for 16bits gamma - remove legacy function mga_crtc_load_lut() - can't remove the call to drm_mode_crtc_set_gamma_size() because it doesn't work with userspace. - other small refactors v3: - change mgag200_crtc_set_gamma*() argument to struct drm_format_info *format - fix printk format to %p4cc for 4cc and %zu for size_t - rebased to drm-misc-next. Signed-off-by: Jocelyn Falempe Tested-by: Thomas Zimmermann Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220513084900.1832381-1-jfalempe@redhat.com --- drivers/gpu/drm/mgag200/mgag200_mode.c | 131 ++++++++++++++++--------- 1 file changed, 85 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index dec744d0bee2..73d5a4a42b3a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -32,57 +32,78 @@ * This file contains setup code for the CRTC. */ -static void mga_crtc_load_lut(struct drm_crtc *crtc) +static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, + const struct drm_format_info *format) { - struct drm_device *dev = crtc->dev; - struct mga_device *mdev = to_mga_device(dev); - struct drm_framebuffer *fb; - u16 *r_ptr, *g_ptr, *b_ptr; int i; - if (!crtc->enabled) - return; - - if (!mdev->display_pipe.plane.state) - return; - - fb = mdev->display_pipe.plane.state->fb; - - r_ptr = crtc->gamma_store; - g_ptr = r_ptr + crtc->gamma_size; - b_ptr = g_ptr + crtc->gamma_size; - WREG8(DAC_INDEX + MGA1064_INDEX, 0); - if (fb && fb->format->cpp[0] * 8 == 16) { - int inc = (fb->format->depth == 15) ? 8 : 4; - u8 r, b; - for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { - if (fb->format->depth == 16) { - if (i > (MGAG200_LUT_SIZE >> 1)) { - r = b = 0; - } else { - r = *r_ptr++ >> 8; - b = *b_ptr++ >> 8; - r_ptr++; - b_ptr++; - } - } else { - r = *r_ptr++ >> 8; - b = *b_ptr++ >> 8; - } - /* VGA registers */ - WREG8(DAC_INDEX + MGA1064_COL_PAL, r); - WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); - WREG8(DAC_INDEX + MGA1064_COL_PAL, b); + switch (format->format) { + case DRM_FORMAT_RGB565: + /* Use better interpolation, to take 32 values from 0 to 255 */ + for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4); + WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16); + WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4); } - return; + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, 0); + WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16); + WREG8(DAC_INDEX + MGA1064_COL_PAL, 0); + } + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_XRGB8888: + for (i = 0; i < MGAG200_LUT_SIZE; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, i); + WREG8(DAC_INDEX + MGA1064_COL_PAL, i); + WREG8(DAC_INDEX + MGA1064_COL_PAL, i); + } + break; + default: + drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; } - for (i = 0; i < MGAG200_LUT_SIZE; i++) { - /* VGA registers */ - WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8); - WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); - WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8); +} + +static void mgag200_crtc_set_gamma(struct mga_device *mdev, + const struct drm_format_info *format, + struct drm_color_lut *lut) +{ + int i; + + WREG8(DAC_INDEX + MGA1064_INDEX, 0); + + switch (format->format) { + case DRM_FORMAT_RGB565: + /* Use better interpolation, to take 32 values from lut[0] to lut[255] */ + for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].red >> 8); + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8); + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].blue >> 8); + } + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, 0); + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8); + WREG8(DAC_INDEX + MGA1064_COL_PAL, 0); + } + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_XRGB8888: + for (i = 0; i < MGAG200_LUT_SIZE; i++) { + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].red >> 8); + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].green >> 8); + WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].blue >> 8); + } + break; + default: + drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n", + &format->format); + break; } } @@ -907,7 +928,11 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, if (mdev->type == G200_WB || mdev->type == G200_EW3) mgag200_g200wb_release_bmc(mdev); - mga_crtc_load_lut(crtc); + if (crtc_state->gamma_lut) + mgag200_crtc_set_gamma(mdev, fb->format, crtc_state->gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, fb->format); + mgag200_enable_display(mdev); mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]); @@ -958,6 +983,14 @@ mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, return ret; } + if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { + if (crtc_state->gamma_lut->length != + MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { + drm_err(dev, "Wrong size for gamma_lut %zu\n", + crtc_state->gamma_lut->length); + return -EINVAL; + } + } return 0; } @@ -966,6 +999,7 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct drm_plane *plane = &pipe->plane; + struct drm_crtc *crtc = &pipe->crtc; struct drm_device *dev = plane->dev; struct mga_device *mdev = to_mga_device(dev); struct drm_plane_state *state = plane->state; @@ -979,6 +1013,9 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, mutex_lock(&mdev->rmmio_lock); + if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) + mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data); + drm_atomic_helper_damage_iter_init(&iter, old_state, state); drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]); @@ -1132,9 +1169,11 @@ int mgag200_modeset_init(struct mga_device *mdev) drm_plane_enable_fb_damage_clips(&pipe->plane); - /* FIXME: legacy gamma tables; convert to CRTC state */ + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE); + drm_mode_config_reset(dev); return 0; From a24191b1c4ad05fc578ea5ea01652c09b71da86d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 30 Apr 2022 04:50:20 +0200 Subject: [PATCH 076/170] drm: bridge: icn6211: Register macro clean up Drop two unused register macros, ICN6211_MAX_REGISTER and MIPI_ATE_STATUS_1, neither of which is used and where the later should be specified using macro MIPI_ATE_STATUS(1) instead. Drop the _(n) underscore and keep only the (n) part of register macros. No functional change. Signed-off-by: Marek Vasut Cc: Jagan Teki Cc: Mark Brown Cc: Maxime Ripard Cc: Robert Foss Cc: Sam Ravnborg Cc: Thomas Zimmermann To: dri-devel@lists.freedesktop.org Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220430025020.640277-1-marex@denx.de --- drivers/gpu/drm/bridge/chipone-icn6211.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index 47dea657a752..cc9c12a33639 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -100,7 +100,7 @@ #define MIPI_PN_SWAP 0x87 #define MIPI_PN_SWAP_CLK BIT(4) #define MIPI_PN_SWAP_D(n) BIT((n) & 0x3) -#define MIPI_SOT_SYNC_BIT_(n) (0x88 + ((n) & 0x1)) /* 0..1 */ +#define MIPI_SOT_SYNC_BIT(n) (0x88 + ((n) & 0x1)) /* 0..1 */ #define MIPI_ULPS_CTRL 0x8a #define MIPI_CLK_CHK_VAR 0x8e #define MIPI_CLK_CHK_INI 0x8f @@ -115,7 +115,7 @@ #define MIPI_T_CLK_SETTLE 0x9a #define MIPI_TO_HS_RX_L 0x9e #define MIPI_TO_HS_RX_H 0x9f -#define MIPI_PHY_(n) (0xa0 + ((n) & 0x7)) /* 0..5 */ +#define MIPI_PHY(n) (0xa0 + ((n) & 0x7)) /* 0..5 */ #define MIPI_PD_RX 0xb0 #define MIPI_PD_TERM 0xb1 #define MIPI_PD_HSRX 0xb2 @@ -125,13 +125,11 @@ #define MIPI_FORCE_0 0xb6 #define MIPI_RST_CTRL 0xb7 #define MIPI_RST_NUM 0xb8 -#define MIPI_DBG_SET_(n) (0xc0 + ((n) & 0xf)) /* 0..9 */ +#define MIPI_DBG_SET(n) (0xc0 + ((n) & 0xf)) /* 0..9 */ #define MIPI_DBG_SEL 0xe0 #define MIPI_DBG_DATA 0xe1 #define MIPI_ATE_TEST_SEL 0xe2 -#define MIPI_ATE_STATUS_(n) (0xe3 + ((n) & 0x1)) /* 0..1 */ -#define MIPI_ATE_STATUS_1 0xe4 -#define ICN6211_MAX_REGISTER MIPI_ATE_STATUS(1) +#define MIPI_ATE_STATUS(n) (0xe3 + ((n) & 0x1)) /* 0..1 */ struct chipone { struct device *dev; @@ -155,10 +153,10 @@ static const struct regmap_range chipone_dsi_readable_ranges[] = { regmap_reg_range(MIPI_CLK_CHK_VAR, MIPI_T_TA_SURE_PRE), regmap_reg_range(MIPI_T_LPX_SET, MIPI_INIT_TIME_H), regmap_reg_range(MIPI_T_CLK_TERM_EN, MIPI_T_CLK_SETTLE), - regmap_reg_range(MIPI_TO_HS_RX_L, MIPI_PHY_(5)), + regmap_reg_range(MIPI_TO_HS_RX_L, MIPI_PHY(5)), regmap_reg_range(MIPI_PD_RX, MIPI_RST_NUM), - regmap_reg_range(MIPI_DBG_SET_(0), MIPI_DBG_SET_(9)), - regmap_reg_range(MIPI_DBG_SEL, MIPI_ATE_STATUS_(1)), + regmap_reg_range(MIPI_DBG_SET(0), MIPI_DBG_SET(9)), + regmap_reg_range(MIPI_DBG_SEL, MIPI_ATE_STATUS(1)), }; static const struct regmap_access_table chipone_dsi_readable_table = { @@ -172,10 +170,10 @@ static const struct regmap_range chipone_dsi_writeable_ranges[] = { regmap_reg_range(MIPI_CLK_CHK_VAR, MIPI_T_TA_SURE_PRE), regmap_reg_range(MIPI_T_LPX_SET, MIPI_INIT_TIME_H), regmap_reg_range(MIPI_T_CLK_TERM_EN, MIPI_T_CLK_SETTLE), - regmap_reg_range(MIPI_TO_HS_RX_L, MIPI_PHY_(5)), + regmap_reg_range(MIPI_TO_HS_RX_L, MIPI_PHY(5)), regmap_reg_range(MIPI_PD_RX, MIPI_RST_NUM), - regmap_reg_range(MIPI_DBG_SET_(0), MIPI_DBG_SET_(9)), - regmap_reg_range(MIPI_DBG_SEL, MIPI_ATE_STATUS_(1)), + regmap_reg_range(MIPI_DBG_SET(0), MIPI_DBG_SET(9)), + regmap_reg_range(MIPI_DBG_SEL, MIPI_ATE_STATUS(1)), }; static const struct regmap_access_table chipone_dsi_writeable_table = { @@ -189,7 +187,7 @@ static const struct regmap_config chipone_regmap_config = { .rd_table = &chipone_dsi_readable_table, .wr_table = &chipone_dsi_writeable_table, .cache_type = REGCACHE_RBTREE, - .max_register = MIPI_ATE_STATUS_(1), + .max_register = MIPI_ATE_STATUS(1), }; static int chipone_dsi_read(void *context, From a9ad5822366c5065e6a65fe5ff5090295ba98986 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 9 May 2022 15:52:02 +0200 Subject: [PATCH 077/170] drm: bridge: DRM_FSL_LDB should depend on ARCH_MXC The Freescale i.MX8MP LDB bridge is only present on Freescale i.MX8MP SoCs. Hence add a dependency on ARCH_MXC, to prevent asking the user about this driver when configuring a kernel without i.MX SoC support. Fixes: 463db5c2ed4aed01 ("drm: bridge: ldb: Implement simple Freescale i.MX8MP LDB bridge") Signed-off-by: Geert Uytterhoeven Reviewed-by: Marek Vasut Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/449e08ca791a3ca308de5477c1bdc1f6eb1b34e7.1652104211.git.geert+renesas@glider.be --- drivers/gpu/drm/bridge/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index da3441830d46..146ab069838f 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -78,6 +78,7 @@ config DRM_DISPLAY_CONNECTOR config DRM_FSL_LDB tristate "Freescale i.MX8MP LDB bridge" depends on OF + depends on ARCH_MXC || COMPILE_TEST select DRM_KMS_HELPER select DRM_PANEL_BRIDGE help From 7d64c40a7d96190d9d06e240305389e025295916 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 12 Apr 2022 01:15:36 +0300 Subject: [PATCH 078/170] drm/scheduler: Don't kill jobs in interrupt context Interrupt context can't sleep. Drivers like Panfrost and MSM are taking mutex when job is released, and thus, that code can sleep. This results into "BUG: scheduling while atomic" if locks are contented while job is freed. There is no good reason for releasing scheduler's jobs in IRQ context, hence use normal context to fix the trouble. Cc: stable@vger.kernel.org Fixes: 542cff7893a3 ("drm/sched: Avoid lockdep spalt on killing a processes") Signed-off-by: Dmitry Osipenko Signed-off-by: Andrey Grodzovsky Link: https://patchwork.freedesktop.org/patch/msgid/20220411221536.283312-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/scheduler/sched_entity.c | 6 +++--- include/drm/gpu_scheduler.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 191c56064f19..6b25b2f4f5a3 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -190,7 +190,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) } EXPORT_SYMBOL(drm_sched_entity_flush); -static void drm_sched_entity_kill_jobs_irq_work(struct irq_work *wrk) +static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) { struct drm_sched_job *job = container_of(wrk, typeof(*job), work); @@ -207,8 +207,8 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, struct drm_sched_job *job = container_of(cb, struct drm_sched_job, finish_cb); - init_irq_work(&job->work, drm_sched_entity_kill_jobs_irq_work); - irq_work_queue(&job->work); + INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); + schedule_work(&job->work); } static struct dma_fence * diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 0fca8f38bee4..addb135eeea6 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) @@ -295,7 +295,7 @@ struct drm_sched_job { */ union { struct dma_fence_cb finish_cb; - struct irq_work work; + struct work_struct work; }; uint64_t id; From 7328736d270aa4fa6fcd033ade02acc2874a2db5 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Fri, 22 Apr 2022 16:47:17 +0800 Subject: [PATCH 079/170] dt-bindings:drm/bridge:anx7625: add port@0 property Add 'bus-type' and 'data-lanes' define, bus-type 7 for MIPI DPI input, others for DSI input. Signed-off-by: Xin Ji Reviewed-by: Rob Herring Reviewed-by: Robert Foss Acked-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220422084720.959271-3-xji@analogixsemi.com --- .../display/bridge/analogix,anx7625.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 35a48515836e..4590186c4a0b 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -94,7 +94,22 @@ properties: $ref: /schemas/graph.yaml#/$defs/port-base unevaluatedProperties: false description: - Video port for MIPI DSI input. + MIPI DSI/DPI input. + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + type: object + additionalProperties: false + + properties: + remote-endpoint: true + + bus-type: + enum: [7] + default: 1 + + data-lanes: true port@1: $ref: /schemas/graph.yaml#/properties/port @@ -143,6 +158,8 @@ examples: reg = <0>; anx7625_in: endpoint { remote-endpoint = <&mipi_dsi>; + bus-type = <7>; + data-lanes = <0 1 2 3>; }; }; From a77c2af0994e24ee36c7ffb6dc852770bdf06fb1 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Fri, 22 Apr 2022 16:47:18 +0800 Subject: [PATCH 080/170] drm/bridge: anx7625: Use DPI bus type As V4L2_FWNODE_BUS_TYPE_PARALLEL not properly descript for DPI interface, this patch use new defined V4L2_FWNODE_BUS_TYPE_DPI for it. Fixes: fd0310b6fe7d ("drm/bridge: anx7625: add MIPI DPI input feature") Signed-off-by: Xin Ji Tested-by: Chen-Yu Tsai Acked-by: Robert Foss Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220422084720.959271-4-xji@analogixsemi.com --- drivers/gpu/drm/bridge/analogix/anx7625.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 53a5da6c49dd..01f46d9189c1 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1623,14 +1623,14 @@ static int anx7625_parse_dt(struct device *dev, anx7625_get_swing_setting(dev, pdata); - pdata->is_dpi = 1; /* default dpi mode */ + pdata->is_dpi = 0; /* default dsi mode */ pdata->mipi_host_node = of_graph_get_remote_node(np, 0, 0); if (!pdata->mipi_host_node) { DRM_DEV_ERROR(dev, "fail to get internal panel.\n"); return -ENODEV; } - bus_type = V4L2_FWNODE_BUS_TYPE_PARALLEL; + bus_type = 0; mipi_lanes = MAX_LANES_SUPPORT; ep0 = of_graph_get_endpoint_by_regs(np, 0, 0); if (ep0) { @@ -1640,8 +1640,8 @@ static int anx7625_parse_dt(struct device *dev, mipi_lanes = of_property_count_u32_elems(ep0, "data-lanes"); } - if (bus_type == V4L2_FWNODE_BUS_TYPE_PARALLEL) /* bus type is Parallel(DSI) */ - pdata->is_dpi = 0; + if (bus_type == V4L2_FWNODE_BUS_TYPE_DPI) /* bus type is DPI */ + pdata->is_dpi = 1; pdata->mipi_lanes = mipi_lanes; if (pdata->mipi_lanes > MAX_LANES_SUPPORT || pdata->mipi_lanes <= 0) From 5913ab941d6ea782e841234c76958c6872ea752d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:37 +0200 Subject: [PATCH 081/170] drm/mgag200: Acquire I/O lock while reading EDID DDC operation conflicts with concurrent mode setting. Acquire the driver's I/O lock in get_modes to prevent this. This change should have been part of commit 931e3f3a0e99 ("drm/mgag200: Protect concurrent access to I/O registers with lock"), but apparently got lost somewhere. v3: * fix commit message to say 'drm/mgag200' (Jocelyn) Signed-off-by: Thomas Zimmermann Fixes: 931e3f3a0e99 ("drm/mgag200: Protect concurrent access to I/O registers with lock") Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Cc: Thomas Zimmermann Cc: Jocelyn Falempe Cc: Daniel Vetter Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-2-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 73d5a4a42b3a..762b9657ae8d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -691,16 +691,26 @@ static void mgag200_disable_display(struct mga_device *mdev) static int mga_vga_get_modes(struct drm_connector *connector) { + struct mga_device *mdev = to_mga_device(connector->dev); struct mga_connector *mga_connector = to_mga_connector(connector); struct edid *edid; int ret = 0; + /* + * Protect access to I/O registers from concurrent modesetting + * by acquiring the I/O-register lock. + */ + mutex_lock(&mdev->rmmio_lock); + edid = drm_get_edid(connector, &mga_connector->i2c->adapter); if (edid) { drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } + + mutex_unlock(&mdev->rmmio_lock); + return ret; } From d50f74790bbba662d1438dbc03be6616c52c0722 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:38 +0200 Subject: [PATCH 082/170] drm/mgag200: Fail on I2C initialization errors Initialization of the I2C adapter was allowed to fail. The mgag200 driver would have continued without DDC support. Had this happened in practice, it would have led to segmentation faults in the connector code. Resolve this problem by failing driver initialization on I2C- related errors. v2: * initialize 'ret' before drm_err() (kernel test robot) Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-3-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_i2c.c | 13 ++++++++----- drivers/gpu/drm/mgag200/mgag200_mode.c | 7 +++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index ac8e34eef513..31e2c641a781 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -120,7 +120,7 @@ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) i2c = kzalloc(sizeof(struct mga_i2c_chan), GFP_KERNEL); if (!i2c) - return NULL; + return ERR_PTR(-ENOMEM); i2c->data = data; i2c->clock = clock; @@ -142,11 +142,14 @@ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) i2c->bit.getscl = mga_gpio_getscl; ret = i2c_bit_add_bus(&i2c->adapter); - if (ret) { - kfree(i2c); - i2c = NULL; - } + if (ret) + goto err_kfree; + return i2c; + +err_kfree: + kfree(i2c); + return ERR_PTR(ret); } void mgag200_i2c_destroy(struct mga_i2c_chan *i2c) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 762b9657ae8d..b227891d01ec 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -849,8 +849,11 @@ static int mgag200_vga_connector_init(struct mga_device *mdev) int ret; i2c = mgag200_i2c_create(dev); - if (!i2c) - drm_warn(dev, "failed to add DDC bus\n"); + if (IS_ERR(i2c)) { + ret = PTR_ERR(i2c) + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } ret = drm_connector_init_with_ddc(dev, connector, &mga_vga_connector_funcs, From 16f1456466c269ecda32b88c3f8fdd76f8ec370c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:39 +0200 Subject: [PATCH 083/170] drm/mgag200: Implement connector's get_modes with helper Provide drm_connector_helper_get_modes_from_ddc() to implement the connector's get_modes callback. The new helper updates the connector from DDC-provided EDID data. v2: * clear property if EDID is NULL in helper Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_probe_helper.c | 36 ++++++++++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 17 +++--------- include/drm/drm_probe_helper.h | 2 ++ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 682359512996..d77f17867195 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -964,3 +964,39 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) return changed; } EXPORT_SYMBOL(drm_helper_hpd_irq_event); + +/** + * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID + * property from the connector's + * DDC channel + * @connector: The connector + * + * Returns: + * The number of detected display modes. + * + * Uses a connector's DDC channel to retrieve EDID data and update the + * connector's EDID property and display modes. Drivers can use this + * function to implement struct &drm_connector_helper_funcs.get_modes + * for connectors with a DDC channel. + */ +int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector) +{ + struct edid *edid; + int count = 0; + + if (!connector->ddc) + return 0; + + edid = drm_get_edid(connector, connector->ddc); + + // clears property if EDID is NULL + drm_connector_update_edid_property(connector, edid); + + if (edid) { + count = drm_add_edid_modes(connector, edid); + kfree(edid); + } + + return count; +} +EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index b227891d01ec..4c0680dd1a78 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -689,26 +689,17 @@ static void mgag200_disable_display(struct mga_device *mdev) * Connector */ -static int mga_vga_get_modes(struct drm_connector *connector) +static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { struct mga_device *mdev = to_mga_device(connector->dev); - struct mga_connector *mga_connector = to_mga_connector(connector); - struct edid *edid; - int ret = 0; + int ret; /* * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ mutex_lock(&mdev->rmmio_lock); - - edid = drm_get_edid(connector, &mga_connector->i2c->adapter); - if (edid) { - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } - + ret = drm_connector_helper_get_modes_from_ddc(connector); mutex_unlock(&mdev->rmmio_lock); return ret; @@ -828,7 +819,7 @@ static void mga_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { - .get_modes = mga_vga_get_modes, + .get_modes = mgag200_vga_connector_helper_get_modes, .mode_valid = mga_vga_mode_valid, }; diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h index 48300aa6ca71..c80cab7a53b7 100644 --- a/include/drm/drm_probe_helper.h +++ b/include/drm/drm_probe_helper.h @@ -26,4 +26,6 @@ void drm_kms_helper_poll_disable(struct drm_device *dev); void drm_kms_helper_poll_enable(struct drm_device *dev); bool drm_kms_helper_is_poll_worker(void); +int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector); + #endif From b279df242972ae816a75cf1cc732af836f999100 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:40 +0200 Subject: [PATCH 084/170] drm/mgag200: Switch I2C code to managed cleanup Store the I2C state within struct mga_device and switch I2C to managed release. Simplifies the related code and lets us remove mga_connector_destroy(). Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-5-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.h | 5 ++-- drivers/gpu/drm/mgag200/mgag200_i2c.c | 33 +++++++++----------------- drivers/gpu/drm/mgag200/mgag200_mode.c | 24 ++++--------------- 3 files changed, 18 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index a18384c41fc4..5bdd09432114 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -179,7 +179,6 @@ struct mga_i2c_chan { struct mga_connector { struct drm_connector base; - struct mga_i2c_chan *i2c; }; struct mga_mc { @@ -239,6 +238,7 @@ struct mga_device { struct mga_connector connector; struct mgag200_pll pixpll; + struct mga_i2c_chan i2c; struct drm_simple_display_pipe display_pipe; }; @@ -251,8 +251,7 @@ static inline struct mga_device *to_mga_device(struct drm_device *dev) int mgag200_modeset_init(struct mga_device *mdev); /* mgag200_i2c.c */ -struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev); -void mgag200_i2c_destroy(struct mga_i2c_chan *i2c); +int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c); /* mgag200_mm.c */ int mgag200_mm_init(struct mga_device *mdev); diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index 31e2c641a781..f57b33917152 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -86,10 +86,16 @@ static int mga_gpio_getscl(void *data) return (mga_i2c_read_gpio(mdev) & i2c->clock) ? 1 : 0; } -struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) +static void mgag200_i2c_release(void *res) { - struct mga_device *mdev = to_mga_device(dev); - struct mga_i2c_chan *i2c; + struct mga_i2c_chan *i2c = res; + + i2c_del_adapter(&i2c->adapter); +} + +int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) +{ + struct drm_device *dev = &mdev->base; int ret; int data, clock; @@ -118,10 +124,6 @@ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) break; } - i2c = kzalloc(sizeof(struct mga_i2c_chan), GFP_KERNEL); - if (!i2c) - return ERR_PTR(-ENOMEM); - i2c->data = data; i2c->clock = clock; i2c->adapter.owner = THIS_MODULE; @@ -143,20 +145,7 @@ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) ret = i2c_bit_add_bus(&i2c->adapter); if (ret) - goto err_kfree; + return ret; - return i2c; - -err_kfree: - kfree(i2c); - return ERR_PTR(ret); + return devm_add_action_or_reset(dev->dev, mgag200_i2c_release, i2c); } - -void mgag200_i2c_destroy(struct mga_i2c_chan *i2c) -{ - if (!i2c) - return; - i2c_del_adapter(&i2c->adapter); - kfree(i2c); -} - diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 4c0680dd1a78..ae78950e270b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -811,13 +811,6 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, return MODE_OK; } -static void mga_connector_destroy(struct drm_connector *connector) -{ - struct mga_connector *mga_connector = to_mga_connector(connector); - mgag200_i2c_destroy(mga_connector->i2c); - drm_connector_cleanup(connector); -} - static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { .get_modes = mgag200_vga_connector_helper_get_modes, .mode_valid = mga_vga_mode_valid, @@ -826,7 +819,7 @@ static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = static const struct drm_connector_funcs mga_vga_connector_funcs = { .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = mga_connector_destroy, + .destroy = drm_connector_cleanup, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; @@ -836,12 +829,11 @@ static int mgag200_vga_connector_init(struct mga_device *mdev) struct drm_device *dev = &mdev->base; struct mga_connector *mconnector = &mdev->connector; struct drm_connector *connector = &mconnector->base; - struct mga_i2c_chan *i2c; + struct mga_i2c_chan *i2c = &mdev->i2c; int ret; - i2c = mgag200_i2c_create(dev); - if (IS_ERR(i2c)) { - ret = PTR_ERR(i2c) + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { drm_err(dev, "failed to add DDC bus: %d\n", ret); return ret; } @@ -851,16 +843,10 @@ static int mgag200_vga_connector_init(struct mga_device *mdev) DRM_MODE_CONNECTOR_VGA, &i2c->adapter); if (ret) - goto err_mgag200_i2c_destroy; + return ret; drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); - mconnector->i2c = i2c; - return 0; - -err_mgag200_i2c_destroy: - mgag200_i2c_destroy(i2c); - return ret; } /* From 8219f11fdaf56593a719e1d72fa582673560315a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:41 +0200 Subject: [PATCH 085/170] drm/mgag200: Remove struct mga_connector struct mga_connector has outlived its purpose. Inline the rsp init helper into the mode-config code and remove the data structure. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-6-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.h | 8 +---- drivers/gpu/drm/mgag200/mgag200_mode.c | 44 ++++++++------------------ 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 5bdd09432114..5634fc003ca4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -168,8 +168,6 @@ static inline struct mgag200_crtc_state *to_mgag200_crtc_state(struct drm_crtc_s return container_of(base, struct mgag200_crtc_state, base); } -#define to_mga_connector(x) container_of(x, struct mga_connector, base) - struct mga_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; @@ -177,10 +175,6 @@ struct mga_i2c_chan { int data, clock; }; -struct mga_connector { - struct drm_connector base; -}; - struct mga_mc { resource_size_t vram_size; resource_size_t vram_base; @@ -236,9 +230,9 @@ struct mga_device { } g200se; } model; - struct mga_connector connector; struct mgag200_pll pixpll; struct mga_i2c_chan i2c; + struct drm_connector connector; struct drm_simple_display_pipe display_pipe; }; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index ae78950e270b..0baaec117502 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -824,31 +824,6 @@ static const struct drm_connector_funcs mga_vga_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int mgag200_vga_connector_init(struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - struct mga_connector *mconnector = &mdev->connector; - struct drm_connector *connector = &mconnector->base; - struct mga_i2c_chan *i2c = &mdev->i2c; - int ret; - - ret = mgag200_i2c_init(mdev, i2c); - if (ret) { - drm_err(dev, "failed to add DDC bus: %d\n", ret); - return ret; - } - - ret = drm_connector_init_with_ddc(dev, connector, - &mga_vga_connector_funcs, - DRM_MODE_CONNECTOR_VGA, - &i2c->adapter); - if (ret) - return ret; - drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); - - return 0; -} - /* * Simple Display Pipe */ @@ -1109,7 +1084,8 @@ static unsigned int mgag200_preferred_depth(struct mga_device *mdev) int mgag200_modeset_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; - struct drm_connector *connector = &mdev->connector.base; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; struct drm_simple_display_pipe *pipe = &mdev->display_pipe; size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); int ret; @@ -1132,14 +1108,22 @@ int mgag200_modeset_init(struct mga_device *mdev) dev->mode_config.funcs = &mgag200_mode_config_funcs; - ret = mgag200_vga_connector_init(mdev); + ret = mgag200_i2c_init(mdev, i2c); if (ret) { - drm_err(dev, - "mgag200_vga_connector_init() failed, error %d\n", - ret); + drm_err(dev, "failed to add DDC bus: %d\n", ret); return ret; } + ret = drm_connector_init_with_ddc(dev, connector, + &mga_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); + ret = mgag200_pixpll_init(&mdev->pixpll, mdev); if (ret) return ret; From 69340e529a064da4807622395e967aa2b5eba1c5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:42 +0200 Subject: [PATCH 086/170] drm/mgag200: Test memory requirements in drm_mode_config_funcs.mode_valid Test for a mode's memory requirements in the device-wide mode_valid helper. For simplicify, always assume a 32-bit color format. While some rejected modes would work with less colors, implementing this is probably not worth the effort. Also remove the memory-related test from the connector's mode_valid helper. The test uses the bpp value that users can specify on the kernel's command line. This value is unrelated and the test would belong into atomic_check. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-7-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 35 +++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0baaec117502..a718a20b3a20 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -796,18 +796,6 @@ static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, return MODE_BAD; } - /* Validate the mode input by the user */ - if (connector->cmdline_mode.specified) { - if (connector->cmdline_mode.bpp_specified) - bpp = connector->cmdline_mode.bpp; - } - - if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->vram_fb_available) { - if (connector->cmdline_mode.specified) - connector->cmdline_mode.specified = false; - return MODE_BAD; - } - return MODE_OK; } @@ -1067,9 +1055,28 @@ static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { * Mode config */ +static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888 + struct mga_device *mdev = to_mga_device(dev); + unsigned long fbsize, fbpages, max_fbpages; + + max_fbpages = mdev->vram_fb_available >> PAGE_SHIFT; + + fbsize = mode->hdisplay * mode->vdisplay * max_bpp; + fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); + + if (fbpages > max_fbpages) + return MODE_MEM; + + return MODE_OK; +} + static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { - .fb_create = drm_gem_fb_create_with_dirty, - .atomic_check = drm_atomic_helper_check, + .fb_create = drm_gem_fb_create_with_dirty, + .mode_valid = mgag200_mode_config_mode_valid, + .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; From 475e2b970cc372f49e9d3e4bbead8b4874299d31 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:43 +0200 Subject: [PATCH 087/170] drm/mgag200: Split up connector's mode_valid helper Split up the connector's mode_valid helper into a simple-pipe and a mode-config helper. The simple-pipe helper tests for display-size limits while the mode-config helper tests for memory-bandwidth limits. Also add the mgag200_ prefix to mga_vga_calculate_mode_bandwidth() and comment on the function's purpose. The memory-bandwidth tests assume that the display uses 4 bytes per pixel. The first models of G200SE-A only had 1.75 MiB of VRAM, which limits these devices to 640x480-32. v2: * note the memory constraints on early G200SE-A Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-8-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 182 ++++++++++++------------- 1 file changed, 87 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index a718a20b3a20..028c6ba7124c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -705,103 +705,8 @@ static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connecto return ret; } -static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, - int bits_per_pixel) -{ - uint32_t total_area, divisor; - uint64_t active_area, pixels_per_second, bandwidth; - uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; - - divisor = 1024; - - if (!mode->htotal || !mode->vtotal || !mode->clock) - return 0; - - active_area = mode->hdisplay * mode->vdisplay; - total_area = mode->htotal * mode->vtotal; - - pixels_per_second = active_area * mode->clock * 1000; - do_div(pixels_per_second, total_area); - - bandwidth = pixels_per_second * bytes_per_pixel * 100; - do_div(bandwidth, divisor); - - return (uint32_t)(bandwidth); -} - -#define MODE_BANDWIDTH MODE_BAD - -static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct drm_device *dev = connector->dev; - struct mga_device *mdev = to_mga_device(dev); - int bpp = 32; - - if (IS_G200_SE(mdev)) { - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; - - if (unique_rev_id == 0x01) { - if (mode->hdisplay > 1600) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1200) - return MODE_VIRTUAL_Y; - if (mga_vga_calculate_mode_bandwidth(mode, bpp) - > (24400 * 1024)) - return MODE_BANDWIDTH; - } else if (unique_rev_id == 0x02) { - if (mode->hdisplay > 1920) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1200) - return MODE_VIRTUAL_Y; - if (mga_vga_calculate_mode_bandwidth(mode, bpp) - > (30100 * 1024)) - return MODE_BANDWIDTH; - } else { - if (mga_vga_calculate_mode_bandwidth(mode, bpp) - > (55000 * 1024)) - return MODE_BANDWIDTH; - } - } else if (mdev->type == G200_WB) { - if (mode->hdisplay > 1280) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1024) - return MODE_VIRTUAL_Y; - if (mga_vga_calculate_mode_bandwidth(mode, bpp) > - (31877 * 1024)) - return MODE_BANDWIDTH; - } else if (mdev->type == G200_EV && - (mga_vga_calculate_mode_bandwidth(mode, bpp) - > (32700 * 1024))) { - return MODE_BANDWIDTH; - } else if (mdev->type == G200_EH && - (mga_vga_calculate_mode_bandwidth(mode, bpp) - > (37500 * 1024))) { - return MODE_BANDWIDTH; - } else if (mdev->type == G200_ER && - (mga_vga_calculate_mode_bandwidth(mode, - bpp) > (55000 * 1024))) { - return MODE_BANDWIDTH; - } - - if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || - (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { - return MODE_H_ILLEGAL; - } - - if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || - mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || - mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || - mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { - return MODE_BAD; - } - - return MODE_OK; -} - static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { .get_modes = mgag200_vga_connector_helper_get_modes, - .mode_valid = mga_vga_mode_valid, }; static const struct drm_connector_funcs mga_vga_connector_funcs = { @@ -820,6 +725,41 @@ static enum drm_mode_status mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, const struct drm_display_mode *mode) { + struct mga_device *mdev = to_mga_device(pipe->crtc.dev); + + if (IS_G200_SE(mdev)) { + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + + if (unique_rev_id == 0x01) { + if (mode->hdisplay > 1600) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1200) + return MODE_VIRTUAL_Y; + } else if (unique_rev_id == 0x02) { + if (mode->hdisplay > 1920) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1200) + return MODE_VIRTUAL_Y; + } + } else if (mdev->type == G200_WB) { + if (mode->hdisplay > 1280) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1024) + return MODE_VIRTUAL_Y; + } + + if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || + (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { + return MODE_H_ILLEGAL; + } + + if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || + mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || + mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || + mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { + return MODE_BAD; + } + return MODE_OK; } @@ -1055,6 +995,31 @@ static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { * Mode config */ +/* Calculates a mode's required memory bandwidth (in KiB/sec). */ +static uint32_t mgag200_calculate_mode_bandwidth(const struct drm_display_mode *mode, + unsigned int bits_per_pixel) +{ + uint32_t total_area, divisor; + uint64_t active_area, pixels_per_second, bandwidth; + uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; + + divisor = 1024; + + if (!mode->htotal || !mode->vtotal || !mode->clock) + return 0; + + active_area = mode->hdisplay * mode->vdisplay; + total_area = mode->htotal * mode->vtotal; + + pixels_per_second = active_area * mode->clock * 1000; + do_div(pixels_per_second, total_area); + + bandwidth = pixels_per_second * bytes_per_pixel * 100; + do_div(bandwidth, divisor); + + return (uint32_t)bandwidth; +} + static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode) { @@ -1070,6 +1035,33 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de if (fbpages > max_fbpages) return MODE_MEM; + if (IS_G200_SE(mdev)) { + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + + if (unique_rev_id == 0x01) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (24400 * 1024)) + return MODE_BAD; + } else if (unique_rev_id == 0x02) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (30100 * 1024)) + return MODE_BAD; + } else { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024)) + return MODE_BAD; + } + } else if (mdev->type == G200_WB) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (31877 * 1024)) + return MODE_BAD; + } else if (mdev->type == G200_EV) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (32700 * 1024)) + return MODE_BAD; + } else if (mdev->type == G200_EH) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (37500 * 1024)) + return MODE_BAD; + } else if (mdev->type == G200_ER) { + if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024)) + return MODE_BAD; + } + return MODE_OK; } From 315a8d00ac74c59a688a1a88c0ed97a7791d1c91 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 8 Feb 2022 15:31:52 +0100 Subject: [PATCH 088/170] drm/udl: Set VGA connector Set the connector type to VGA. The previously exported DVII type isn't even supported by the driver. Signed-off-by: Thomas Zimmermann Acked-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20220208143152.5846-1-tzimmermann@suse.de --- drivers/gpu/drm/udl/udl_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 930574ad2bca..318fdb38b47a 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -128,7 +128,7 @@ struct drm_connector *udl_connector_init(struct drm_device *dev) connector = &udl_connector->connector; drm_connector_init(dev, connector, &udl_connector_funcs, - DRM_MODE_CONNECTOR_DVII); + DRM_MODE_CONNECTOR_VGA); drm_connector_helper_add(connector, &udl_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_HPD | From 7381076809586528e2a812a709e2758916318a99 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 11 May 2022 09:40:51 +0400 Subject: [PATCH 089/170] drm/meson: Fix refcount leak in meson_encoder_hdmi_init of_find_device_by_node() takes reference, we should use put_device() to release it when not need anymore. Add missing put_device() in error path to avoid refcount leak. Fixes: 0af5e0b41110 ("drm/meson: encoder_hdmi: switch to bridge DRM_BRIDGE_ATTACH_NO_CONNECTOR") Signed-off-by: Miaoqian Lin Reviewed-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20220511054052.51981-1-linmq006@gmail.com --- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 5e306de6f485..de87f02cd388 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -435,8 +435,10 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) cec_fill_conn_info_from_drm(&conn_info, meson_encoder_hdmi->connector); notifier = cec_notifier_conn_register(&pdev->dev, NULL, &conn_info); - if (!notifier) + if (!notifier) { + put_device(&pdev->dev); return -ENOMEM; + } meson_encoder_hdmi->cec_notifier = notifier; } From c193a003dc46ae601f46908b41d6f485b87db1ad Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Mon, 16 May 2022 07:22:45 +0000 Subject: [PATCH 090/170] drm/meson: add YUV422 output support Support YUV422 output from the Amlogic Meson SoC VPU to the HDMI controller. Without this YUV422 format out of the HDMI encoder leads to using the dw-hdmi YUV444 to YUV422 color conversion which gives wrong colors and a green line on the left edge of the screen. Signed-off-by: Dongjin Kim Signed-off-by: Christian Hewitt Tested-by: Furkan Kardame Acked-by: Neil Armstrong Tested-by: Dan Johansen Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20220516072245.10745-1-christianshewitt@gmail.com --- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index de87f02cd388..2593c542ad41 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -218,7 +218,8 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; yuv420_mode = true; - } + } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) + ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; /* VENC + VENC-DVI Mode setup */ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); @@ -230,6 +231,10 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, /* Setup YUV420 to HDMI-TX, no 10bit diphering */ writel_relaxed(2 | (2 << 2), priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) + /* Setup YUV422 to HDMI-TX, no 10bit diphering */ + writel_relaxed(1 | (2 << 2), + priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); else /* Setup YUV444 to HDMI-TX, no 10bit diphering */ writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); @@ -257,6 +262,7 @@ static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge, static const u32 meson_encoder_hdmi_out_bus_fmts[] = { MEDIA_BUS_FMT_YUV8_1X24, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYYVYY8_0_5X24, }; From f159b1b22c8a2d3d7c1fa877fafc8aacff0deeba Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:23 +0200 Subject: [PATCH 091/170] drm/gem: Share code between drm_gem_fb_{begin,end}_cpu_access() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error-recovery code in drm_gem_fb_begin() is of the same pattern as drm_gem_fb_end(). Implement both of them using an internal helper. No functional changes. v2: * print additional information in error message (Javier) * fix commit description (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-2-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index f4619803acd0..931828784dfe 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -403,6 +403,28 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_gem_fb_vunmap); +static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir, + unsigned int num_planes) +{ + struct dma_buf_attachment *import_attach; + struct drm_gem_object *obj; + int ret; + + while (num_planes) { + --num_planes; + obj = drm_gem_fb_get_obj(fb, num_planes); + if (!obj) + continue; + import_attach = obj->import_attach; + if (!import_attach) + continue; + ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); + if (ret) + drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n", + ret, num_planes, dir); + } +} + /** * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access * @fb: the framebuffer @@ -422,7 +444,7 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct struct dma_buf_attachment *import_attach; struct drm_gem_object *obj; size_t i; - int ret, ret2; + int ret; for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { obj = drm_gem_fb_get_obj(fb, i); @@ -433,28 +455,13 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct continue; ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir); if (ret) - goto err_dma_buf_end_cpu_access; + goto err___drm_gem_fb_end_cpu_access; } return 0; -err_dma_buf_end_cpu_access: - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - import_attach = obj->import_attach; - if (!import_attach) - continue; - ret2 = dma_buf_end_cpu_access(import_attach->dmabuf, dir); - if (ret2) { - drm_err(fb->dev, - "dma_buf_end_cpu_access() failed during error handling: %d\n", - ret2); - } - } - +err___drm_gem_fb_end_cpu_access: + __drm_gem_fb_end_cpu_access(fb, dir, i); return ret; } EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); @@ -472,23 +479,7 @@ EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); */ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) { - size_t i = ARRAY_SIZE(fb->obj); - struct dma_buf_attachment *import_attach; - struct drm_gem_object *obj; - int ret; - - while (i) { - --i; - obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; - import_attach = obj->import_attach; - if (!import_attach) - continue; - ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir); - if (ret) - drm_err(fb->dev, "dma_buf_end_cpu_access() failed: %d\n", ret); - } + __drm_gem_fb_end_cpu_access(fb, dir, ARRAY_SIZE(fb->obj)); } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); From 746b9c62cc8614fa59c23f3332682b5e9e1d801c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:24 +0200 Subject: [PATCH 092/170] drm/gem: Ignore color planes that are unused by framebuffer format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only handle color planes that exist in a framebuffer's color format. Ignore non-existing planes. So far, several helpers assumed that all 4 planes are available and silently ignored non-existing planes. This lead to subtil bugs with uninitialized data in instances of struct iosys_map. [1] Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://lore.kernel.org/dri-devel/20210730183511.20080-1-tzimmermann@suse.de/T/#md0172b10bb588d8f20f4f456e304f08d2a4505f7 # 1 Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_atomic_helper.c | 6 ++-- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 37 +++++++++++--------- include/drm/drm_gem_framebuffer_helper.h | 10 ++---- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index a5026f617739..f16d60217c6c 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -169,8 +169,10 @@ int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_gem_object *obj = drm_gem_fb_get_obj(state->fb, i); struct dma_fence *new; - if (WARN_ON_ONCE(!obj)) - continue; + if (!obj) { + ret = -EINVAL; + goto error; + } ret = dma_resv_get_singleton(obj->resv, usage, &new); if (ret) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 931828784dfe..6d3c26efdeeb 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -92,9 +92,9 @@ drm_gem_fb_init(struct drm_device *dev, */ void drm_gem_fb_destroy(struct drm_framebuffer *fb) { - size_t i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(fb->obj); i++) + for (i = 0; i < fb->format->num_planes; i++) drm_gem_object_put(fb->obj[i]); drm_framebuffer_cleanup(fb); @@ -329,24 +329,26 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * The argument returns the addresses of the data stored in each BO. This * is different from @map if the framebuffer's offsets field is non-zero. * + * Both, @map and @data, must each refer to arrays with at least + * fb->format->num_planes elements. + * * See drm_gem_fb_vunmap() for unmapping. * * Returns: * 0 on success, or a negative errno code otherwise. */ -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES], - struct iosys_map data[DRM_FORMAT_MAX_PLANES]) +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, + struct iosys_map *data) { struct drm_gem_object *obj; unsigned int i; int ret; - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); if (!obj) { - iosys_map_clear(&map[i]); - continue; + ret = -EINVAL; + goto err_drm_gem_vunmap; } ret = drm_gem_vmap(obj, &map[i]); if (ret) @@ -354,7 +356,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, } if (data) { - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { memcpy(&data[i], &map[i], sizeof(data[i])); if (iosys_map_is_null(&data[i])) continue; @@ -385,10 +387,9 @@ EXPORT_SYMBOL(drm_gem_fb_vmap); * * See drm_gem_fb_vmap() for more information. */ -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES]) +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map) { - unsigned int i = DRM_FORMAT_MAX_PLANES; + unsigned int i = fb->format->num_planes; struct drm_gem_object *obj; while (i) { @@ -443,13 +444,15 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct { struct dma_buf_attachment *import_attach; struct drm_gem_object *obj; - size_t i; + unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; + if (!obj) { + ret = -EINVAL; + goto err___drm_gem_fb_end_cpu_access; + } import_attach = obj->import_attach; if (!import_attach) continue; @@ -479,7 +482,7 @@ EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); */ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) { - __drm_gem_fb_end_cpu_access(fb, dir, ARRAY_SIZE(fb->obj)); + __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes); } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 1091e4fa08cb..d302521f3dd4 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -4,8 +4,6 @@ #include #include -#include - struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -39,11 +37,9 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES], - struct iosys_map data[DRM_FORMAT_MAX_PLANES]); -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES]); +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, + struct iosys_map *data); +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); From 1c89b4b718168aa6cf136a984b474d663e4203b7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:25 +0200 Subject: [PATCH 093/170] drm/gem-vram: Share code between GEM VRAM's _{prepare, cleanup}_fb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error-recovery code in drm_gem_vram_plane_helper_prepare_fb() is of the same pattern as drm_gem_vram_plane_helper_cleanup_fb(). Implement both of them using an internal helper. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_vram_helper.c | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 123045b58fec..566d139f0fa0 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -630,6 +631,24 @@ EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create); * Helpers for struct drm_plane_helper_funcs */ +static void __drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *state, + unsigned int num_planes) +{ + struct drm_gem_object *obj; + struct drm_gem_vram_object *gbo; + struct drm_framebuffer *fb = state->fb; + + while (num_planes) { + --num_planes; + obj = drm_gem_fb_get_obj(fb, num_planes); + if (!obj) + continue; + gbo = drm_gem_vram_of_gem(obj); + drm_gem_vram_unpin(gbo); + } +} + /** * drm_gem_vram_plane_helper_prepare_fb() - \ * Implements &struct drm_plane_helper_funcs.prepare_fb @@ -671,11 +690,7 @@ drm_gem_vram_plane_helper_prepare_fb(struct drm_plane *plane, return 0; err_drm_gem_vram_unpin: - while (i) { - --i; - gbo = drm_gem_vram_of_gem(new_state->fb->obj[i]); - drm_gem_vram_unpin(gbo); - } + __drm_gem_vram_plane_helper_cleanup_fb(plane, new_state, i); return ret; } EXPORT_SYMBOL(drm_gem_vram_plane_helper_prepare_fb); @@ -694,18 +709,12 @@ void drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { - size_t i; - struct drm_gem_vram_object *gbo; + struct drm_framebuffer *fb = old_state->fb; - if (!old_state->fb) + if (!fb) return; - for (i = 0; i < ARRAY_SIZE(old_state->fb->obj); ++i) { - if (!old_state->fb->obj[i]) - continue; - gbo = drm_gem_vram_of_gem(old_state->fb->obj[i]); - drm_gem_vram_unpin(gbo); - } + __drm_gem_vram_plane_helper_cleanup_fb(plane, old_state, ARRAY_SIZE(fb->obj)); } EXPORT_SYMBOL(drm_gem_vram_plane_helper_cleanup_fb); From a8d6e127254c48d895c4f6e973ec998fd4a0eff3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:26 +0200 Subject: [PATCH 094/170] drm/gem-vram: Ignore planes that are unused by framebuffer format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only handle color planes that exist in a framebuffer's color format. Ignore non-existing planes. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-5-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_vram_helper.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index 566d139f0fa0..d607043716d3 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -667,17 +667,22 @@ int drm_gem_vram_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { - size_t i; + struct drm_framebuffer *fb = new_state->fb; struct drm_gem_vram_object *gbo; + struct drm_gem_object *obj; + unsigned int i; int ret; - if (!new_state->fb) + if (!fb) return 0; - for (i = 0; i < ARRAY_SIZE(new_state->fb->obj); ++i) { - if (!new_state->fb->obj[i]) - continue; - gbo = drm_gem_vram_of_gem(new_state->fb->obj[i]); + for (i = 0; i < fb->format->num_planes; ++i) { + obj = drm_gem_fb_get_obj(fb, i); + if (!obj) { + ret = -EINVAL; + goto err_drm_gem_vram_unpin; + } + gbo = drm_gem_vram_of_gem(obj); ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); if (ret) goto err_drm_gem_vram_unpin; @@ -714,7 +719,7 @@ drm_gem_vram_plane_helper_cleanup_fb(struct drm_plane *plane, if (!fb) return; - __drm_gem_vram_plane_helper_cleanup_fb(plane, old_state, ARRAY_SIZE(fb->obj)); + __drm_gem_vram_plane_helper_cleanup_fb(plane, old_state, fb->format->num_planes); } EXPORT_SYMBOL(drm_gem_vram_plane_helper_cleanup_fb); From 4f093a527b0b8f9d3059a4e8376e582fd14cf09e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:27 +0200 Subject: [PATCH 095/170] drm/gem: Warn on trying to use a non-existing framebuffer plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warn if callers of drm_gem_fb_get_obj() try to use a GEM buffer for a non-existing or unset plane. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-6-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 6d3c26efdeeb..61339a9cd010 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -53,7 +53,11 @@ MODULE_IMPORT_NS(DMA_BUF); struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb, unsigned int plane) { - if (plane >= ARRAY_SIZE(fb->obj)) + struct drm_device *dev = fb->dev; + + if (drm_WARN_ON_ONCE(dev, plane >= ARRAY_SIZE(fb->obj))) + return NULL; + else if (drm_WARN_ON_ONCE(dev, !fb->obj[plane])) return NULL; return fb->obj[plane]; From 4a2a13a57b605994ee44e5c2cd7b9efc49901404 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 11 May 2022 15:58:07 -0700 Subject: [PATCH 096/170] drm/probe-helper: Add helper for drm_helper_probe_single_connector_modes() The drm_helper_probe_single_connector_modes() is a bit long. Let's break a chunk off to update and validate modes. This helps avoid one goto and also will allow us to more easily call the helper a second time in a future patch without adding looping or another goto. This change is intended to be a no-op change--just code movement. Signed-off-by: Douglas Anderson Reviewed-by: Abhinav Kumar Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220511155749.v3.1.I2dd93486c6952bd52f2020904de0133970d11b29@changeid --- drivers/gpu/drm/drm_probe_helper.c | 106 ++++++++++++++++------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index d77f17867195..0dd23a7193e7 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -354,6 +354,61 @@ drm_helper_probe_detect(struct drm_connector *connector, } EXPORT_SYMBOL(drm_helper_probe_detect); +static int __drm_helper_update_and_validate(struct drm_connector *connector, + uint32_t maxX, uint32_t maxY, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode; + int mode_flags = 0; + int ret; + + drm_connector_list_update(connector); + + if (connector->interlace_allowed) + mode_flags |= DRM_MODE_FLAG_INTERLACE; + if (connector->doublescan_allowed) + mode_flags |= DRM_MODE_FLAG_DBLSCAN; + if (connector->stereo_allowed) + mode_flags |= DRM_MODE_FLAG_3D_MASK; + + list_for_each_entry(mode, &connector->modes, head) { + if (mode->status != MODE_OK) + continue; + + mode->status = drm_mode_validate_driver(dev, mode); + if (mode->status != MODE_OK) + continue; + + mode->status = drm_mode_validate_size(mode, maxX, maxY); + if (mode->status != MODE_OK) + continue; + + mode->status = drm_mode_validate_flag(mode, mode_flags); + if (mode->status != MODE_OK) + continue; + + ret = drm_mode_validate_pipeline(mode, connector, ctx, + &mode->status); + if (ret) { + drm_dbg_kms(dev, + "drm_mode_validate_pipeline failed: %d\n", + ret); + + if (drm_WARN_ON_ONCE(dev, ret != -EDEADLK)) + mode->status = MODE_ERROR; + else + return -EDEADLK; + } + + if (mode->status != MODE_OK) + continue; + mode->status = drm_mode_validate_ycbcr420(mode, connector); + } + + return 0; +} + /** * drm_helper_probe_single_connector_modes - get complete set of display modes * @connector: connector to probe @@ -421,7 +476,6 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int count = 0, ret; - int mode_flags = 0; bool verbose_prune = true; enum drm_connector_status old_status; struct drm_modeset_acquire_ctx ctx; @@ -519,52 +573,12 @@ retry: connector->status == connector_status_unknown)) count = drm_add_modes_noedid(connector, 1024, 768); count += drm_helper_probe_add_cmdline_mode(connector); - if (count == 0) - goto prune; - - drm_connector_list_update(connector); - - if (connector->interlace_allowed) - mode_flags |= DRM_MODE_FLAG_INTERLACE; - if (connector->doublescan_allowed) - mode_flags |= DRM_MODE_FLAG_DBLSCAN; - if (connector->stereo_allowed) - mode_flags |= DRM_MODE_FLAG_3D_MASK; - - list_for_each_entry(mode, &connector->modes, head) { - if (mode->status != MODE_OK) - continue; - - mode->status = drm_mode_validate_driver(dev, mode); - if (mode->status != MODE_OK) - continue; - - mode->status = drm_mode_validate_size(mode, maxX, maxY); - if (mode->status != MODE_OK) - continue; - - mode->status = drm_mode_validate_flag(mode, mode_flags); - if (mode->status != MODE_OK) - continue; - - ret = drm_mode_validate_pipeline(mode, connector, &ctx, - &mode->status); - if (ret) { - drm_dbg_kms(dev, - "drm_mode_validate_pipeline failed: %d\n", - ret); - - if (drm_WARN_ON_ONCE(dev, ret != -EDEADLK)) { - mode->status = MODE_ERROR; - } else { - drm_modeset_backoff(&ctx); - goto retry; - } + if (count != 0) { + ret = __drm_helper_update_and_validate(connector, maxX, maxY, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; } - - if (mode->status != MODE_OK) - continue; - mode->status = drm_mode_validate_ycbcr420(mode, connector); } prune: From e7c254d75d16b75abf1958095fd34e2ecdc0d645 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 11 May 2022 15:58:08 -0700 Subject: [PATCH 097/170] drm/probe-helper: For DP, add 640x480 if all other modes are bad As per Displayport spec section 5.2.1.2 ("Video Timing Format") says that all detachable sinks shall support 640x480 @60Hz as a fail safe mode. A DP compliance test expected us to utilize the above fact when all modes it presented to the DP source were not achievable. It presented only modes that would be achievable with more lanes and/or higher speeds than we had available and expected that when we couldn't do that then we'd fall back to 640x480 even though it didn't advertise this size. In order to pass the compliance test (and also support any users who might fall into a similar situation with their display), we need to add 640x480 into the list of modes. However, we don't want to add 640x480 all the time. Despite the fact that the DP spec says all sinks _shall support_ 640x480, they're not guaranteed to support it _well_. Continuing to read the spec you can see that the display is not required to really treat 640x480 equal to all the other modes. It doesn't need to scale or anything--just display the pixels somehow for failsafe purposes. It should also be noted that it's not hard to find a display hooked up via DisplayPort that _doesn't_ support 640x480 at all. The HP ZR30w screen I'm sitting in front of has a native DP port and doesn't work at 640x480. I also plugged in a tiny 800x480 HDMI display via a DP to HDMI adapter and that screen definitely doesn't support 640x480. As a compromise solution, let's only add the 640x480 mode if: * We're on DP. * All other modes have been pruned. This acknowledges that 640x480 might not be the best mode to use but, since sinks are _supposed_ to support it, we will at least fall back to it if there's nothing else. Note that we _don't_ add higher resolution modes like 1024x768 in this case. We only add those modes for a failed EDID read where we have no idea what's going on. In the case where we've pruned all modes then instead we only want 640x480 which is the only defined "Fail Safe" resolution. This patch originated in response to Kuogee Hsieh's patch [1]. [1] https://lore.kernel.org/r/1650671124-14030-1-git-send-email-quic_khsieh@quicinc.com Signed-off-by: Douglas Anderson Tested-by: Kuogee Hsieh Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220511155749.v3.2.I4ac7f55aa446699f8c200a23c10463256f6f439f@changeid --- drivers/gpu/drm/drm_probe_helper.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 0dd23a7193e7..425f56280d51 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -476,7 +476,6 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int count = 0, ret; - bool verbose_prune = true; enum drm_connector_status old_status; struct drm_modeset_acquire_ctx ctx; @@ -556,8 +555,8 @@ retry: DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, connector->name); drm_connector_update_edid_property(connector, NULL); - verbose_prune = false; - goto prune; + drm_mode_prune_invalid(dev, &connector->modes, false); + goto exit; } count = (*connector_funcs->get_modes)(connector); @@ -581,9 +580,27 @@ retry: } } -prune: - drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); + drm_mode_prune_invalid(dev, &connector->modes, true); + /* + * Displayport spec section 5.2.1.2 ("Video Timing Format") says that + * all detachable sinks shall support 640x480 @60Hz as a fail safe + * mode. If all modes were pruned, perhaps because they need more + * lanes or a higher pixel clock than available, at least try to add + * in 640x480. + */ + if (list_empty(&connector->modes) && + connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + count = drm_add_modes_noedid(connector, 640, 480); + ret = __drm_helper_update_and_validate(connector, maxX, maxY, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_mode_prune_invalid(dev, &connector->modes, true); + } + +exit: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); From 69ef4a192bba0d76216198ec6d5fe82375337903 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 May 2022 16:18:09 -0700 Subject: [PATCH 098/170] drm: Document the power requirements for DP AUX transfers When doing DP AUX transfers there are two actors that need to be powered in order for the DP AUX transfer to work: the DP source and the DP sink. Commit bacbab58f09d ("drm: Mention the power state requirement on side-channel operations") added some documentation saying that the DP source is required to power itself up (if needed) to do AUX transfers. However, that commit doesn't talk anything about the DP sink. For full fledged DP the sink isn't really a problem. It's expected that if an external DP monitor isn't plugged in that attempting to do AUX transfers won't work. It's also expected that if a DP monitor is plugged in (and thus asserting HPD) then AUX transfers will work. When we're looking at eDP, however, things are less obvious. Let's add some documentation about expectations. Here's what we'll say: 1. We don't expect the DP AUX transfer function to power on an eDP panel. If an eDP panel is physically connected but powered off then it makes sense for the transfer to fail. 2. We'll document that the official way to power on a panel is via the bridge chain, specifically by making sure that the panel's prepare function has been called (which is called by panel_bridge_pre_enable()). It's already specified in the kernel doc of drm_panel_prepare() that this is the way to power the panel on and also that after this call "it is possible to communicate with any integrated circuitry via a command bus." 3. We'll also document that for code running in the panel driver itself that it is legal for the panel driver to power itself up however it wants (it doesn't need to officially call drm_panel_pre_enable()) and then it can do AUX bus transfers. This is currently the way that edp-panel works when it's running atop the DP AUX bus. NOTE: there was much discussion of all of this in response to v1 [1] of this patch. A summary of that is: * With the Intel i195 driver, apparently eDP panels do get powered up. We won't forbid this but it is expected that code that wants to run on a variety of platforms should ensure that the drm_panel's prepare() function has been called. * There is at least a reasonable amount of agreement that the transfer() functions itself shouldn't be responsible for powering the panel. It's proposed that if we need the DP AUX dev nodes to be robust for eDP that the code handling the DP AUX dev nodes could handle powering the panel by ensuring that the panel's prepare() call was made. Potentially drm_dp_aux_dev_get_by_minor() could be a good place to do this. This is left as a future exercise. Until that's fixed the DP AUX dev nodes for eDP are probably best just used for debugging. * If a panel could be in PSR and DP AUX via the dev node needs to be reliable then we need to be able to pull the panel out of PSR. On i915 this is also apparently handled as part of the transfer() function. [1] https://lore.kernel.org/r/20220503162033.1.Ia8651894026707e4fa61267da944ff739610d180@changeid Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220509161733.v2.1.Ia8651894026707e4fa61267da944ff739610d180@changeid --- include/drm/display/drm_dp_helper.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index dca40a045dd6..dc3c02225fcf 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -370,9 +370,19 @@ struct drm_dp_aux { * helpers assume this is the case. * * Also note that this callback can be called no matter the - * state @dev is in. Drivers that need that device to be powered - * to perform this operation will first need to make sure it's - * been properly enabled. + * state @dev is in and also no matter what state the panel is + * in. It's expected: + * - If the @dev providing the AUX bus is currently unpowered then + * it will power itself up for the transfer. + * - If we're on eDP (using a drm_panel) and the panel is not in a + * state where it can respond (it's not powered or it's in a + * low power state) then this function may return an error, but + * not crash. It's up to the caller of this code to make sure that + * the panel is powered on if getting an error back is not OK. If a + * drm_panel driver is initiating a DP AUX transfer it may power + * itself up however it wants. All other code should ensure that + * the pre_enable() bridge chain (which eventually calls the + * drm_panel prepare function) has powered the panel. */ ssize_t (*transfer)(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg); From 39c28cdfb719f0e306b447f0827dfd712f81858b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:41 -0700 Subject: [PATCH 099/170] drm/dp: Export symbol / kerneldoc fixes for DP AUX bus While working on the DP AUX bus code I found a few small things that should be fixed. Namely the non-devm version of of_dp_aux_populate_ep_devices() was missing an export. There was also an extra blank line in a kerneldoc and a kerneldoc that incorrectly documented a return value. Fix these. Fixes: aeb33699fc2c ("drm: Introduce the DP AUX bus") Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.1.Ia91f4849adfc5eb9da1eb37ba79aa65fb3c95a0f@changeid --- drivers/gpu/drm/display/drm_dp_aux_bus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_aux_bus.c b/drivers/gpu/drm/display/drm_dp_aux_bus.c index dccf3e2ea323..552f949cff59 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_bus.c +++ b/drivers/gpu/drm/display/drm_dp_aux_bus.c @@ -66,7 +66,6 @@ static int dp_aux_ep_probe(struct device *dev) * @dev: The device to remove. * * Calls through to the endpoint driver remove. - * */ static void dp_aux_ep_remove(struct device *dev) { @@ -120,8 +119,6 @@ ATTRIBUTE_GROUPS(dp_aux_ep_dev); /** * dp_aux_ep_dev_release() - Free memory for the dp_aux_ep device * @dev: The device to free. - * - * Return: 0 if no error or negative error code. */ static void dp_aux_ep_dev_release(struct device *dev) { @@ -256,6 +253,7 @@ int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) return 0; } +EXPORT_SYMBOL_GPL(of_dp_aux_populate_ep_devices); static void of_dp_aux_depopulate_ep_devices_void(void *data) { From 0d662350928e6787d29ab205e47e5aa6f1f792f9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 19 May 2022 11:51:36 +0200 Subject: [PATCH 100/170] drm/bridge: tc358767: Handle dsi_lanes == 0 as invalid Handle empty data-lanes = < >; property, which translates to dsi_lanes = 0 as invalid. Reviewed-by: Andrzej Hajda Reviewed-by: Lucas Stach Fixes: bbfd3190b6562 ("drm/bridge: tc358767: Add DSI-to-DPI mode support") Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20220519095137.11896-1-marex@denx.de --- drivers/gpu/drm/bridge/tc358767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 798da0e4d086..f78c2ad84515 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1899,7 +1899,7 @@ static int tc_mipi_dsi_host_attach(struct tc_data *tc) of_node_put(host_node); of_node_put(endpoint); - if (dsi_lanes < 0 || dsi_lanes > 4) + if (dsi_lanes <= 0 || dsi_lanes > 4) return -EINVAL; if (!host) From c1de02bbeca58894c805b3d45c2da4bf30cfc5d9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 19 May 2022 11:51:37 +0200 Subject: [PATCH 101/170] drm/bridge: tc358767: Report DSI-to-(e)DP as supported The DSI-to-e(DP) mode is now supported, update the driver comment to reflect this. No functional change. Reviewed-by: Andrzej Hajda Reviewed-by: Lucas Stach Fixes: 3080c21a043ab ("drm/bridge: tc358767: Add DSI-to-(e)DP mode support") Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20220519095137.11896-2-marex@denx.de --- drivers/gpu/drm/bridge/tc358767.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index f78c2ad84515..45ea829d5660 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -3,10 +3,7 @@ * TC358767/TC358867/TC9595 DSI/DPI-to-DPI/(e)DP bridge driver * * The TC358767/TC358867/TC9595 can operate in multiple modes. - * The following modes are supported: - * DPI->(e)DP -- supported - * DSI->DPI .... supported - * DSI->(e)DP .. NOT supported + * All modes are supported -- DPI->(e)DP / DSI->DPI / DSI->(e)DP . * * Copyright (C) 2016 CogentEmbedded Inc * Author: Andrey Gusakov From 0b4c48f3e315d172e4cc06e10f2c8ba180788baf Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 20 May 2022 14:15:43 +0200 Subject: [PATCH 102/170] drm/bridge: tc358767: Make sure Refclk clock are enabled The Refclk may be supplied by SoC clock output instead of crystal oscillator, make sure the clock are enabled before any other action is performed with the bridge chip, otherwise it may either fail to operate at all, or miss reset GPIO toggle. Reviewed-by: Lucas Stach Fixes: 7caff0fc4296e ("drm/bridge: tc358767: Add DPI to eDP bridge driver") Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Reviewed-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20220520121543.11550-1-marex@denx.de --- drivers/gpu/drm/bridge/tc358767.c | 32 ++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 45ea829d5660..6c6177028742 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2033,6 +2033,13 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc) return -EINVAL; } +static void tc_clk_disable(void *data) +{ + struct clk *refclk = data; + + clk_disable_unprepare(refclk); +} + static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; @@ -2049,6 +2056,24 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) if (ret) return ret; + tc->refclk = devm_clk_get(dev, "ref"); + if (IS_ERR(tc->refclk)) { + ret = PTR_ERR(tc->refclk); + dev_err(dev, "Failed to get refclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(tc->refclk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, tc_clk_disable, tc->refclk); + if (ret) + return ret; + + /* tRSTW = 100 cycles , at 13 MHz that is ~7.69 us */ + usleep_range(10, 15); + /* Shut down GPIO is optional */ tc->sd_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); if (IS_ERR(tc->sd_gpio)) @@ -2069,13 +2094,6 @@ static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id) usleep_range(5000, 10000); } - tc->refclk = devm_clk_get(dev, "ref"); - if (IS_ERR(tc->refclk)) { - ret = PTR_ERR(tc->refclk); - dev_err(dev, "Failed to get refclk: %d\n", ret); - return ret; - } - tc->regmap = devm_regmap_init_i2c(client, &tc_regmap_config); if (IS_ERR(tc->regmap)) { ret = PTR_ERR(tc->regmap); From 6556551f8848f98eff356c8aacae42c8dd65b2df Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 5 Apr 2022 17:15:10 +0200 Subject: [PATCH 103/170] drm/r128: Fix undefined behavior due to shift overflowing the constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: drivers/gpu/drm/r128/r128_cce.c: In function ‘r128_do_init_cce’: drivers/gpu/drm/r128/r128_cce.c:417:2: error: case label does not reduce to an integer constant case R128_PM4_64BM_64VCBM_64INDBM: ^~~~ drivers/gpu/drm/r128/r128_cce.c:418:2: error: case label does not reduce to an integer constant case R128_PM4_64PIO_64VCPIO_64INDPIO: ^~~~ See https://lore.kernel.org/r/YkwQ6%2BtIH8GQpuct@zn.tnic for the gory details as to why it triggers with older gccs only. Reviewed-by: Randy Dunlap Signed-off-by: Borislav Petkov Cc: David Airlie Cc: Daniel Vetter Cc: Alex Deucher Cc: dri-devel@lists.freedesktop.org Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220405151517.29753-5-bp@alien8.de --- drivers/gpu/drm/r128/r128_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 2e1bc01aa5c9..970e192b0d51 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h @@ -300,8 +300,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, # define R128_PM4_64PIO_128INDBM (5 << 28) # define R128_PM4_64BM_128INDBM (6 << 28) # define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) -# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) -# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8U << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15U << 28) # define R128_PM4_BUFFER_CNTL_NOUPDATE (1 << 27) #define R128_PM4_BUFFER_WM_CNTL 0x0708 From 67d935b4713988d0a41097439c0c2d74f240b204 Mon Sep 17 00:00:00 2001 From: Bhanuprakash Modem Date: Thu, 19 May 2022 15:21:47 +0530 Subject: [PATCH 104/170] drm/debug: Expose connector's max supported bpc via debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's useful to know the connector's max supported bpc for IGT testing. Expose it via a debugfs file on the connector "output_bpc". Example: cat /sys/kernel/debug/dri/0/DP-1/output_bpc V2: * Fix typo in comments (Harry) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Harry Wentland Signed-off-by: Bhanuprakash Modem Reviewed-by: Arun R Murthy Reviewed-by: Harry Wentland Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220519095149.3560034-2-bhanuprakash.modem@intel.com --- drivers/gpu/drm/drm_debugfs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 7f1b82dbaebb..fb04b7a984de 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -395,6 +395,23 @@ static int vrr_range_show(struct seq_file *m, void *data) } DEFINE_SHOW_ATTRIBUTE(vrr_range); +/* + * Returns Connector's max supported bpc through debugfs file. + * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc + */ +static int output_bpc_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + + if (connector->status != connector_status_connected) + return -ENODEV; + + seq_printf(m, "Maximum: %u\n", connector->display_info.bpc); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(output_bpc); + static const struct file_operations drm_edid_fops = { .owner = THIS_MODULE, .open = edid_open, @@ -437,6 +454,10 @@ void drm_debugfs_connector_add(struct drm_connector *connector) debugfs_create_file("vrr_range", S_IRUGO, root, connector, &vrr_range_fops); + /* max bpc */ + debugfs_create_file("output_bpc", 0444, root, connector, + &output_bpc_fops); + if (connector->funcs->debugfs_init) connector->funcs->debugfs_init(connector, root); } From fa373eb2190115ef2c3597f89c12350d0a250eb0 Mon Sep 17 00:00:00 2001 From: Bhanuprakash Modem Date: Thu, 19 May 2022 15:21:48 +0530 Subject: [PATCH 105/170] drm/i915/display/debug: Expose crtc current bpc via debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This new debugfs will expose the currently using bpc by crtc. It is very useful for verifying whether we enter the correct output color depth from IGT. This patch will also add the connector's max supported bpc to "i915_display_info" debugfs. Example: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc Current: 8 Cc: Jani Nikula Cc: Ville Syrjälä Cc: Uma Shankar Signed-off-by: Bhanuprakash Modem Reviewed-by: Arun R Murthy Acked-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220519095149.3560034-3-bhanuprakash.modem@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 452d773fd4e3..6c3954479047 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -590,6 +590,8 @@ static void intel_connector_info(struct seq_file *m, seq_puts(m, "\tHDCP version: "); intel_hdcp_info(m, intel_connector); + seq_printf(m, "\tmax bpc: %u\n", connector->display_info.bpc); + intel_panel_info(m, intel_connector); seq_printf(m, "\tmodes:\n"); @@ -2202,6 +2204,29 @@ static const struct file_operations i915_dsc_bpp_fops = { .write = i915_dsc_bpp_write }; +/* + * Returns the Current CRTC's bpc. + * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc + */ +static int i915_current_bpc_show(struct seq_file *m, void *data) +{ + struct intel_crtc *crtc = to_intel_crtc(m->private); + struct intel_crtc_state *crtc_state; + int ret; + + ret = drm_modeset_lock_single_interruptible(&crtc->base.mutex); + if (ret) + return ret; + + crtc_state = to_intel_crtc_state(crtc->base.state); + seq_printf(m, "Current: %u\n", crtc_state->pipe_bpp / 3); + + drm_modeset_unlock(&crtc->base.mutex); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(i915_current_bpc); + /** * intel_connector_debugfs_add - add i915 specific connector debugfs files * @connector: pointer to a registered drm_connector @@ -2272,4 +2297,7 @@ void intel_crtc_debugfs_add(struct drm_crtc *crtc) crtc_updates_add(crtc); intel_fbc_crtc_debugfs_add(to_intel_crtc(crtc)); + + debugfs_create_file("i915_current_bpc", 0444, crtc->debugfs_entry, crtc, + &i915_current_bpc_fops); } From 4cd79f614b501e496ee8e4181d528c0cc1cb4e18 Mon Sep 17 00:00:00 2001 From: Bhanuprakash Modem Date: Thu, 19 May 2022 15:21:49 +0530 Subject: [PATCH 106/170] drm/amd/display: Move connector debugfs to drm As drm_connector already have the display_info, instead of creating "output_bpc" debugfs in vendor specific driver, move the logic to the drm layer. This patch will also move "Current" bpc to the crtc debugfs from connector debugfs, since we are getting this info from crtc_state. Cc: Harry Wentland Cc: Rodrigo Siqueira Signed-off-by: Bhanuprakash Modem Reported-by: kernel test robot Reviewed-by: Arun R Murthy Reviewed-by: Harry Wentland Acked-by: Harry Wentland Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20220519095149.3560034-4-bhanuprakash.modem@intel.com --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 -- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 38 +++++++------------ .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.h | 2 - 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index f9ce8cb45e6d..dae0b772865c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6617,14 +6617,12 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) return &state->base; } -#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc) { crtc_debugfs_init(crtc); return 0; } -#endif static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable) { @@ -6722,9 +6720,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .enable_vblank = dm_enable_vblank, .disable_vblank = dm_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) .late_register = amdgpu_dm_crtc_late_register, -#endif }; static enum drm_connector_status diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 188039f14544..78f3974ef7b8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -873,28 +873,18 @@ static int psr_capability_show(struct seq_file *m, void *data) } /* - * Returns the current and maximum output bpc for the connector. - * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc + * Returns the current bpc for the crtc. + * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/amdgpu_current_bpc */ -static int output_bpc_show(struct seq_file *m, void *data) +static int amdgpu_current_bpc_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; - struct drm_crtc *crtc = NULL; + struct drm_crtc *crtc = m->private; + struct drm_device *dev = crtc->dev; struct dm_crtc_state *dm_crtc_state = NULL; int res = -ENODEV; unsigned int bpc; mutex_lock(&dev->mode_config.mutex); - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - - if (connector->state == NULL) - goto unlock; - - crtc = connector->state->crtc; - if (crtc == NULL) - goto unlock; - drm_modeset_lock(&crtc->mutex, NULL); if (crtc->state == NULL) goto unlock; @@ -924,18 +914,15 @@ static int output_bpc_show(struct seq_file *m, void *data) } seq_printf(m, "Current: %u\n", bpc); - seq_printf(m, "Maximum: %u\n", connector->display_info.bpc); res = 0; unlock: - if (crtc) - drm_modeset_unlock(&crtc->mutex); - - drm_modeset_unlock(&dev->mode_config.connection_mutex); + drm_modeset_unlock(&crtc->mutex); mutex_unlock(&dev->mode_config.mutex); return res; } +DEFINE_SHOW_ATTRIBUTE(amdgpu_current_bpc); /* * Example usage: @@ -2541,7 +2528,6 @@ static int target_backlight_show(struct seq_file *m, void *unused) DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support); DEFINE_SHOW_ATTRIBUTE(dmub_fw_state); DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer); -DEFINE_SHOW_ATTRIBUTE(output_bpc); DEFINE_SHOW_ATTRIBUTE(dp_lttpr_status); #ifdef CONFIG_DRM_AMD_DC_HDCP DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability); @@ -2788,7 +2774,6 @@ static const struct { const struct file_operations *fops; } connector_debugfs_entries[] = { {"force_yuv420_output", &force_yuv420_output_fops}, - {"output_bpc", &output_bpc_fops}, {"trigger_hotplug", &trigger_hotplug_debugfs_fops}, {"internal_display", &internal_display_fops} }; @@ -3172,9 +3157,10 @@ static int crc_win_update_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(crc_win_update_fops, crc_win_update_get, crc_win_update_set, "%llu\n"); - +#endif void crtc_debugfs_init(struct drm_crtc *crtc) { +#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY struct dentry *dir = debugfs_lookup("crc", crtc->debugfs_entry); if (!dir) @@ -3190,9 +3176,11 @@ void crtc_debugfs_init(struct drm_crtc *crtc) &crc_win_y_end_fops); debugfs_create_file_unsafe("crc_win_update", 0644, dir, crtc, &crc_win_update_fops); - -} #endif + debugfs_create_file("amdgpu_current_bpc", 0644, crtc->debugfs_entry, + crtc, &amdgpu_current_bpc_fops); +} + /* * Writes DTN log state to the user supplied buffer. * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h index 3366cb644053..071200473c27 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -31,8 +31,6 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector); void dtn_debugfs_init(struct amdgpu_device *adev); -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) void crtc_debugfs_init(struct drm_crtc *crtc); -#endif #endif From 2ba5b683260e13d8f2c43bc594d5ae15ec7f7a04 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 19 May 2022 01:38:44 +0200 Subject: [PATCH 107/170] drm/bridge: ti-sn65dsi83: Handle dsi_lanes == 0 as invalid Handle empty data-lanes = < >; property, which translates to dsi_lanes = 0 as invalid. Fixes: ceb515ba29ba6 ("drm/bridge: ti-sn65dsi83: Add TI SN65DSI83 and SN65DSI84 driver") Signed-off-by: Marek Vasut Cc: Jonas Karlman Cc: Laurent Pinchart Cc: Lucas Stach Cc: Marek Vasut Cc: Maxime Ripard Cc: Neil Armstrong Cc: Robert Foss Cc: Sam Ravnborg Reviewed-by: Andrzej Hajda Reviewed-by: Lucas Stach Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220518233844.248504-1-marex@denx.de --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 2831f0813c3a..ac66f408b40c 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -577,7 +577,7 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) ctx->host_node = of_graph_get_remote_port_parent(endpoint); of_node_put(endpoint); - if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) { + if (ctx->dsi_lanes <= 0 || ctx->dsi_lanes > 4) { ret = -EINVAL; goto err_put_node; } From 670c87fd169518eb4f15030c63f6c1b4ddf18bfb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 19 May 2022 13:23:37 +0200 Subject: [PATCH 108/170] drm/bridge: anx7625: Add missing of_node_put for endpoint Add of_node_put call on the endpoint node after it is not needed. Signed-off-by: Marek Vasut Cc: Alex Deucher Cc: Javier Martinez Canillas Cc: Lyude Paul Cc: Thomas Zimmermann Cc: Xin Ji Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220519112337.62198-1-marex@denx.de --- drivers/gpu/drm/bridge/analogix/anx7625.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 01f46d9189c1..0fab2aa47c67 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1638,6 +1638,7 @@ static int anx7625_parse_dt(struct device *dev, bus_type = 0; mipi_lanes = of_property_count_u32_elems(ep0, "data-lanes"); + of_node_put(ep0); } if (bus_type == V4L2_FWNODE_BUS_TYPE_DPI) /* bus type is DPI */ From 1ff72d434b40d221e2583fab5e1203031d05c059 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 11 May 2022 01:26:11 +0000 Subject: [PATCH 109/170] drm/bridge: lt9611: Consolidate detection logic This patch simply consolidates the duplicated detection functionality in the driver. Cc: Yongqin Liu Cc: Amit Pundir Cc: Peter Collingbourne Cc: Vinod Koul Cc: Bjorn Andersson Cc: Robert Foss Cc: kernel-team@android.com Reviewed-by: Robert Foss Signed-off-by: John Stultz Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220511012612.3297577-1-jstultz@google.com --- drivers/gpu/drm/bridge/lontium-lt9611.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 7ef8fe5abc12..08a9b606c12d 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -578,10 +578,8 @@ static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode) } /* connector funcs */ -static enum drm_connector_status -lt9611_connector_detect(struct drm_connector *connector, bool force) +static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) { - struct lt9611 *lt9611 = connector_to_lt9611(connector); unsigned int reg_val = 0; int connected = 0; @@ -594,6 +592,12 @@ lt9611_connector_detect(struct drm_connector *connector, bool force) return lt9611->status; } +static enum drm_connector_status +lt9611_connector_detect(struct drm_connector *connector, bool force) +{ + return __lt9611_detect(connector_to_lt9611(connector)); +} + static int lt9611_read_edid(struct lt9611 *lt9611) { unsigned int temp; @@ -893,17 +897,7 @@ static void lt9611_bridge_mode_set(struct drm_bridge *bridge, static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge) { - struct lt9611 *lt9611 = bridge_to_lt9611(bridge); - unsigned int reg_val = 0; - int connected; - - regmap_read(lt9611->regmap, 0x825e, ®_val); - connected = reg_val & BIT(0); - - lt9611->status = connected ? connector_status_connected : - connector_status_disconnected; - - return lt9611->status; + return __lt9611_detect(bridge_to_lt9611(bridge)); } static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge, From 649eb3828fb22e829e222ebd83f4e11dc503a565 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 11 May 2022 01:26:12 +0000 Subject: [PATCH 110/170] drm/bridge: lt9611: Use both bits for HDMI sensing In commit 19cf41b64e3b ("lontium-lt9611: check a different register bit for HDMI sensing"), the bit flag used to detect HDMI cable connect was switched from BIT(2) to BIT(0) to improve compatibility with some monitors that didn't seem to set BIT(2). However, with that change, I've seen occasional issues where the detection failed, because BIT(2) was set, but not BIT(0). Unfortunately, as I understand it, the bits and their function was never clearly documented. So lets instead check both (BIT(2) | BIT(0)) when checking the register. Cc: Yongqin Liu Cc: Amit Pundir Cc: Peter Collingbourne Cc: Vinod Koul Cc: Bjorn Andersson Cc: Robert Foss Cc: kernel-team@android.com Fixes: 19cf41b64e3b ("lontium-lt9611: check a different register bit for HDMI sensing") Signed-off-by: John Stultz Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220511012612.3297577-2-jstultz@google.com --- drivers/gpu/drm/bridge/lontium-lt9611.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 08a9b606c12d..88f2a4f43cfb 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -584,7 +584,7 @@ static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611) int connected = 0; regmap_read(lt9611->regmap, 0x825e, ®_val); - connected = (reg_val & BIT(0)); + connected = (reg_val & (BIT(2) | BIT(0))); lt9611->status = connected ? connector_status_connected : connector_status_disconnected; From 9ad6f181ad9a19a26bda73a7b199df44ccfcdaba Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 20 May 2022 11:16:02 +0200 Subject: [PATCH 111/170] drm/st7735r: Fix module autoloading for Okaya RH128128T The SPI core always reports a "MODALIAS=spi:", even if the device was registered via OF. This means that the st7735r.ko module won't autoload if a DT has a node with a compatible "okaya,rh128128t" string. In that case, kmod expects a "MODALIAS=of:N*T*Cokaya,rh128128t" uevent but instead will get a "MODALIAS=spi:rh128128t", which is not present in the list of aliases: $ modinfo drivers/gpu/drm/tiny/st7735r.ko | grep alias alias: of:N*T*Cokaya,rh128128tC* alias: of:N*T*Cokaya,rh128128t alias: of:N*T*Cjianda,jd-t18003-t01C* alias: of:N*T*Cjianda,jd-t18003-t01 alias: spi:jd-t18003-t01 To workaround this issue, add in the SPI table an entry for that device. Fixes: d1d511d516f7 ("drm: tiny: st7735r: Add support for Okaya RH128128T") Signed-off-by: Javier Martinez Canillas Reviewed-by: Geert Uytterhoeven Acked-by: David Lechner Link: https://patchwork.freedesktop.org/patch/msgid/20220520091602.179078-1-javierm@redhat.com --- drivers/gpu/drm/tiny/st7735r.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index 29d618093e94..e0f02d367d88 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -174,6 +174,7 @@ MODULE_DEVICE_TABLE(of, st7735r_of_match); static const struct spi_device_id st7735r_id[] = { { "jd-t18003-t01", (uintptr_t)&jd_t18003_t01_cfg }, + { "rh128128t", (uintptr_t)&rh128128t_cfg }, { }, }; MODULE_DEVICE_TABLE(spi, st7735r_id); From 61922beba36adea8702fe8069b309c806f6608af Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 23 May 2022 18:15:19 +0200 Subject: [PATCH 112/170] Revert "drm/bridge: anx7625: Use DPI bus type" This reverts commit a77c2af0994e24ee36c7ffb6dc852770bdf06fb1. This patch depends on the patches just aplied to the media tree, and will not build without them, which leaves drm-misc-next in a broken state. Let's revert the two latter patches until rc1 has been branched, and rc1 has been backmerged into drm-misc-next. Signed-off-by: Robert Foss Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220523161520.354687-1-robert.foss@linaro.org --- drivers/gpu/drm/bridge/analogix/anx7625.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 0fab2aa47c67..e92eb4a40745 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1623,14 +1623,14 @@ static int anx7625_parse_dt(struct device *dev, anx7625_get_swing_setting(dev, pdata); - pdata->is_dpi = 0; /* default dsi mode */ + pdata->is_dpi = 1; /* default dpi mode */ pdata->mipi_host_node = of_graph_get_remote_node(np, 0, 0); if (!pdata->mipi_host_node) { DRM_DEV_ERROR(dev, "fail to get internal panel.\n"); return -ENODEV; } - bus_type = 0; + bus_type = V4L2_FWNODE_BUS_TYPE_PARALLEL; mipi_lanes = MAX_LANES_SUPPORT; ep0 = of_graph_get_endpoint_by_regs(np, 0, 0); if (ep0) { @@ -1641,8 +1641,8 @@ static int anx7625_parse_dt(struct device *dev, of_node_put(ep0); } - if (bus_type == V4L2_FWNODE_BUS_TYPE_DPI) /* bus type is DPI */ - pdata->is_dpi = 1; + if (bus_type == V4L2_FWNODE_BUS_TYPE_PARALLEL) /* bus type is Parallel(DSI) */ + pdata->is_dpi = 0; pdata->mipi_lanes = mipi_lanes; if (pdata->mipi_lanes > MAX_LANES_SUPPORT || pdata->mipi_lanes <= 0) From 8e71a4a8156a9f3fa27088dc59e852693713d94f Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 23 May 2022 18:15:20 +0200 Subject: [PATCH 113/170] Revert "dt-bindings:drm/bridge:anx7625: add port@0 property" This reverts commit 7328736d270aa4fa6fcd033ade02acc2874a2db5. This patch depends on the patches just aplied to the media tree, and will not build without them, which leaves drm-misc-next in a broken state. Let's revert the two latter patches until rc1 has been branched, and rc1 has been backmerged into drm-misc-next. Signed-off-by: Robert Foss Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220523161520.354687-2-robert.foss@linaro.org --- .../display/bridge/analogix,anx7625.yaml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml index 4590186c4a0b..35a48515836e 100644 --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml @@ -94,22 +94,7 @@ properties: $ref: /schemas/graph.yaml#/$defs/port-base unevaluatedProperties: false description: - MIPI DSI/DPI input. - - properties: - endpoint: - $ref: /schemas/media/video-interfaces.yaml# - type: object - additionalProperties: false - - properties: - remote-endpoint: true - - bus-type: - enum: [7] - default: 1 - - data-lanes: true + Video port for MIPI DSI input. port@1: $ref: /schemas/graph.yaml#/properties/port @@ -158,8 +143,6 @@ examples: reg = <0>; anx7625_in: endpoint { remote-endpoint = <&mipi_dsi>; - bus-type = <7>; - data-lanes = <0 1 2 3>; }; }; From 6b03816f869529393b37d03e5d75b68f7365a7a4 Mon Sep 17 00:00:00 2001 From: Mark Menzynski Date: Mon, 23 May 2022 13:35:41 +0200 Subject: [PATCH 114/170] drm/nouveau: clear output poll workers before nouveau_fbcon_destroy() Resources needed for output poll workers are destroyed in nouveau_fbcon_fini() before output poll workers are cleared in nouveau_display_fini(). This means there is a time between fbcon_fini() and display_fini(), where if output poll happens, it crashes. This patch introduces another output poll clearing before fbcon resources are destroyed. BUG: KASAN: use-after-free in __drm_fb_helper_initial_config_and_unlock.cold+0x1f3/0x291 [drm_kms_helper] Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Cc: nouveau@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Menzynski Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220523113541.10562-1-mmenzyns@redhat.com --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 4f9b3aa5deda..5226323e55d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -605,6 +606,7 @@ nouveau_fbcon_fini(struct drm_device *dev) if (!drm->fbcon) return; + drm_kms_helper_poll_fini(dev); nouveau_fbcon_accel_fini(dev); nouveau_fbcon_destroy(dev, drm->fbcon); kfree(drm->fbcon); From e4f21d1436519fec3e181082c8e1c3fb00ec08a7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:07 +0200 Subject: [PATCH 115/170] drm/nouveau/mmu: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Reviewed-by: Lyude Paul [also fix double space] Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220521111145.81697-57-Julia.Lawall@inria.fr --- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index 8bf00b396ec1..ca74775834dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -280,7 +280,7 @@ nvkm_vmm_unref_ptes(struct nvkm_vmm_iter *it, bool pfn, u32 ptei, u32 ptes) if (desc->type == SPT && (pgt->refs[0] || pgt->refs[1])) nvkm_vmm_unref_sptes(it, pgt, desc, ptei, ptes); - /* PT no longer neeed? Destroy it. */ + /* PT no longer needed? Destroy it. */ if (!pgt->refs[type]) { it->lvl++; TRA(it, "%s empty", nvkm_vmm_desc_type(desc)); From 1a3b1ea111c44d9dce9f70ba032531a223395a15 Mon Sep 17 00:00:00 2001 From: Guo Zhengkui Date: Thu, 19 May 2022 15:29:48 +0800 Subject: [PATCH 116/170] drm/nouveau/tegra: remove needless NULL check There has already been NULL check in clk_prepare_enable() and clk_disable_unprepare(), so remove needless NULL check before calling them. Signed-off-by: Guo Zhengkui Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220519072950.128268-1-guozhengkui@vivo.com --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 992cc285f2fe..493c297966d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -41,11 +41,9 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) ret = clk_prepare_enable(tdev->clk); if (ret) goto err_clk; - if (tdev->clk_ref) { - ret = clk_prepare_enable(tdev->clk_ref); - if (ret) - goto err_clk_ref; - } + ret = clk_prepare_enable(tdev->clk_ref); + if (ret) + goto err_clk_ref; ret = clk_prepare_enable(tdev->clk_pwr); if (ret) goto err_clk_pwr; @@ -70,8 +68,7 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) err_clamp: clk_disable_unprepare(tdev->clk_pwr); err_clk_pwr: - if (tdev->clk_ref) - clk_disable_unprepare(tdev->clk_ref); + clk_disable_unprepare(tdev->clk_ref); err_clk_ref: clk_disable_unprepare(tdev->clk); err_clk: @@ -87,8 +84,7 @@ nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev) int ret; clk_disable_unprepare(tdev->clk_pwr); - if (tdev->clk_ref) - clk_disable_unprepare(tdev->clk_ref); + clk_disable_unprepare(tdev->clk_ref); clk_disable_unprepare(tdev->clk); udelay(10); From a67664860f7833015a683ea295f7c79ac2901332 Mon Sep 17 00:00:00 2001 From: Gao Chao Date: Tue, 24 May 2022 10:45:51 +0800 Subject: [PATCH 117/170] drm/panel: Fix build error when CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=y && CONFIG_DRM_DISPLAY_HELPER=m If CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=y && CONFIG_DRM_DISPLAY_HELPER=m, bulding fails: drivers/gpu/drm/panel/panel-samsung-atna33xc20.o: In function `atana33xc20_probe': panel-samsung-atna33xc20.c:(.text+0x744): undefined reference to `drm_panel_dp_aux_backlight' make: *** [vmlinux] Error 1 Let CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 select DRM_DISPLAY_DP_HELPER and CONFIG_DRM_DISPLAY_HELPER to fix this error. Fixes: 32ce3b320343 ("drm/panel: atna33xc20: Introduce the Samsung ATNA33XC20 panel") Reported-by: Hulk Robot Signed-off-by: Gao Chao Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20220524024551.539-1-gaochao49@huawei.com --- drivers/gpu/drm/panel/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 38799effd00a..4f1f004b3c54 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -438,6 +438,8 @@ config DRM_PANEL_SAMSUNG_ATNA33XC20 depends on OF depends on BACKLIGHT_CLASS_DEVICE depends on PM + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER select DRM_DP_AUX_BUS help DRM panel driver for the Samsung ATNA33XC20 panel. This panel can't From b981cc333ff06cb23c7968007965e79c80f5df97 Mon Sep 17 00:00:00 2001 From: Niels Dossche Date: Sun, 22 May 2022 01:41:04 +0200 Subject: [PATCH 118/170] drm: use ENOMEM for drmm_kzalloc allocation failures Other callers of drmm_kzalloc already return -ENOMEM on allocation failure. Change EINVAL to ENOMEM for consistency. Signed-off-by: Niels Dossche Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220521234104.88410-1-dossche.niels@gmail.com --- drivers/gpu/drm/drm_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 72e982323a5e..a940024c8087 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -226,7 +226,7 @@ void *__drmm_encoder_alloc(struct drm_device *dev, size_t size, size_t offset, container = drmm_kzalloc(dev, size, GFP_KERNEL); if (!container) - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOMEM); encoder = container + offset; From e31372492904415e425430402453a192e2c6519f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Sat, 21 May 2022 16:13:42 -0300 Subject: [PATCH 119/170] drm/vkms: Update vkms_composer_worker documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ba420afab565 ("drm/vkms: Bugfix racing hrtimer vblank handle") the work is scheduled at vkms_vblank_simulate() and since commit 5ef8100a3919 ("drm/vkms: flush crc workers earlier in commit flow") the work is flushed at vkms_atomic_commit_tail(). Update function commment to reflect that. Signed-off-by: André Almeida Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220521191342.23520-1-andrealmeid@igalia.com --- drivers/gpu/drm/vkms/vkms_composer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index c6a1036bf2ea..914c0ac7dc8b 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -213,7 +213,7 @@ static int compose_active_planes(void **vaddr_out, * * Work handler for composing and computing CRCs. work_struct scheduled in * an ordered workqueue that's periodically scheduled to run by - * _vblank_handle() and flushed at vkms_atomic_crtc_destroy_state(). + * vkms_vblank_simulate() and flushed at vkms_atomic_commit_tail(). */ void vkms_composer_worker(struct work_struct *work) { From 91776af1d8deb8f36cbec6bf2bf24b661b2b5cbb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 25 May 2022 18:53:16 -0300 Subject: [PATCH 120/170] drm: bridge: adv7511: Move CEC definitions to adv7511_cec.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADV7511_REG_CEC_RX_FRAME_HDR[] and ADV7511_REG_CEC_RX_FRAME_LEN[] are only used inside adv7511_cec.c. Move their definitions to this file to avoid the following build warnings when CONFIG_DRM_I2C_ADV7511_CEC is not selected: drivers/gpu/drm/bridge/adv7511/adv7511.h:229:17: warning: 'ADV7511_REG_CEC_RX_FRAME_HDR' defined but not used [-Wunused-const-variable=] drivers/gpu/drm/bridge/adv7511/adv7511.h:235:17: warning: 'ADV7511_REG_CEC_RX_FRAME_LEN' defined but not used [-Wunused-const-variable=] Reported-by: kernel test robot Fixes: ab0af093bf90 ("drm: bridge: adv7511: use non-legacy mode for CEC RX") Signed-off-by: Fabio Estevam Reviewed-by: Alvin Šipraga Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220525215316.1133057-1-festevam@gmail.com --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 12 ------------ drivers/gpu/drm/bridge/adv7511/adv7511_cec.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 9e3bb8a8ee40..a031a0cd1f18 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -226,18 +226,6 @@ #define ADV7511_REG_CEC_CLK_DIV 0x4e #define ADV7511_REG_CEC_SOFT_RESET 0x50 -static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = { - ADV7511_REG_CEC_RX1_FRAME_HDR, - ADV7511_REG_CEC_RX2_FRAME_HDR, - ADV7511_REG_CEC_RX3_FRAME_HDR, -}; - -static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = { - ADV7511_REG_CEC_RX1_FRAME_LEN, - ADV7511_REG_CEC_RX2_FRAME_LEN, - ADV7511_REG_CEC_RX3_FRAME_LEN, -}; - #define ADV7533_REG_CEC_OFFSET 0x70 enum adv7511_input_clock { diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c index 399f625a50c8..0b266f28f150 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c @@ -15,6 +15,18 @@ #include "adv7511.h" +static const u8 ADV7511_REG_CEC_RX_FRAME_HDR[] = { + ADV7511_REG_CEC_RX1_FRAME_HDR, + ADV7511_REG_CEC_RX2_FRAME_HDR, + ADV7511_REG_CEC_RX3_FRAME_HDR, +}; + +static const u8 ADV7511_REG_CEC_RX_FRAME_LEN[] = { + ADV7511_REG_CEC_RX1_FRAME_LEN, + ADV7511_REG_CEC_RX2_FRAME_LEN, + ADV7511_REG_CEC_RX3_FRAME_LEN, +}; + #define ADV7511_INT1_CEC_MASK \ (ADV7511_INT1_CEC_TX_READY | ADV7511_INT1_CEC_TX_ARBIT_LOST | \ ADV7511_INT1_CEC_TX_RETRY_TIMEOUT | ADV7511_INT1_CEC_RX_READY1 | \ From f4d8aec6e4bf0a554388f30d555657cfb0d6e8c4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 25 May 2022 15:56:26 -0500 Subject: [PATCH 121/170] dt-bindings: display: ingenic,jz4780-hdmi: Drop undocumented 'ddc-i2c-bus' While 'ddc-i2c-bus' is a common property, it should be in a connector node rather than the HDMI bridge node as the I2C bus goes to a connector and not the HDMI block. Drop it from the example. Signed-off-by: Rob Herring Reviewed-by: Laurent Pinchart Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220525205626.2482584-1-robh@kernel.org --- .../devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml index b8219eab4475..89490fdffeb0 100644 --- a/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml @@ -55,7 +55,6 @@ examples: compatible = "ingenic,jz4780-dw-hdmi"; reg = <0x10180000 0x8000>; reg-io-width = <4>; - ddc-i2c-bus = <&i2c4>; interrupt-parent = <&intc>; interrupts = <3>; clocks = <&cgu JZ4780_CLK_AHB0>, <&cgu JZ4780_CLK_HDMI>; From 9180c30cd61aa0b2f0eb4791c8e490c8c5abc54c Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Mon, 23 May 2022 23:01:44 +1000 Subject: [PATCH 122/170] drm: bridge: icn6211: Adjust clock phase using SYS_CTRL_1 The code from [1] sets SYS_CTRL_1 to different values depending on the desired clock phase (0, 1/4, 1/2 or 3/4). A clock phase of 0 aligns the positive edge of the clock with the pixel data while other values delay the clock by a fraction of the clock period. A clock phase of 1/2 aligns the negative edge of the clock with the pixel data. The driver currently hard codes SYS_CTRL_1 to 0x88 which corresponds to aligning the positive edge of the clock with the pixel data. This won't work correctly for panels that require aligning the negative edge of the clock with the pixel data. Adjust the clock phase to 0 if DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE is present in bus_flags, otherwise adjust the clock phase to 1/2 as appropriate for DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE. [1] https://github.com/tdjastrzebski/ICN6211-Configurator Signed-off-by: Jonathan Liu Reviewed-by: Marek Vasut Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220523130144.444225-1-net147@gmail.com --- drivers/gpu/drm/bridge/chipone-icn6211.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index cc9c12a33639..2b8cf64cbd80 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -26,6 +28,11 @@ #define PD_CTRL(n) (0x0a + ((n) & 0x3)) /* 0..3 */ #define RST_CTRL(n) (0x0e + ((n) & 0x1)) /* 0..1 */ #define SYS_CTRL(n) (0x10 + ((n) & 0x7)) /* 0..4 */ +#define SYS_CTRL_1_CLK_PHASE_MSK GENMASK(5, 4) +#define CLK_PHASE_0 0 +#define CLK_PHASE_1_4 1 +#define CLK_PHASE_1_2 2 +#define CLK_PHASE_3_4 3 #define RGB_DRV(n) (0x18 + ((n) & 0x3)) /* 0..3 */ #define RGB_DLY(n) (0x1c + ((n) & 0x1)) /* 0..1 */ #define RGB_TEST_CTRL 0x1e @@ -334,7 +341,7 @@ static void chipone_atomic_enable(struct drm_bridge *bridge, const struct drm_bridge_state *bridge_state; u16 hfp, hbp, hsync; u32 bus_flags; - u8 pol, id[4]; + u8 pol, sys_ctrl_1, id[4]; chipone_readb(icn, VENDOR_ID, id); chipone_readb(icn, DEVICE_ID_H, id + 1); @@ -412,7 +419,14 @@ static void chipone_atomic_enable(struct drm_bridge *bridge, chipone_configure_pll(icn, mode); chipone_writeb(icn, SYS_CTRL(0), 0x40); - chipone_writeb(icn, SYS_CTRL(1), 0x88); + sys_ctrl_1 = 0x88; + + if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) + sys_ctrl_1 |= FIELD_PREP(SYS_CTRL_1_CLK_PHASE_MSK, CLK_PHASE_0); + else + sys_ctrl_1 |= FIELD_PREP(SYS_CTRL_1_CLK_PHASE_MSK, CLK_PHASE_1_2); + + chipone_writeb(icn, SYS_CTRL(1), sys_ctrl_1); /* icn6211 specific sequence */ chipone_writeb(icn, MIPI_FORCE_0, 0x20); From 5d82e74a97c292da054ac5e49b41926242ada745 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:46 -0400 Subject: [PATCH 123/170] dt-bindings: Add compatible for Mali Valhall (JM) From the kernel's perspective, (pre-CSF, "Job Manager") Valhall is more or less compatible with Bifrost, although they differ to userspace. Add a compatible for Valhall to the existing Bifrost bindings documentation. As the first SoC with a Valhall GPU receiving mainline support, add a specific compatible for the MediaTek MT8192, which instantiates a Mali-G57. v2: Change compatible to arm,mali-valhall-jm (Daniel Stone). CC: devicetree@vger.kernel.org Reviewed-by: Rob Herring Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-2-alyssa.rosenzweig@collabora.com --- .../bindings/gpu/arm,mali-bifrost.yaml | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml index 85f8d4764740..78964c140b46 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml @@ -14,16 +14,21 @@ properties: pattern: '^gpu@[a-f0-9]+$' compatible: - items: - - enum: - - amlogic,meson-g12a-mali - - mediatek,mt8183-mali - - realtek,rtd1619-mali - - renesas,r9a07g044-mali - - renesas,r9a07g054-mali - - rockchip,px30-mali - - rockchip,rk3568-mali - - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable + oneOf: + - items: + - enum: + - amlogic,meson-g12a-mali + - mediatek,mt8183-mali + - realtek,rtd1619-mali + - renesas,r9a07g044-mali + - renesas,r9a07g054-mali + - rockchip,px30-mali + - rockchip,rk3568-mali + - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable + - items: + - enum: + - mediatek,mt8192-mali + - const: arm,mali-valhall-jm # Mali Valhall GPU model/revision is fully discoverable reg: maxItems: 1 From 382435709516c1a7dc3843872792abf95e786c83 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:47 -0400 Subject: [PATCH 124/170] drm/panfrost: Handle HW_ISSUE_TTRX_2968_TTRX_3162 Add handling for the HW_ISSUE_TTRX_2968_TTRX_3162 quirk. Logic ported from kbase. kbase lists this workaround as used on Mali-G57. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-3-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 3 +++ drivers/gpu/drm/panfrost/panfrost_issues.h | 3 +++ drivers/gpu/drm/panfrost/panfrost_regs.h | 1 + 3 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index aa89926742fd..295bef27fb55 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -108,6 +108,9 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) quirks |= SC_LS_ALLOW_ATTR_TYPES; } + if (panfrost_has_hw_issue(pfdev, HW_ISSUE_TTRX_2968_TTRX_3162)) + quirks |= SC_VAR_ALGORITHM; + if (panfrost_has_hw_feature(pfdev, HW_FEATURE_TLS_HASHING)) quirks |= SC_TLS_HASH_ENABLE; diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h index 501a76c5e95f..41a714ce6fce 100644 --- a/drivers/gpu/drm/panfrost/panfrost_issues.h +++ b/drivers/gpu/drm/panfrost/panfrost_issues.h @@ -125,6 +125,9 @@ enum panfrost_hw_issue { * kernel must fiddle with L2 caches to prevent data leakage */ HW_ISSUE_TGOX_R1_1234, + /* Must set SC_VAR_ALGORITHM */ + HW_ISSUE_TTRX_2968_TTRX_3162, + HW_ISSUE_END }; diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index 0b6cd8fdcb47..accb4fa3adb8 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -195,6 +195,7 @@ #define SC_TLS_HASH_ENABLE BIT(17) #define SC_LS_ATTR_CHECK_DISABLE BIT(18) #define SC_ENABLE_TEXGRD_FLAGS BIT(25) +#define SC_VAR_ALGORITHM BIT(29) /* End SHADER_CONFIG register */ /* TILER_CONFIG register */ From a17775a1af59573b1023e4ff2419ba48f4b6f648 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:48 -0400 Subject: [PATCH 125/170] drm/panfrost: Constify argument to has_hw_issue Logically, this function is free of side effects, so any pointers it takes should be const. Needed to avoid a warning in the next patch. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-4-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_issues.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h index 41a714ce6fce..14670ee58ace 100644 --- a/drivers/gpu/drm/panfrost/panfrost_issues.h +++ b/drivers/gpu/drm/panfrost/panfrost_issues.h @@ -251,7 +251,7 @@ enum panfrost_hw_issue { #define hw_issues_g76 0 -static inline bool panfrost_has_hw_issue(struct panfrost_device *pfdev, +static inline bool panfrost_has_hw_issue(const struct panfrost_device *pfdev, enum panfrost_hw_issue issue) { return test_bit(issue, pfdev->features.hw_issues); From 0c0af438345ebe5477720f07216c7e48f6f88756 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:49 -0400 Subject: [PATCH 126/170] drm/panfrost: Handle HW_ISSUE_TTRX_3076 Some Valhall GPUs require resets when encountering bus faults due to occlusion query writes. Add the issue bit for this and handle it. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-5-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_device.c | 9 +++++++-- drivers/gpu/drm/panfrost/panfrost_issues.h | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index 7f51a4682ccb..ee612303f076 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -11,6 +11,7 @@ #include "panfrost_device.h" #include "panfrost_devfreq.h" #include "panfrost_features.h" +#include "panfrost_issues.h" #include "panfrost_gpu.h" #include "panfrost_job.h" #include "panfrost_mmu.h" @@ -380,9 +381,13 @@ const char *panfrost_exception_name(u32 exception_code) bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev, u32 exception_code) { - /* Right now, none of the GPU we support need a reset, but this - * might change. + /* If an occlusion query write causes a bus fault on affected GPUs, + * future fragment jobs may hang. Reset to workaround. */ + if (exception_code == DRM_PANFROST_EXCEPTION_JOB_BUS_FAULT) + return panfrost_has_hw_issue(pfdev, HW_ISSUE_TTRX_3076); + + /* No other GPUs we support need a reset */ return false; } diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h index 14670ee58ace..e35807e4b743 100644 --- a/drivers/gpu/drm/panfrost/panfrost_issues.h +++ b/drivers/gpu/drm/panfrost/panfrost_issues.h @@ -128,6 +128,10 @@ enum panfrost_hw_issue { /* Must set SC_VAR_ALGORITHM */ HW_ISSUE_TTRX_2968_TTRX_3162, + /* Bus fault from occlusion query write may cause future fragment jobs + * to hang */ + HW_ISSUE_TTRX_3076, + HW_ISSUE_END }; From 892e7fb7c254008c195431ae559b2b4f7909c95f Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:50 -0400 Subject: [PATCH 127/170] drm/panfrost: Add HW_ISSUE_TTRX_3485 quirk TTRX_3485 requires the infamous "dummy job" workaround. I have this workaround implemented in a local branch, but I have not yet hit a case that requires it so I cannot test whether the implementation is correct. In the mean time, add the quirk bit so we can document which platforms may need it in the future. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-6-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_issues.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h index e35807e4b743..4d41e0a13867 100644 --- a/drivers/gpu/drm/panfrost/panfrost_issues.h +++ b/drivers/gpu/drm/panfrost/panfrost_issues.h @@ -132,6 +132,9 @@ enum panfrost_hw_issue { * to hang */ HW_ISSUE_TTRX_3076, + /* Must issue a dummy job before starting real work to prevent hangs */ + HW_ISSUE_TTRX_3485, + HW_ISSUE_END }; From 5b9afc161ea595c82707f5f9d67c96a00a8bcbae Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:51 -0400 Subject: [PATCH 128/170] drm/panfrost: Add "clean only safe" feature bit Add the HW_FEATURE_CLEAN_ONLY_SAFE bit based on kbase. When I actually tried to port the logic from kbase, trivial jobs raised Data Invalid Faults, so this may depend on other coherency details. It's still useful to have the bit to record the feature bit when adding new models. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-7-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_features.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_features.h b/drivers/gpu/drm/panfrost/panfrost_features.h index 36fadcf9634e..1a8bdebc86a3 100644 --- a/drivers/gpu/drm/panfrost/panfrost_features.h +++ b/drivers/gpu/drm/panfrost/panfrost_features.h @@ -21,6 +21,7 @@ enum panfrost_hw_feature { HW_FEATURE_TLS_HASHING, HW_FEATURE_THREAD_GROUP_SPLIT, HW_FEATURE_IDVS_GROUP_SIZE, + HW_FEATURE_CLEAN_ONLY_SAFE, HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG, }; From d8e53d8a4e0ae842ef5e83e0dfb0796980f710cf Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:52 -0400 Subject: [PATCH 129/170] drm/panfrost: Don't set L2_MMU_CONFIG quirks L2_MMU_CONFIG is an implementation-defined register. Different Mali GPUs define slightly different MAX_READS and MAX_WRITES fields, which throttle outstanding reads and writes when set to non-zero values. When left as zero, reads and writes are not throttled. Both kbase and panfrost always zero these registers. Per discussion with Steven Price, there are two reasons these quirks may be used: 1. Simulating slower memory subsystems. This use case is only of interest to system-on-chip designers; it is not relevant to mainline. 2. Working around broken memory subsystems. Hopefully we never see this case in mainline. If we do, we'll need to set this register based on an SoC-compatible, rather than generally matching on the GPU model. To the best of our knowledge, these fields are zero at reset, so the write is not necessary. Let's remove the write to aid porting to new Mali GPUs, which have different layouts for the L2_MMU_CONFIG register. Suggested-by: Steven Price Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-8-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gpu.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 295bef27fb55..e1a6e763d0dc 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -127,18 +127,6 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_TILER_CONFIG, quirks); - quirks = gpu_read(pfdev, GPU_L2_MMU_CONFIG); - - /* Limit read & write ID width for AXI */ - if (panfrost_has_hw_feature(pfdev, HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) - quirks &= ~(L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS | - L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES); - else - quirks &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_READS | - L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES); - - gpu_write(pfdev, GPU_L2_MMU_CONFIG, quirks); - quirks = 0; if ((panfrost_model_eq(pfdev, 0x860) || panfrost_model_eq(pfdev, 0x880)) && pfdev->features.revision >= 0x2000) From 5ba99fca1de0272ce05b65f19bcc184b5cb43285 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:53 -0400 Subject: [PATCH 130/170] drm/panfrost: Add Mali-G57 "Natt" support Add the features, issues, and GPU ID for Mali-G57, a first-generation Valhall GPU. Other first- and second-generation Valhall GPUs should be similar. v2: Split out issue list for r0p0 from newer Natt GPUs, as TTRX_3485 was fixed in r0p1. Unfortunately, MT8192 has a r0p0, so we do need to handle TTRX_3485. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-9-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_features.h | 12 ++++++++++++ drivers/gpu/drm/panfrost/panfrost_gpu.c | 3 +++ drivers/gpu/drm/panfrost/panfrost_issues.h | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_features.h b/drivers/gpu/drm/panfrost/panfrost_features.h index 1a8bdebc86a3..7ed0cd3ea2d4 100644 --- a/drivers/gpu/drm/panfrost/panfrost_features.h +++ b/drivers/gpu/drm/panfrost/panfrost_features.h @@ -106,6 +106,18 @@ enum panfrost_hw_feature { BIT_ULL(HW_FEATURE_TLS_HASHING) | \ BIT_ULL(HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) +#define hw_features_g57 (\ + BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ + BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ + BIT_ULL(HW_FEATURE_XAFFINITY) | \ + BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ + BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ + BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ + BIT_ULL(HW_FEATURE_COHERENCY_REG) | \ + BIT_ULL(HW_FEATURE_AARCH64_MMU) | \ + BIT_ULL(HW_FEATURE_IDVS_GROUP_SIZE) | \ + BIT_ULL(HW_FEATURE_CLEAN_ONLY_SAFE)) + static inline bool panfrost_has_hw_feature(struct panfrost_device *pfdev, enum panfrost_hw_feature feat) { diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index e1a6e763d0dc..6452e4e900dd 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -201,6 +201,9 @@ static const struct panfrost_model gpu_models[] = { GPU_MODEL(g52, 0x7002), GPU_MODEL(g31, 0x7003, GPU_REV(g31, 1, 0)), + + GPU_MODEL(g57, 0x9001, + GPU_REV(g57, 0, 0)), }; static void panfrost_gpu_init_features(struct panfrost_device *pfdev) diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h index 4d41e0a13867..eb60cb83667a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_issues.h +++ b/drivers/gpu/drm/panfrost/panfrost_issues.h @@ -258,6 +258,13 @@ enum panfrost_hw_issue { #define hw_issues_g76 0 +#define hw_issues_g57 (\ + BIT_ULL(HW_ISSUE_TTRX_2968_TTRX_3162) | \ + BIT_ULL(HW_ISSUE_TTRX_3076)) + +#define hw_issues_g57_r0p0 (\ + BIT_ULL(HW_ISSUE_TTRX_3485)) + static inline bool panfrost_has_hw_issue(const struct panfrost_device *pfdev, enum panfrost_hw_issue issue) { From 952cd974509251d6b5074bc3677b8297826a6ef1 Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Wed, 25 May 2022 10:57:54 -0400 Subject: [PATCH 131/170] drm/panfrost: Add arm,mali-valhall-jm compatible The most important Valhall-specific quirks have been handled, so add the Valhall compatible and probe. v2: Use arm,mali-valhall-jm compatible. Reviewed-by: Steven Price Signed-off-by: Alyssa Rosenzweig Link: https://patchwork.freedesktop.org/patch/msgid/20220525145754.25866-10-alyssa.rosenzweig@collabora.com --- drivers/gpu/drm/panfrost/panfrost_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 7fcbc2a5b6cd..b48b6f2af029 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -664,6 +664,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "arm,mali-t860", .data = &default_data, }, { .compatible = "arm,mali-t880", .data = &default_data, }, { .compatible = "arm,mali-bifrost", .data = &default_data, }, + { .compatible = "arm,mali-valhall-jm", .data = &default_data, }, { .compatible = "mediatek,mt8183-mali", .data = &mediatek_mt8183_data }, {} }; From ade1fc91eb99614c7155fec762ad5761bb470e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 10 May 2022 13:42:41 +0300 Subject: [PATCH 132/170] drm/edid: Extract drm_edid_decode_mfg_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the PNPID decoding available for other users. Cc: dri-devel@lists.freedesktop.org Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-15-ville.syrjala@linux.intel.com --- include/drm/drm_edid.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c61e75ab8f63..1d5950b5b407 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -497,6 +497,22 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; } +/** + * drm_edid_decode_mfg_id - Decode the manufacturer ID + * @mfg_id: The manufacturer ID + * @vend: A 4-byte buffer to store the 3-letter vendor string plus a '\0' + * termination + */ +static inline const char *drm_edid_decode_mfg_id(u16 mfg_id, char vend[4]) +{ + vend[0] = '@' + ((mfg_id >> 10) & 0x1f); + vend[1] = '@' + ((mfg_id >> 5) & 0x1f); + vend[2] = '@' + ((mfg_id >> 0) & 0x1f); + vend[3] = '\0'; + + return vend; +} + /** * drm_edid_encode_panel_id - Encode an ID for matching against drm_edid_get_panel_id() * @vend_chr_0: First character of the vendor string. @@ -537,10 +553,7 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) static inline void drm_edid_decode_panel_id(u32 panel_id, char vend[4], u16 *product_id) { *product_id = (u16)(panel_id & 0xffff); - vend[0] = '@' + ((panel_id >> 26) & 0x1f); - vend[1] = '@' + ((panel_id >> 21) & 0x1f); - vend[2] = '@' + ((panel_id >> 16) & 0x1f); - vend[3] = '\0'; + drm_edid_decode_mfg_id(panel_id >> 16, vend); } bool drm_probe_ddc(struct i2c_adapter *adapter); From 14374e3eee1b02dbf162e1dd75b789373f07ef43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 11 May 2022 17:40:38 +0200 Subject: [PATCH 133/170] dma-buf: cleanup dma_fence_chain_walk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use unrcu_pointer() instead of the manual cast. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518085446.31338-1-christian.koenig@amd.com --- drivers/dma-buf/dma-fence-chain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index 06f8ef97c6e8..a0d920576ba6 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -62,8 +62,8 @@ struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence) replacement = NULL; } - tmp = cmpxchg((struct dma_fence __force **)&chain->prev, - prev, replacement); + tmp = unrcu_pointer(cmpxchg(&chain->prev, RCU_INITIALIZER(prev), + RCU_INITIALIZER(replacement))); if (tmp == prev) dma_fence_put(tmp); else From 435c249008cba04ed6a7975e9411f3b934620204 Mon Sep 17 00:00:00 2001 From: Yunhao Tian Date: Tue, 10 May 2022 11:02:19 +0800 Subject: [PATCH 134/170] drm/mipi-dbi: align max_chunk to 2 in spi_transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In __spi_validate, there's a validation that no partial transfers are accepted (xfer->len % w_size must be zero). When max_chunk is not a multiple of bpw (e.g. max_chunk = 65535, bpw = 16), the transfer will be rejected. This patch aligns max_chunk to 2 bytes (the maximum value of bpw is 16), so that no partial transfer will occur. Fixes: d23d4d4dac01 ("drm/tinydrm: Move tinydrm_spi_transfer()") Signed-off-by: Yunhao Tian Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/20220510030219.2486687-1-t123yh.xyz@gmail.com --- drivers/gpu/drm/drm_mipi_dbi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 9314f2ead79f..09e4edb5a992 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -1199,6 +1199,13 @@ int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz, size_t chunk; int ret; + /* In __spi_validate, there's a validation that no partial transfers + * are accepted (xfer->len % w_size must be zero). + * Here we align max_chunk to multiple of 2 (16bits), + * to prevent transfers from being rejected. + */ + max_chunk = ALIGN_DOWN(max_chunk, 2); + spi_message_init_with_transfers(&m, &tr, 1); while (len) { From 0c5064fa8d5a02dc2dcc6c674a0ad1bbaf79efda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 4 May 2022 12:28:31 +0200 Subject: [PATCH 135/170] dma-buf: cleanup dma_fence_unwrap selftest v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The selftests, fix the error handling, remove unused functions and stop leaking memory in failed tests. v2: fix the memory leak correctly. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-2-christian.koenig@amd.com --- drivers/dma-buf/st-dma-fence-unwrap.c | 48 +++++++++++---------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index 039f016b57be..e20c5a7dcfe4 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -4,27 +4,19 @@ * Copyright (C) 2022 Advanced Micro Devices, Inc. */ +#include +#include +#include #include -#if 0 -#include -#include -#include -#include -#include -#include -#include -#endif #include "selftest.h" #define CHAIN_SZ (4 << 10) -static inline struct mock_fence { +struct mock_fence { struct dma_fence base; spinlock_t lock; -} *to_mock_fence(struct dma_fence *f) { - return container_of(f, struct mock_fence, base); -} +}; static const char *mock_name(struct dma_fence *f) { @@ -45,7 +37,8 @@ static struct dma_fence *mock_fence(void) return NULL; spin_lock_init(&f->lock); - dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); + dma_fence_init(&f->base, &mock_ops, &f->lock, + dma_fence_context_alloc(1), 1); return &f->base; } @@ -59,7 +52,7 @@ static struct dma_fence *mock_array(unsigned int num_fences, ...) fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); if (!fences) - return NULL; + goto error_put; va_start(valist, num_fences); for (i = 0; i < num_fences; ++i) @@ -70,13 +63,17 @@ static struct dma_fence *mock_array(unsigned int num_fences, ...) dma_fence_context_alloc(1), 1, false); if (!array) - goto cleanup; + goto error_free; return &array->base; -cleanup: - for (i = 0; i < num_fences; ++i) - dma_fence_put(fences[i]); +error_free: kfree(fences); + +error_put: + va_start(valist, num_fences); + for (i = 0; i < num_fences; ++i) + dma_fence_put(va_arg(valist, typeof(*fences))); + va_end(valist); return NULL; } @@ -113,7 +110,6 @@ static int sanitycheck(void *arg) if (!chain) return -ENOMEM; - dma_fence_signal(f); dma_fence_put(chain); return err; } @@ -154,10 +150,8 @@ static int unwrap_array(void *arg) err = -EINVAL; } - dma_fence_signal(f1); - dma_fence_signal(f2); dma_fence_put(array); - return 0; + return err; } static int unwrap_chain(void *arg) @@ -196,10 +190,8 @@ static int unwrap_chain(void *arg) err = -EINVAL; } - dma_fence_signal(f1); - dma_fence_signal(f2); dma_fence_put(chain); - return 0; + return err; } static int unwrap_chain_array(void *arg) @@ -242,10 +234,8 @@ static int unwrap_chain_array(void *arg) err = -EINVAL; } - dma_fence_signal(f1); - dma_fence_signal(f2); dma_fence_put(chain); - return 0; + return err; } int dma_fence_unwrap(void) From 01357a5a45ed8eb9543183f5c9c6713ae60fc1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 24 Apr 2022 16:55:14 +0200 Subject: [PATCH 136/170] dma-buf: cleanup dma_fence_unwrap implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the code from the inline functions into exported functions. Signed-off-by: Christian König Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-3-christian.koenig@amd.com --- drivers/dma-buf/Makefile | 2 +- drivers/dma-buf/dma-fence-unwrap.c | 59 ++++++++++++++++++++++++++++++ include/linux/dma-fence-unwrap.h | 52 ++------------------------ 3 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 drivers/dma-buf/dma-fence-unwrap.c diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 4c9eb53ba3f8..70ec901edf2c 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ - dma-resv.o + dma-fence-unwrap.o dma-resv.o obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o obj-$(CONFIG_DMABUF_HEAPS) += heaps/ obj-$(CONFIG_SYNC_FILE) += sync_file.o diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c new file mode 100644 index 000000000000..711be125428c --- /dev/null +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dma-fence-util: misc functions for dma_fence objects + * + * Copyright (C) 2022 Advanced Micro Devices, Inc. + * Authors: + * Christian König + */ + +#include +#include +#include +#include + +/* Internal helper to start new array iteration, don't use directly */ +static struct dma_fence * +__dma_fence_unwrap_array(struct dma_fence_unwrap *cursor) +{ + cursor->array = dma_fence_chain_contained(cursor->chain); + cursor->index = 0; + return dma_fence_array_first(cursor->array); +} + +/** + * dma_fence_unwrap_first - return the first fence from fence containers + * @head: the entrypoint into the containers + * @cursor: current position inside the containers + * + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the + * first fence. + */ +struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head, + struct dma_fence_unwrap *cursor) +{ + cursor->chain = dma_fence_get(head); + return __dma_fence_unwrap_array(cursor); +} +EXPORT_SYMBOL_GPL(dma_fence_unwrap_first); + +/** + * dma_fence_unwrap_next - return the next fence from a fence containers + * @cursor: current position inside the containers + * + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return + * the next fence from them. + */ +struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) +{ + struct dma_fence *tmp; + + ++cursor->index; + tmp = dma_fence_array_next(cursor->array, cursor->index); + if (tmp) + return tmp; + + cursor->chain = dma_fence_chain_walk(cursor->chain); + return __dma_fence_unwrap_array(cursor); +} +EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index 77e335a1bcac..e7c219da4ed7 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * fence-chain: chain fences together in a timeline - * * Copyright (C) 2022 Advanced Micro Devices, Inc. * Authors: * Christian König @@ -10,8 +8,7 @@ #ifndef __LINUX_DMA_FENCE_UNWRAP_H #define __LINUX_DMA_FENCE_UNWRAP_H -#include -#include +struct dma_fence; /** * struct dma_fence_unwrap - cursor into the container structure @@ -33,50 +30,9 @@ struct dma_fence_unwrap { unsigned int index; }; -/* Internal helper to start new array iteration, don't use directly */ -static inline struct dma_fence * -__dma_fence_unwrap_array(struct dma_fence_unwrap * cursor) -{ - cursor->array = dma_fence_chain_contained(cursor->chain); - cursor->index = 0; - return dma_fence_array_first(cursor->array); -} - -/** - * dma_fence_unwrap_first - return the first fence from fence containers - * @head: the entrypoint into the containers - * @cursor: current position inside the containers - * - * Unwraps potential dma_fence_chain/dma_fence_array containers and return the - * first fence. - */ -static inline struct dma_fence * -dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor) -{ - cursor->chain = dma_fence_get(head); - return __dma_fence_unwrap_array(cursor); -} - -/** - * dma_fence_unwrap_next - return the next fence from a fence containers - * @cursor: current position inside the containers - * - * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return - * the next fence from them. - */ -static inline struct dma_fence * -dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) -{ - struct dma_fence *tmp; - - ++cursor->index; - tmp = dma_fence_array_next(cursor->array, cursor->index); - if (tmp) - return tmp; - - cursor->chain = dma_fence_chain_walk(cursor->chain); - return __dma_fence_unwrap_array(cursor); -} +struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head, + struct dma_fence_unwrap *cursor); +struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); /** * dma_fence_unwrap_for_each - iterate over all fences in containers From 8f61973718485f3e89bc4f408f929048b7b47c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 4 May 2022 13:01:29 +0200 Subject: [PATCH 137/170] dma-buf: return only unsignaled fences in dma_fence_unwrap_for_each v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dma_fence_chain containers cleanup signaled fences automatically, so filter those out from arrays as well. v2: fix missing walk over the array v3: massively simplify the patch and actually update the description. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-4-christian.koenig@amd.com --- include/linux/dma-fence-unwrap.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index e7c219da4ed7..a4d342fef8e0 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -43,9 +43,13 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all * potential fences in them. If @head is just a normal fence only that one is * returned. + * + * Note that signalled fences are opportunistically filtered out, which + * means the iteration is potentially over no fence at all. */ #define dma_fence_unwrap_for_each(fence, cursor, head) \ for (fence = dma_fence_unwrap_first(head, cursor); fence; \ - fence = dma_fence_unwrap_next(cursor)) + fence = dma_fence_unwrap_next(cursor)) \ + if (!dma_fence_is_signaled(fence)) #endif From 245a4a7b531cffb41233a716497c25b06835cf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 25 Apr 2022 14:22:12 +0200 Subject: [PATCH 138/170] dma-buf: generalize dma_fence unwrap & merging v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a dma_fence_unwrap_merge() macro which allows to unwrap fences which potentially can be containers as well and then merge them back together into a flat dma_fence_array. v2: rename the function, add some more comments about how the wrapper is used, move filtering of signaled fences into the unwrap iterator, add complex selftest which covers more cases. v3: fix signaled fence filtering once more Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-5-christian.koenig@amd.com --- drivers/dma-buf/dma-fence-unwrap.c | 103 ++++++++++++++++++++++ drivers/dma-buf/st-dma-fence-unwrap.c | 109 +++++++++++++++++++++++ drivers/dma-buf/sync_file.c | 119 ++------------------------ include/linux/dma-fence-unwrap.h | 24 ++++++ 4 files changed, 242 insertions(+), 113 deletions(-) diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 711be125428c..502a65ea6d44 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Internal helper to start new array iteration, don't use directly */ static struct dma_fence * @@ -57,3 +58,105 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) return __dma_fence_unwrap_array(cursor); } EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); + +/* Implementation for the dma_fence_merge() marco, don't use directly */ +struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, + struct dma_fence **fences, + struct dma_fence_unwrap *iter) +{ + struct dma_fence_array *result; + struct dma_fence *tmp, **array; + unsigned int i; + size_t count; + + count = 0; + for (i = 0; i < num_fences; ++i) { + dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) + ++count; + } + + if (count == 0) + return dma_fence_get_stub(); + + array = kmalloc_array(count, sizeof(*array), GFP_KERNEL); + if (!array) + return NULL; + + /* + * This trashes the input fence array and uses it as position for the + * following merge loop. This works because the dma_fence_merge() + * wrapper macro is creating this temporary array on the stack together + * with the iterators. + */ + for (i = 0; i < num_fences; ++i) + fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]); + + count = 0; + do { + unsigned int sel; + +restart: + tmp = NULL; + for (i = 0; i < num_fences; ++i) { + struct dma_fence *next; + + while (fences[i] && dma_fence_is_signaled(fences[i])) + fences[i] = dma_fence_unwrap_next(&iter[i]); + + next = fences[i]; + if (!next) + continue; + + /* + * We can't guarantee that inpute fences are ordered by + * context, but it is still quite likely when this + * function is used multiple times. So attempt to order + * the fences by context as we pass over them and merge + * fences with the same context. + */ + if (!tmp || tmp->context > next->context) { + tmp = next; + sel = i; + + } else if (tmp->context < next->context) { + continue; + + } else if (dma_fence_is_later(tmp, next)) { + fences[i] = dma_fence_unwrap_next(&iter[i]); + goto restart; + } else { + fences[sel] = dma_fence_unwrap_next(&iter[sel]); + goto restart; + } + } + + if (tmp) { + array[count++] = dma_fence_get(tmp); + fences[sel] = dma_fence_unwrap_next(&iter[sel]); + } + } while (tmp); + + if (count == 0) { + tmp = dma_fence_get_stub(); + goto return_tmp; + } + + if (count == 1) { + tmp = array[0]; + goto return_tmp; + } + + result = dma_fence_array_create(count, array, + dma_fence_context_alloc(1), + 1, false); + if (!result) { + tmp = NULL; + goto return_tmp; + } + return &result->base; + +return_tmp: + kfree(array); + return tmp; +} +EXPORT_SYMBOL_GPL(__dma_fence_unwrap_merge); diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index e20c5a7dcfe4..4105d5ea8dde 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -238,6 +238,113 @@ static int unwrap_chain_array(void *arg) return err; } +static int unwrap_merge(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *f3; + struct dma_fence_unwrap iter; + int err = 0; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) { + err = -ENOMEM; + goto error_put_f1; + } + + f3 = dma_fence_unwrap_merge(f1, f2); + if (!f3) { + err = -ENOMEM; + goto error_put_f2; + } + + dma_fence_unwrap_for_each(fence, &iter, f3) { + if (fence == f1) { + dma_fence_put(f1); + f1 = NULL; + } else if (fence == f2) { + dma_fence_put(f2); + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_put(f3); +error_put_f2: + dma_fence_put(f2); +error_put_f1: + dma_fence_put(f1); + return err; +} + +static int unwrap_merge_complex(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5; + struct dma_fence_unwrap iter; + int err = -ENOMEM; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) + goto error_put_f1; + + f3 = dma_fence_unwrap_merge(f1, f2); + if (!f3) + goto error_put_f2; + + /* The resulting array has the fences in reverse */ + f4 = dma_fence_unwrap_merge(f2, f1); + if (!f4) + goto error_put_f3; + + /* Signaled fences should be filtered, the two arrays merged. */ + f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub()); + if (!f5) + goto error_put_f4; + + err = 0; + dma_fence_unwrap_for_each(fence, &iter, f5) { + if (fence == f1) { + dma_fence_put(f1); + f1 = NULL; + } else if (fence == f2) { + dma_fence_put(f2); + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_put(f5); +error_put_f4: + dma_fence_put(f4); +error_put_f3: + dma_fence_put(f3); +error_put_f2: + dma_fence_put(f2); +error_put_f1: + dma_fence_put(f1); + return err; +} + int dma_fence_unwrap(void) { static const struct subtest tests[] = { @@ -245,6 +352,8 @@ int dma_fence_unwrap(void) SUBTEST(unwrap_array), SUBTEST(unwrap_chain), SUBTEST(unwrap_chain_array), + SUBTEST(unwrap_merge), + SUBTEST(unwrap_merge_complex), }; return subtests(tests, NULL); diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 0fe564539166..3ebec19a8e02 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -146,50 +146,6 @@ char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len) return buf; } -static int sync_file_set_fence(struct sync_file *sync_file, - struct dma_fence **fences, int num_fences) -{ - struct dma_fence_array *array; - - /* - * The reference for the fences in the new sync_file and held - * in add_fence() during the merge procedure, so for num_fences == 1 - * we already own a new reference to the fence. For num_fence > 1 - * we own the reference of the dma_fence_array creation. - */ - - if (num_fences == 0) { - sync_file->fence = dma_fence_get_stub(); - kfree(fences); - - } else if (num_fences == 1) { - sync_file->fence = fences[0]; - kfree(fences); - - } else { - array = dma_fence_array_create(num_fences, fences, - dma_fence_context_alloc(1), - 1, false); - if (!array) - return -ENOMEM; - - sync_file->fence = &array->base; - } - - return 0; -} - -static void add_fence(struct dma_fence **fences, - int *i, struct dma_fence *fence) -{ - fences[*i] = fence; - - if (!dma_fence_is_signaled(fence)) { - dma_fence_get(fence); - (*i)++; - } -} - /** * sync_file_merge() - merge two sync_files * @name: name of new fence @@ -203,84 +159,21 @@ static void add_fence(struct dma_fence **fences, static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, struct sync_file *b) { - struct dma_fence *a_fence, *b_fence, **fences; - struct dma_fence_unwrap a_iter, b_iter; - unsigned int index, num_fences; struct sync_file *sync_file; + struct dma_fence *fence; sync_file = sync_file_alloc(); if (!sync_file) return NULL; - num_fences = 0; - dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence) - ++num_fences; - dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence) - ++num_fences; - - if (num_fences > INT_MAX) - goto err_free_sync_file; - - fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); - if (!fences) - goto err_free_sync_file; - - /* - * We can't guarantee that fences in both a and b are ordered, but it is - * still quite likely. - * - * So attempt to order the fences as we pass over them and merge fences - * with the same context. - */ - - index = 0; - for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter), - b_fence = dma_fence_unwrap_first(b->fence, &b_iter); - a_fence || b_fence; ) { - - if (!b_fence) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - - } else if (!a_fence) { - add_fence(fences, &index, b_fence); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else if (a_fence->context < b_fence->context) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - - } else if (b_fence->context < a_fence->context) { - add_fence(fences, &index, b_fence); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno, - a_fence->ops)) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else { - add_fence(fences, &index, b_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - b_fence = dma_fence_unwrap_next(&b_iter); - } + fence = dma_fence_unwrap_merge(a->fence, b->fence); + if (!fence) { + fput(sync_file->file); + return NULL; } - - if (sync_file_set_fence(sync_file, fences, index) < 0) - goto err_put_fences; - + sync_file->fence = fence; strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name)); return sync_file; - -err_put_fences: - while (index) - dma_fence_put(fences[--index]); - kfree(fences); - -err_free_sync_file: - fput(sync_file->file); - return NULL; } static int sync_file_release(struct inode *inode, struct file *file) diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index a4d342fef8e0..390de1ee9d35 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -52,4 +52,28 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); fence = dma_fence_unwrap_next(cursor)) \ if (!dma_fence_is_signaled(fence)) +struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, + struct dma_fence **fences, + struct dma_fence_unwrap *cursors); + +/** + * dma_fence_unwrap_merge - unwrap and merge fences + * + * All fences given as parameters are unwrapped and merged back together as flat + * dma_fence_array. Useful if multiple containers need to be merged together. + * + * Implemented as a macro to allocate the necessary arrays on the stack and + * account the stack frame size to the caller. + * + * Returns NULL on memory allocation failure, a dma_fence object representing + * all the given fences otherwise. + */ +#define dma_fence_unwrap_merge(...) \ + ({ \ + struct dma_fence *__f[] = { __VA_ARGS__ }; \ + struct dma_fence_unwrap __c[ARRAY_SIZE(__f)]; \ + \ + __dma_fence_unwrap_merge(ARRAY_SIZE(__f), __f, __c); \ + }) + #endif From ec8d985ff26f29d53d9ebff04973e96572fd0285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 4 May 2022 13:34:03 +0200 Subject: [PATCH 139/170] drm: use dma_fence_unwrap_merge() in drm_syncobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unwrap merge function is now intended for this use case. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-6-christian.koenig@amd.com --- drivers/gpu/drm/drm_syncobj.c | 57 +++++------------------------------ 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 7e48dcd1bee4..bbad9e4696e7 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -184,6 +184,7 @@ */ #include +#include #include #include #include @@ -853,57 +854,12 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data, &args->handle); } - -/* - * Try to flatten a dma_fence_chain into a dma_fence_array so that it can be - * added as timeline fence to a chain again. - */ -static int drm_syncobj_flatten_chain(struct dma_fence **f) -{ - struct dma_fence_chain *chain = to_dma_fence_chain(*f); - struct dma_fence *tmp, **fences; - struct dma_fence_array *array; - unsigned int count; - - if (!chain) - return 0; - - count = 0; - dma_fence_chain_for_each(tmp, &chain->base) - ++count; - - fences = kmalloc_array(count, sizeof(*fences), GFP_KERNEL); - if (!fences) - return -ENOMEM; - - count = 0; - dma_fence_chain_for_each(tmp, &chain->base) - fences[count++] = dma_fence_get(tmp); - - array = dma_fence_array_create(count, fences, - dma_fence_context_alloc(1), - 1, false); - if (!array) - goto free_fences; - - dma_fence_put(*f); - *f = &array->base; - return 0; - -free_fences: - while (count--) - dma_fence_put(fences[count]); - - kfree(fences); - return -ENOMEM; -} - static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, struct drm_syncobj_transfer *args) { struct drm_syncobj *timeline_syncobj = NULL; + struct dma_fence *fence, *tmp; struct dma_fence_chain *chain; - struct dma_fence *fence; int ret; timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle); @@ -912,13 +868,14 @@ static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private, } ret = drm_syncobj_find_fence(file_private, args->src_handle, args->src_point, args->flags, - &fence); + &tmp); if (ret) goto err_put_timeline; - ret = drm_syncobj_flatten_chain(&fence); - if (ret) - goto err_free_fence; + fence = dma_fence_unwrap_merge(tmp); + dma_fence_put(tmp); + if (!fence) + goto err_put_timeline; chain = dma_fence_chain_alloc(); if (!chain) { From a0ab5abced550ddeefddb06055ed60779a54eb79 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Sat, 21 May 2022 07:23:39 -0700 Subject: [PATCH 140/170] drm/hyperv : Removing the restruction of VRAM allocation with PCI bar size There were two different approaches getting used in this driver to allocate vram: 1. VRAM allocation from PCI region for Gen1 2. VRAM alloaction from MMIO region for Gen2 First approach limilts the vram to PCI BAR size, which is 64 MB in most legacy systems. This limits the maximum resolution to be restricted to 64 MB size, and with recent conclusion on fbdev issue its concluded to have similar allocation strategy for both Gen1 and Gen2. This patch unifies the Gen1 and Gen2 vram allocation strategy. Signed-off-by: Saurabh Sengar Reviewed-by: Deepak Rawat Signed-off-by: Deepak Rawat Link: https://patchwork.freedesktop.org/patch/msgid/1653143019-20032-1-git-send-email-ssengar@linux.microsoft.com --- drivers/gpu/drm/hyperv/hyperv_drm_drv.c | 74 +------------------------ 1 file changed, 3 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c index 4a8941fa0815..6d11e7938c83 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c @@ -69,56 +69,7 @@ static struct pci_driver hyperv_pci_driver = { .remove = hyperv_pci_remove, }; -static int hyperv_setup_gen1(struct hyperv_drm_device *hv) -{ - struct drm_device *dev = &hv->dev; - struct pci_dev *pdev; - int ret; - - pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, - PCI_DEVICE_ID_HYPERV_VIDEO, NULL); - if (!pdev) { - drm_err(dev, "Unable to find PCI Hyper-V video\n"); - return -ENODEV; - } - - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &hyperv_driver); - if (ret) { - drm_err(dev, "Not able to remove boot fb\n"); - return ret; - } - - if (pci_request_region(pdev, 0, DRIVER_NAME) != 0) - drm_warn(dev, "Cannot request framebuffer, boot fb still active?\n"); - - if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) { - drm_err(dev, "Resource at bar 0 is not IORESOURCE_MEM\n"); - ret = -ENODEV; - goto error; - } - - hv->fb_base = pci_resource_start(pdev, 0); - hv->fb_size = pci_resource_len(pdev, 0); - if (!hv->fb_base) { - drm_err(dev, "Resource not available\n"); - ret = -ENODEV; - goto error; - } - - hv->fb_size = min(hv->fb_size, - (unsigned long)(hv->mmio_megabytes * 1024 * 1024)); - hv->vram = devm_ioremap(&pdev->dev, hv->fb_base, hv->fb_size); - if (!hv->vram) { - drm_err(dev, "Failed to map vram\n"); - ret = -ENOMEM; - } - -error: - pci_dev_put(pdev); - return ret; -} - -static int hyperv_setup_gen2(struct hyperv_drm_device *hv, +static int hyperv_setup_vram(struct hyperv_drm_device *hv, struct hv_device *hdev) { struct drm_device *dev = &hv->dev; @@ -181,10 +132,7 @@ static int hyperv_vmbus_probe(struct hv_device *hdev, goto err_hv_set_drv_data; } - if (efi_enabled(EFI_BOOT)) - ret = hyperv_setup_gen2(hv, hdev); - else - ret = hyperv_setup_gen1(hv); + ret = hyperv_setup_vram(hv, hdev); if (ret) goto err_vmbus_close; @@ -225,29 +173,13 @@ static int hyperv_vmbus_remove(struct hv_device *hdev) { struct drm_device *dev = hv_get_drvdata(hdev); struct hyperv_drm_device *hv = to_hv(dev); - struct pci_dev *pdev; drm_dev_unplug(dev); drm_atomic_helper_shutdown(dev); vmbus_close(hdev->channel); hv_set_drvdata(hdev, NULL); - /* - * Free allocated MMIO memory only on Gen2 VMs. - * On Gen1 VMs, release the PCI device - */ - if (efi_enabled(EFI_BOOT)) { - vmbus_free_mmio(hv->mem->start, hv->fb_size); - } else { - pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, - PCI_DEVICE_ID_HYPERV_VIDEO, NULL); - if (!pdev) { - drm_err(dev, "Unable to find PCI Hyper-V video\n"); - return -ENODEV; - } - pci_release_region(pdev, 0); - pci_dev_put(pdev); - } + vmbus_free_mmio(hv->mem->start, hv->fb_size); return 0; } From a9bfcb56a2ef265092a4cfcd4b9c58ddff4d3649 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sat, 28 May 2022 10:18:36 -0400 Subject: [PATCH 141/170] drm/nouveau/fifo/gv100-: set gv100_fifo_runlist storage-class to static sparse reports drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c:56:1: warning: symbol 'gv100_fifo_runlist' was not declared. Should it be static? gv100_fifo_runlist is only used in gv100.c, so change it to static. Signed-off-by: Tom Rix Reviewed-by: Lyude Paul Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220528141836.4155970-1-trix@redhat.com --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c index 70e16a91ac12..faf0fe9f704c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c @@ -52,7 +52,7 @@ gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *cgrp, nvkm_wo32(memory, offset + 0xc, 0x00000000); } -const struct gk104_fifo_runlist_func +static const struct gk104_fifo_runlist_func gv100_fifo_runlist = { .size = 16, .cgrp = gv100_fifo_runlist_cgrp, From 01ece65132e2980ece4eca91105dfc9eed504881 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 30 May 2022 16:02:46 +0200 Subject: [PATCH 142/170] drm/ssd130x: Only define a SPI device ID table when built as a module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kernel test robot reports a compile warning due the ssd130x_spi_table variable being defined but not used. This happen when ssd130x-spi driver is built-in instead of being built as a module, i.e: CC drivers/gpu/drm/solomon/ssd130x-spi.o AR drivers/base/firmware_loader/built-in.a AR drivers/base/built-in.a CC kernel/trace/trace.o drivers/gpu/drm/solomon/ssd130x-spi.c:155:35: warning: ‘ssd130x_spi_table’ defined but not used [-Wunused-const-variable=] 155 | static const struct spi_device_id ssd130x_spi_table[] = { | ^~~~~~~~~~~~~~~~~ The driver shouldn't need a SPI device ID table and only have an OF device ID table, but the former is needed to workaround an issue in the SPI core. This always reports a MODALIAS of the form "spi:" even for devices registered through Device Trees. But the table is only needed when the driver built as a module to populate the .ko alias info. It's not needed when the driver is built-in the kernel. Fixes: 74373977d2ca ("drm/solomon: Add SSD130x OLED displays SPI support") Reported-by: kernel test robot Signed-off-by: Javier Martinez Canillas Reviewed-by: Nathan Chancellor Link: https://patchwork.freedesktop.org/patch/msgid/20220530140246.742469-1-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x-spi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 43722adab1f8..07802907e39a 100644 --- a/drivers/gpu/drm/solomon/ssd130x-spi.c +++ b/drivers/gpu/drm/solomon/ssd130x-spi.c @@ -143,6 +143,7 @@ static const struct of_device_id ssd130x_of_match[] = { }; MODULE_DEVICE_TABLE(of, ssd130x_of_match); +#if IS_MODULE(CONFIG_DRM_SSD130X_SPI) /* * The SPI core always reports a MODALIAS uevent of the form "spi:", even * if the device was registered via OF. This means that the module will not be @@ -160,6 +161,7 @@ static const struct spi_device_id ssd130x_spi_table[] = { { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, ssd130x_spi_table); +#endif static struct spi_driver ssd130x_spi_driver = { .driver = { From 04477e5e1e6ced4573d9bd5271572ba633a260ab Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:04 +0200 Subject: [PATCH 143/170] drm/gma500: Use gma_ prefix for our i2c abstraction psb_intel_i2c_chan is used by all chips so use the correct prefix. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-2-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_crt.c | 4 ++-- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 6 +++--- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 14 +++++--------- drivers/gpu/drm/gma500/intel_i2c.c | 22 +++++++++++----------- drivers/gpu/drm/gma500/oaktrail_lvds.c | 2 +- drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c | 12 ++++++------ drivers/gpu/drm/gma500/psb_drv.h | 2 +- drivers/gpu/drm/gma500/psb_intel_drv.h | 12 ++++++------ drivers/gpu/drm/gma500/psb_intel_lvds.c | 16 ++++++++-------- 9 files changed, 43 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 6bcd18c63c31..36c72a379d9f 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -194,7 +194,7 @@ static void cdv_intel_crt_destroy(struct drm_connector *connector) struct gma_connector *gma_connector = to_gma_connector(connector); struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - psb_intel_i2c_destroy(gma_encoder->ddc_bus); + gma_i2c_destroy(gma_encoder->ddc_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -267,7 +267,7 @@ void cdv_intel_crt_init(struct drm_device *dev, gma_connector_attach_encoder(gma_connector, gma_encoder); /* Set up the DDC bus. */ - gma_encoder->ddc_bus = psb_intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + gma_encoder->ddc_bus = gma_i2c_create(dev, GPIOA, "CRTDDC_A"); if (!gma_encoder->ddc_bus) { dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n"); goto failed_ddc; diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 8987e555e113..e87272c9d358 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -245,7 +245,7 @@ static void cdv_hdmi_destroy(struct drm_connector *connector) struct gma_connector *gma_connector = to_gma_connector(connector); struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - psb_intel_i2c_destroy(gma_encoder->i2c_bus); + gma_i2c_destroy(gma_encoder->i2c_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -342,8 +342,8 @@ void cdv_hdmi_init(struct drm_device *dev, break; } - gma_encoder->i2c_bus = psb_intel_i2c_create(dev, - ddc_bus, (reg == SDVOB) ? "HDMIB" : "HDMIC"); + gma_encoder->i2c_bus = gma_i2c_create(dev, ddc_bus, + (reg == SDVOB) ? "HDMIB" : "HDMIC"); if (!gma_encoder->i2c_bus) { dev_err(dev->dev, "No ddc adapter available!\n"); diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 98d9f5483a7c..02dedf5dfa62 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -329,7 +329,7 @@ static void cdv_intel_lvds_destroy(struct drm_connector *connector) struct gma_connector *gma_connector = to_gma_connector(connector); struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - psb_intel_i2c_destroy(gma_encoder->i2c_bus); + gma_i2c_destroy(gma_encoder->i2c_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -550,9 +550,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, * Set up I2C bus * FIXME: distroy i2c_bus when exit */ - gma_encoder->i2c_bus = psb_intel_i2c_create(dev, - GPIOB, - "LVDSBLC_B"); + gma_encoder->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); if (!gma_encoder->i2c_bus) { dev_printk(KERN_ERR, dev->dev, "I2C bus registration failed.\n"); @@ -572,9 +570,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, */ /* Set up the DDC bus. */ - gma_encoder->ddc_bus = psb_intel_i2c_create(dev, - GPIOC, - "LVDSDDC_C"); + gma_encoder->ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); if (!gma_encoder->ddc_bus) { dev_printk(KERN_ERR, dev->dev, "DDC bus registration " "failed.\n"); @@ -652,10 +648,10 @@ out: failed_find: mutex_unlock(&dev->mode_config.mutex); pr_err("Failed find\n"); - psb_intel_i2c_destroy(gma_encoder->ddc_bus); + gma_i2c_destroy(gma_encoder->ddc_bus); failed_ddc: pr_err("Failed DDC\n"); - psb_intel_i2c_destroy(gma_encoder->i2c_bus); + gma_i2c_destroy(gma_encoder->i2c_bus); failed_blc_i2c: pr_err("Failed BLC\n"); drm_encoder_cleanup(encoder); diff --git a/drivers/gpu/drm/gma500/intel_i2c.c b/drivers/gpu/drm/gma500/intel_i2c.c index 5e1b4d70c317..6e9e2061ff3b 100644 --- a/drivers/gpu/drm/gma500/intel_i2c.c +++ b/drivers/gpu/drm/gma500/intel_i2c.c @@ -22,7 +22,7 @@ static int get_clock(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 val; @@ -32,7 +32,7 @@ static int get_clock(void *data) static int get_data(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 val; @@ -42,7 +42,7 @@ static int get_data(void *data) static void set_clock(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 reserved = 0, clock_bits; @@ -62,7 +62,7 @@ static void set_clock(void *data, int state_high) static void set_data(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; struct drm_device *dev = chan->drm_dev; u32 reserved = 0, data_bits; @@ -83,7 +83,7 @@ static void set_data(void *data, int state_high) } /** - * psb_intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg + * gma_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg * @dev: DRM device * @reg: GPIO reg to use * @name: name for this bus @@ -102,12 +102,12 @@ static void set_data(void *data, int state_high) * %GPIOH * see PRM for details on how these different busses are used. */ -struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, - const u32 reg, const char *name) +struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, + const char *name) { - struct psb_intel_i2c_chan *chan; + struct gma_i2c_chan *chan; - chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL); + chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); if (!chan) goto out_free; @@ -143,12 +143,12 @@ out_free: } /** - * psb_intel_i2c_destroy - unregister and free i2c bus resources + * gma_i2c_destroy - unregister and free i2c bus resources * @chan: channel to free * * Unregister the adapter from the i2c layer, then free the structure. */ -void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan) +void gma_i2c_destroy(struct gma_i2c_chan *chan) { if (!chan) return; diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index aed5de8f8245..58b38e359098 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -408,7 +408,7 @@ failed_find: dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); if (gma_encoder->ddc_bus) { - psb_intel_i2c_destroy(gma_encoder->ddc_bus); + gma_i2c_destroy(gma_encoder->ddc_bus); gma_encoder->ddc_bus = NULL; } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c index d1ae91fcd224..9a6de6ff8b0c 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -65,7 +65,7 @@ static int get_clock(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; u32 val; val = LPC_READ_REG(chan, RGIO); @@ -79,7 +79,7 @@ static int get_clock(void *data) static int get_data(void *data) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; u32 val; val = LPC_READ_REG(chan, RGIO); @@ -93,7 +93,7 @@ static int get_data(void *data) static void set_clock(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; u32 val; if (state_high) { @@ -112,7 +112,7 @@ static void set_clock(void *data, int state_high) static void set_data(void *data, int state_high) { - struct psb_intel_i2c_chan *chan = data; + struct gma_i2c_chan *chan = data; u32 val; if (state_high) { @@ -134,9 +134,9 @@ void oaktrail_lvds_i2c_init(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct gma_encoder *gma_encoder = to_gma_encoder(encoder); struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct psb_intel_i2c_chan *chan; + struct gma_i2c_chan *chan; - chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL); + chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); if (!chan) return; diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 0ddfec1a0851..0ea3d23575f3 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -469,7 +469,7 @@ struct drm_psb_private { struct drm_display_mode *sdvo_lvds_vbt_mode; struct bdb_lvds_backlight *lvds_bl; /* LVDS backlight info from VBT */ - struct psb_intel_i2c_chan *lvds_i2c_bus; /* FIXME: Remove this? */ + struct gma_i2c_chan *lvds_i2c_bus; /* FIXME: Remove this? */ /* Feature bits from the VBIOS */ unsigned int int_tv_support:1; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index db3e757328fe..72585a3df25d 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -78,7 +78,7 @@ struct psb_intel_mode_device { uint32_t saveBLC_PWM_CTL; }; -struct psb_intel_i2c_chan { +struct gma_i2c_chan { /* for getting at dev. private (mmio etc.) */ struct drm_device *drm_dev; u32 reg; /* GPIO reg */ @@ -103,8 +103,8 @@ struct gma_encoder { /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's own set of output privates */ - struct psb_intel_i2c_chan *i2c_bus; - struct psb_intel_i2c_chan *ddc_bus; + struct gma_i2c_chan *i2c_bus; + struct gma_i2c_chan *ddc_bus; }; struct gma_connector { @@ -176,9 +176,9 @@ struct gma_crtc { #define to_psb_intel_framebuffer(x) \ container_of(x, struct psb_intel_framebuffer, base) -struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, - const u32 reg, const char *name); -void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan); +struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, + const char *name); +void gma_i2c_destroy(struct gma_i2c_chan *chan); int psb_intel_ddc_get_modes(struct drm_connector *connector, struct i2c_adapter *adapter); extern bool psb_intel_ddc_probe(struct i2c_adapter *adapter); diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index cad00380b386..07631891531a 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -49,8 +49,8 @@ struct psb_intel_lvds_priv { uint32_t savePFIT_PGM_RATIOS; uint32_t saveBLC_PWM_CTL; - struct psb_intel_i2c_chan *i2c_bus; - struct psb_intel_i2c_chan *ddc_bus; + struct gma_i2c_chan *i2c_bus; + struct gma_i2c_chan *ddc_bus; }; @@ -90,7 +90,7 @@ static int psb_lvds_i2c_set_brightness(struct drm_device *dev, { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; + struct gma_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; u8 out_buf[2]; unsigned int blc_i2c_brightness; @@ -525,7 +525,7 @@ void psb_intel_lvds_destroy(struct drm_connector *connector) struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv; - psb_intel_i2c_destroy(lvds_priv->ddc_bus); + gma_i2c_destroy(lvds_priv->ddc_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -695,7 +695,7 @@ void psb_intel_lvds_init(struct drm_device *dev, * Set up I2C bus * FIXME: distroy i2c_bus when exit */ - lvds_priv->i2c_bus = psb_intel_i2c_create(dev, GPIOB, "LVDSBLC_B"); + lvds_priv->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); if (!lvds_priv->i2c_bus) { dev_printk(KERN_ERR, dev->dev, "I2C bus registration failed.\n"); @@ -715,7 +715,7 @@ void psb_intel_lvds_init(struct drm_device *dev, */ /* Set up the DDC bus. */ - lvds_priv->ddc_bus = psb_intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + lvds_priv->ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); if (!lvds_priv->ddc_bus) { dev_printk(KERN_ERR, dev->dev, "DDC bus registration " "failed.\n"); @@ -786,9 +786,9 @@ out: failed_find: mutex_unlock(&dev->mode_config.mutex); - psb_intel_i2c_destroy(lvds_priv->ddc_bus); + gma_i2c_destroy(lvds_priv->ddc_bus); failed_ddc: - psb_intel_i2c_destroy(lvds_priv->i2c_bus); + gma_i2c_destroy(lvds_priv->i2c_bus); failed_blc_i2c: drm_encoder_cleanup(encoder); drm_connector_cleanup(connector); From ba1677f76b9a510d88efdc7a1416b2e778f125bc Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:05 +0200 Subject: [PATCH 144/170] drm/gma500: Make gma_i2c_chan a subclass of i2c_adapter This makes it easier to get at the full gma_i2c_chan when having an i2c_adapter from eg. drm_connector->ddc. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-3-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_crt.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 6 +++--- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 4 ++-- drivers/gpu/drm/gma500/intel_i2c.c | 14 +++++++------- drivers/gpu/drm/gma500/oaktrail_lvds.c | 2 +- drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c | 12 ++++++------ drivers/gpu/drm/gma500/psb_intel_drv.h | 11 +++++++---- drivers/gpu/drm/gma500/psb_intel_lvds.c | 6 +++--- 8 files changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 36c72a379d9f..be0d6a4591bf 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -203,7 +203,7 @@ static int cdv_intel_crt_get_modes(struct drm_connector *connector) { struct gma_encoder *gma_encoder = gma_attached_encoder(connector); return psb_intel_ddc_get_modes(connector, - &gma_encoder->ddc_bus->adapter); + &gma_encoder->ddc_bus->base); } static int cdv_intel_crt_set_property(struct drm_connector *connector, diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index e87272c9d358..bd6791522160 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -130,7 +130,7 @@ static enum drm_connector_status cdv_hdmi_detect( struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; - edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); + edid = drm_get_edid(connector, &gma_encoder->i2c_bus->base); hdmi_priv->has_hdmi_sink = false; hdmi_priv->has_hdmi_audio = false; @@ -212,7 +212,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) struct edid *edid = NULL; int ret = 0; - edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); + edid = drm_get_edid(connector, &gma_encoder->i2c_bus->base); if (edid) { drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); @@ -350,7 +350,7 @@ void cdv_hdmi_init(struct drm_device *dev, goto failed_ddc; } - hdmi_priv->hdmi_i2c_adapter = &(gma_encoder->i2c_bus->adapter); + hdmi_priv->hdmi_i2c_adapter = &gma_encoder->i2c_bus->base; hdmi_priv->dev = dev; return; diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 02dedf5dfa62..d76c3ecc951c 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -302,7 +302,7 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int ret; - ret = psb_intel_ddc_get_modes(connector, &gma_encoder->i2c_bus->adapter); + ret = psb_intel_ddc_get_modes(connector, &gma_encoder->i2c_bus->base); if (ret) return ret; @@ -583,7 +583,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, */ mutex_lock(&dev->mode_config.mutex); psb_intel_ddc_get_modes(connector, - &gma_encoder->ddc_bus->adapter); + &gma_encoder->ddc_bus->base); list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = diff --git a/drivers/gpu/drm/gma500/intel_i2c.c b/drivers/gpu/drm/gma500/intel_i2c.c index 6e9e2061ff3b..9d02a7b6d9a3 100644 --- a/drivers/gpu/drm/gma500/intel_i2c.c +++ b/drivers/gpu/drm/gma500/intel_i2c.c @@ -113,10 +113,10 @@ struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, chan->drm_dev = dev; chan->reg = reg; - snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); - chan->adapter.owner = THIS_MODULE; - chan->adapter.algo_data = &chan->algo; - chan->adapter.dev.parent = dev->dev; + snprintf(chan->base.name, I2C_NAME_SIZE, "intel drm %s", name); + chan->base.owner = THIS_MODULE; + chan->base.algo_data = &chan->algo; + chan->base.dev.parent = dev->dev; chan->algo.setsda = set_data; chan->algo.setscl = set_clock; chan->algo.getsda = get_data; @@ -125,9 +125,9 @@ struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; - i2c_set_adapdata(&chan->adapter, chan); + i2c_set_adapdata(&chan->base, chan); - if (i2c_bit_add_bus(&chan->adapter)) + if (i2c_bit_add_bus(&chan->base)) goto out_free; /* JJJ: raise SCL and SDA? */ @@ -153,6 +153,6 @@ void gma_i2c_destroy(struct gma_i2c_chan *chan) if (!chan) return; - i2c_del_adapter(&chan->adapter); + i2c_del_adapter(&chan->base); kfree(chan); } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 58b38e359098..8609f6249c4c 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -359,7 +359,7 @@ void oaktrail_lvds_init(struct drm_device *dev, if (edid == NULL && dev_priv->lpc_gpio_base) { oaktrail_lvds_i2c_init(encoder); if (gma_encoder->ddc_bus != NULL) { - i2c_adap = &gma_encoder->ddc_bus->adapter; + i2c_adap = &gma_encoder->ddc_bus->base; edid = drm_get_edid(connector, i2c_adap); } } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c index 9a6de6ff8b0c..ee163fb972d9 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -142,10 +142,10 @@ void oaktrail_lvds_i2c_init(struct drm_encoder *encoder) chan->drm_dev = dev; chan->reg = dev_priv->lpc_gpio_base; - strncpy(chan->adapter.name, "gma500 LPC", I2C_NAME_SIZE - 1); - chan->adapter.owner = THIS_MODULE; - chan->adapter.algo_data = &chan->algo; - chan->adapter.dev.parent = dev->dev; + strncpy(chan->base.name, "gma500 LPC", I2C_NAME_SIZE - 1); + chan->base.owner = THIS_MODULE; + chan->base.algo_data = &chan->algo; + chan->base.dev.parent = dev->dev; chan->algo.setsda = set_data; chan->algo.setscl = set_clock; chan->algo.getsda = get_data; @@ -154,13 +154,13 @@ void oaktrail_lvds_i2c_init(struct drm_encoder *encoder) chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; - i2c_set_adapdata(&chan->adapter, chan); + i2c_set_adapdata(&chan->base, chan); set_data(chan, 1); set_clock(chan, 1); udelay(50); - if (i2c_bit_add_bus(&chan->adapter)) { + if (i2c_bit_add_bus(&chan->base)) { kfree(chan); return; } diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 72585a3df25d..1c28288f36a0 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -79,12 +79,13 @@ struct psb_intel_mode_device { }; struct gma_i2c_chan { - /* for getting at dev. private (mmio etc.) */ - struct drm_device *drm_dev; - u32 reg; /* GPIO reg */ - struct i2c_adapter adapter; + struct i2c_adapter base; struct i2c_algo_bit_data algo; u8 slave_addr; + + /* for getting at dev. private (mmio etc.) */ + struct drm_device *drm_dev; + u32 reg; /* GPIO reg */ }; struct gma_encoder { @@ -175,6 +176,8 @@ struct gma_crtc { container_of(x, struct gma_encoder, base) #define to_psb_intel_framebuffer(x) \ container_of(x, struct psb_intel_framebuffer, base) +#define to_gma_i2c_chan(x) \ + container_of(x, struct gma_i2c_chan, base) struct gma_i2c_chan *gma_i2c_create(struct drm_device *dev, const u32 reg, const char *name); diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 07631891531a..c28fabdcfd73 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -113,7 +113,7 @@ static int psb_lvds_i2c_set_brightness(struct drm_device *dev, out_buf[0] = dev_priv->lvds_bl->brightnesscmd; out_buf[1] = (u8)blc_i2c_brightness; - if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) { + if (i2c_transfer(&lvds_i2c_bus->base, msgs, 1) == 1) { dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n", dev_priv->lvds_bl->brightnesscmd, blc_i2c_brightness); @@ -497,7 +497,7 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) int ret = 0; if (!IS_MRST(dev)) - ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->adapter); + ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->base); if (ret) return ret; @@ -727,7 +727,7 @@ void psb_intel_lvds_init(struct drm_device *dev, * preferred mode is the right one. */ mutex_lock(&dev->mode_config.mutex); - psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter); + psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->base); list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = From 368eb57a1676cef35f8303bc23f95d2ac35b7255 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:06 +0200 Subject: [PATCH 145/170] drm/gma500: Make cdv lvds use ddc adapter from drm_connector We're moving all uses of ddc_bus to drm_connector where they belong. Also, add missing call to destroy ddc bus when destroying the connector and cleanup the error handling in cdv_intel_lvds_init(). Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-4-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 67 ++++++++++++------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index d76c3ecc951c..846ce1546030 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -317,18 +317,12 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) return 0; } -/** - * cdv_intel_lvds_destroy - unregister and free LVDS structures - * @connector: connector to free - * - * Unregister the DDC bus for this connector then free the driver private - * structure. - */ static void cdv_intel_lvds_destroy(struct drm_connector *connector) { struct gma_connector *gma_connector = to_gma_connector(connector); struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); gma_i2c_destroy(gma_encoder->i2c_bus); drm_connector_cleanup(connector); kfree(gma_connector); @@ -487,8 +481,10 @@ void cdv_intel_lvds_init(struct drm_device *dev, struct drm_display_mode *scan; struct drm_crtc *crtc; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *ddc_bus; u32 lvds; int pipe; + int ret; u8 pin; if (!dev_priv->lvds_enabled_in_vbt) @@ -508,11 +504,11 @@ void cdv_intel_lvds_init(struct drm_device *dev, gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); if (!gma_connector) - goto failed_connector; + goto err_free_encoder; lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) - goto failed_lvds_priv; + goto err_free_connector; gma_encoder->dev_priv = lvds_priv; @@ -521,12 +517,24 @@ void cdv_intel_lvds_init(struct drm_device *dev, gma_connector->restore = cdv_intel_lvds_restore; encoder = &gma_encoder->base; + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, + "DDC bus registration " "failed.\n"); + goto err_free_lvds_priv; + } - drm_connector_init(dev, connector, - &cdv_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + &ddc_bus->base); + if (ret) + goto err_destroy_ddc; - drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; gma_connector_attach_encoder(gma_connector, gma_encoder); gma_encoder->type = INTEL_OUTPUT_LVDS; @@ -554,7 +562,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, if (!gma_encoder->i2c_bus) { dev_printk(KERN_ERR, dev->dev, "I2C bus registration failed.\n"); - goto failed_blc_i2c; + goto err_encoder_cleanup; } gma_encoder->i2c_bus->slave_addr = 0x2C; dev_priv->lvds_i2c_bus = gma_encoder->i2c_bus; @@ -569,21 +577,13 @@ void cdv_intel_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - gma_encoder->ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); - if (!gma_encoder->ddc_bus) { - dev_printk(KERN_ERR, dev->dev, - "DDC bus registration " "failed.\n"); - goto failed_ddc; - } - /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ mutex_lock(&dev->mode_config.mutex); - psb_intel_ddc_get_modes(connector, - &gma_encoder->ddc_bus->base); + psb_intel_ddc_get_modes(connector, &ddc_bus->base); + list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = @@ -625,7 +625,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, if (!mode_dev->panel_fixed_mode) { DRM_DEBUG ("Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } /* setup PWM */ @@ -645,20 +645,19 @@ out: mutex_unlock(&dev->mode_config.mutex); return; -failed_find: +err_unlock: mutex_unlock(&dev->mode_config.mutex); - pr_err("Failed find\n"); - gma_i2c_destroy(gma_encoder->ddc_bus); -failed_ddc: - pr_err("Failed DDC\n"); gma_i2c_destroy(gma_encoder->i2c_bus); -failed_blc_i2c: - pr_err("Failed BLC\n"); +err_encoder_cleanup: drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); +err_destroy_ddc: + gma_i2c_destroy(ddc_bus); +err_free_lvds_priv: kfree(lvds_priv); -failed_lvds_priv: +err_free_connector: kfree(gma_connector); -failed_connector: +err_free_encoder: kfree(gma_encoder); } From 544ef14031d0bc9223727fa8d39cd54f0fad7244 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:07 +0200 Subject: [PATCH 146/170] drm/gma500: Make cdv hdmi use ddc adapter from drm_connector We're moving all uses of ddc_bus from gma_encoder to drm_connector where they belong. Also, cleanup the error handling in cdv_hdmi_init() and remove unused i2c pointer in mid_intel_hdmi_priv. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-5-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 98 ++++++++++++------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index bd6791522160..29ef45f14169 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -53,7 +53,6 @@ struct mid_intel_hdmi_priv { bool has_hdmi_audio; /* Should set this when detect hotplug */ bool hdmi_device_connected; - struct i2c_adapter *hdmi_i2c_adapter; /* for control functions */ struct drm_device *dev; }; @@ -130,7 +129,7 @@ static enum drm_connector_status cdv_hdmi_detect( struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; - edid = drm_get_edid(connector, &gma_encoder->i2c_bus->base); + edid = drm_get_edid(connector, connector->ddc); hdmi_priv->has_hdmi_sink = false; hdmi_priv->has_hdmi_audio = false; @@ -208,11 +207,10 @@ static int cdv_hdmi_set_property(struct drm_connector *connector, */ static int cdv_hdmi_get_modes(struct drm_connector *connector) { - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct edid *edid = NULL; int ret = 0; - edid = drm_get_edid(connector, &gma_encoder->i2c_bus->base); + edid = drm_get_edid(connector, connector->ddc); if (edid) { drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); @@ -243,9 +241,9 @@ static enum drm_mode_status cdv_hdmi_mode_valid(struct drm_connector *connector, static void cdv_hdmi_destroy(struct drm_connector *connector) { struct gma_connector *gma_connector = to_gma_connector(connector); - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - gma_i2c_destroy(gma_encoder->i2c_bus); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -278,37 +276,60 @@ void cdv_hdmi_init(struct drm_device *dev, struct gma_encoder *gma_encoder; struct gma_connector *gma_connector; struct drm_connector *connector; - struct drm_encoder *encoder; struct mid_intel_hdmi_priv *hdmi_priv; - int ddc_bus; + struct gma_i2c_chan *ddc_bus; + int ddc_reg; + int ret; gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); - if (!gma_encoder) return; - gma_connector = kzalloc(sizeof(struct gma_connector), - GFP_KERNEL); - + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); if (!gma_connector) - goto err_connector; + goto err_free_encoder; hdmi_priv = kzalloc(sizeof(struct mid_intel_hdmi_priv), GFP_KERNEL); - if (!hdmi_priv) - goto err_priv; + goto err_free_connector; connector = &gma_connector->base; connector->polled = DRM_CONNECTOR_POLL_HPD; gma_connector->save = cdv_hdmi_save; gma_connector->restore = cdv_hdmi_restore; - encoder = &gma_encoder->base; - drm_connector_init(dev, connector, - &cdv_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_DVID); + switch (reg) { + case SDVOB: + ddc_reg = GPIOE; + gma_encoder->ddi_select = DDI0_SELECT; + break; + case SDVOC: + ddc_reg = GPIOD; + gma_encoder->ddi_select = DDI1_SELECT; + break; + default: + DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); + goto err_free_hdmi_priv; + } - drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); + ddc_bus = gma_i2c_create(dev, ddc_reg, + (reg == SDVOB) ? "HDMIB" : "HDMIC"); + if (!ddc_bus) { + dev_err(dev->dev, "No ddc adapter available!\n"); + goto err_free_hdmi_priv; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_DVID, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; + + ret = drm_simple_encoder_init(dev, &gma_encoder->base, + DRM_MODE_ENCODER_TMDS); + if (ret) + goto err_connector_cleanup; gma_connector_attach_encoder(gma_connector, gma_encoder); gma_encoder->type = INTEL_OUTPUT_HDMI; @@ -316,7 +337,7 @@ void cdv_hdmi_init(struct drm_device *dev, hdmi_priv->has_hdmi_sink = false; gma_encoder->dev_priv = hdmi_priv; - drm_encoder_helper_add(encoder, &cdv_hdmi_helper_funcs); + drm_encoder_helper_add(&gma_encoder->base, &cdv_hdmi_helper_funcs); drm_connector_helper_add(connector, &cdv_hdmi_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; @@ -327,38 +348,17 @@ void cdv_hdmi_init(struct drm_device *dev, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); - switch (reg) { - case SDVOB: - ddc_bus = GPIOE; - gma_encoder->ddi_select = DDI0_SELECT; - break; - case SDVOC: - ddc_bus = GPIOD; - gma_encoder->ddi_select = DDI1_SELECT; - break; - default: - DRM_ERROR("unknown reg 0x%x for HDMI\n", reg); - goto failed_ddc; - break; - } - - gma_encoder->i2c_bus = gma_i2c_create(dev, ddc_bus, - (reg == SDVOB) ? "HDMIB" : "HDMIC"); - - if (!gma_encoder->i2c_bus) { - dev_err(dev->dev, "No ddc adapter available!\n"); - goto failed_ddc; - } - - hdmi_priv->hdmi_i2c_adapter = &gma_encoder->i2c_bus->base; hdmi_priv->dev = dev; return; -failed_ddc: - drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); -err_priv: +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_hdmi_priv: + kfree(hdmi_priv); +err_free_connector: kfree(gma_connector); -err_connector: +err_free_encoder: kfree(gma_encoder); } From 147a09072c84b32746fb70139963a92c7d90e07a Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:08 +0200 Subject: [PATCH 147/170] drm/gma500: Make psb lvds use ddc adapter from drm_connector We're moving all uses of ddc_bus to drm_connector where they belong. Also cleanup the error handling in psb_intel_lvds_init() and remove unused ddc_bus in psb_intel_lvds_priv. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-6-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/psb_intel_lvds.c | 72 +++++++++++++------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index c28fabdcfd73..1121bb155c5e 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -50,7 +50,6 @@ struct psb_intel_lvds_priv { uint32_t saveBLC_PWM_CTL; struct gma_i2c_chan *i2c_bus; - struct gma_i2c_chan *ddc_bus; }; @@ -512,20 +511,12 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) return 0; } -/** - * psb_intel_lvds_destroy - unregister and free LVDS structures - * @connector: connector to free - * - * Unregister the DDC bus for this connector then free the driver private - * structure. - */ void psb_intel_lvds_destroy(struct drm_connector *connector) { struct gma_connector *gma_connector = to_gma_connector(connector); - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv; + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - gma_i2c_destroy(lvds_priv->ddc_bus); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); kfree(gma_connector); } @@ -639,25 +630,28 @@ void psb_intel_lvds_init(struct drm_device *dev, struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *ddc_bus; u32 lvds; int pipe; + int ret; gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); if (!gma_encoder) { dev_err(dev->dev, "gma_encoder allocation error\n"); return; } + encoder = &gma_encoder->base; gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); if (!gma_connector) { dev_err(dev->dev, "gma_connector allocation error\n"); - goto failed_encoder; + goto err_free_encoder; } lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) { dev_err(dev->dev, "LVDS private allocation error\n"); - goto failed_connector; + goto err_free_connector; } gma_encoder->dev_priv = lvds_priv; @@ -666,12 +660,24 @@ void psb_intel_lvds_init(struct drm_device *dev, gma_connector->save = psb_intel_lvds_save; gma_connector->restore = psb_intel_lvds_restore; - encoder = &gma_encoder->base; - drm_connector_init(dev, connector, - &psb_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, + "DDC bus registration " "failed.\n"); + goto err_free_lvds_priv; + } - drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + ret = drm_connector_init_with_ddc(dev, connector, + &psb_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; + + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; gma_connector_attach_encoder(gma_connector, gma_encoder); gma_encoder->type = INTEL_OUTPUT_LVDS; @@ -699,7 +705,7 @@ void psb_intel_lvds_init(struct drm_device *dev, if (!lvds_priv->i2c_bus) { dev_printk(KERN_ERR, dev->dev, "I2C bus registration failed.\n"); - goto failed_blc_i2c; + goto err_encoder_cleanup; } lvds_priv->i2c_bus->slave_addr = 0x2C; dev_priv->lvds_i2c_bus = lvds_priv->i2c_bus; @@ -714,20 +720,13 @@ void psb_intel_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - lvds_priv->ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); - if (!lvds_priv->ddc_bus) { - dev_printk(KERN_ERR, dev->dev, - "DDC bus registration " "failed.\n"); - goto failed_ddc; - } - /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ mutex_lock(&dev->mode_config.mutex); - psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->base); + psb_intel_ddc_get_modes(connector, &ddc_bus->base); + list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = @@ -773,7 +772,7 @@ void psb_intel_lvds_init(struct drm_device *dev, /* If we still don't have a mode after all that, give up. */ if (!mode_dev->panel_fixed_mode) { dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } /* @@ -784,17 +783,20 @@ out: mutex_unlock(&dev->mode_config.mutex); return; -failed_find: +err_unlock: mutex_unlock(&dev->mode_config.mutex); - gma_i2c_destroy(lvds_priv->ddc_bus); -failed_ddc: gma_i2c_destroy(lvds_priv->i2c_bus); -failed_blc_i2c: +err_encoder_cleanup: drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); -failed_connector: +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_lvds_priv: + kfree(lvds_priv); +err_free_connector: kfree(gma_connector); -failed_encoder: +err_free_encoder: kfree(gma_encoder); } From 0cc3ae930c8b2a086b802a8c7b915fd28b57c780 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:09 +0200 Subject: [PATCH 148/170] drm/gma500: Make cdv crt use ddc adapter from drm_connector We're moving all uses of ddc_bus to drm_connector where they belong. Also cleanup the error handling in cdv_intel_crt_init(). Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-7-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_crt.c | 47 +++++++++++++++----------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index be0d6a4591bf..7ff1e5141150 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -192,18 +192,16 @@ static enum drm_connector_status cdv_intel_crt_detect( static void cdv_intel_crt_destroy(struct drm_connector *connector) { struct gma_connector *gma_connector = to_gma_connector(connector); - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); + struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc); - gma_i2c_destroy(gma_encoder->ddc_bus); + gma_i2c_destroy(ddc_bus); drm_connector_cleanup(connector); kfree(gma_connector); } static int cdv_intel_crt_get_modes(struct drm_connector *connector) { - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - return psb_intel_ddc_get_modes(connector, - &gma_encoder->ddc_bus->base); + return psb_intel_ddc_get_modes(connector, connector->ddc); } static int cdv_intel_crt_set_property(struct drm_connector *connector, @@ -245,8 +243,10 @@ void cdv_intel_crt_init(struct drm_device *dev, struct gma_connector *gma_connector; struct gma_encoder *gma_encoder; + struct gma_i2c_chan *ddc_bus; struct drm_connector *connector; struct drm_encoder *encoder; + int ret; gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); if (!gma_encoder) @@ -254,25 +254,31 @@ void cdv_intel_crt_init(struct drm_device *dev, gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); if (!gma_connector) - goto failed_connector; + goto err_free_encoder; + + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n"); + goto err_free_connector; + } connector = &gma_connector->base; connector->polled = DRM_CONNECTOR_POLL_HPD; - drm_connector_init(dev, connector, - &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_intel_crt_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &ddc_bus->base); + if (ret) + goto err_ddc_destroy; encoder = &gma_encoder->base; - drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); + if (ret) + goto err_connector_cleanup; gma_connector_attach_encoder(gma_connector, gma_encoder); - /* Set up the DDC bus. */ - gma_encoder->ddc_bus = gma_i2c_create(dev, GPIOA, "CRTDDC_A"); - if (!gma_encoder->ddc_bus) { - dev_printk(KERN_ERR, dev->dev, "DDC bus registration failed.\n"); - goto failed_ddc; - } - gma_encoder->type = INTEL_OUTPUT_ANALOG; connector->interlace_allowed = 0; connector->doublescan_allowed = 0; @@ -282,11 +288,14 @@ void cdv_intel_crt_init(struct drm_device *dev, &cdv_intel_crt_connector_helper_funcs); return; -failed_ddc: - drm_encoder_cleanup(&gma_encoder->base); + +err_connector_cleanup: drm_connector_cleanup(&gma_connector->base); +err_ddc_destroy: + gma_i2c_destroy(ddc_bus); +err_free_connector: kfree(gma_connector); -failed_connector: +err_free_encoder: kfree(gma_encoder); return; } From a57ebfc0b4da16a3f36bfebb158198aab3e340f8 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:10 +0200 Subject: [PATCH 149/170] drm/gma500: Make oaktrail lvds use ddc adapter from drm_connector We're moving all uses of ddc_bus to drm_connector where they belong. The initialization of the gma_i2c_chan for Oaktrail is a bit backwards so it required improvements. Also cleanup the error handling in oaktrail_lvds_init(). Since this is the last user of gma_encoder->ddc_bus we can remove it. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-8-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/oaktrail_lvds.c | 50 +++++++++++++--------- drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c | 14 +++--- drivers/gpu/drm/gma500/psb_intel_drv.h | 3 +- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 8609f6249c4c..9c9ebf8e29c4 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -293,12 +293,14 @@ void oaktrail_lvds_init(struct drm_device *dev, { struct gma_encoder *gma_encoder; struct gma_connector *gma_connector; + struct gma_i2c_chan *ddc_bus; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct edid *edid; struct i2c_adapter *i2c_adap; struct drm_display_mode *scan; /* *modes, *bios_mode; */ + int ret; gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); if (!gma_encoder) @@ -306,16 +308,20 @@ void oaktrail_lvds_init(struct drm_device *dev, gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); if (!gma_connector) - goto failed_connector; + goto err_free_encoder; connector = &gma_connector->base; encoder = &gma_encoder->base; dev_priv->is_lvds_on = true; - drm_connector_init(dev, connector, - &psb_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + ret = drm_connector_init(dev, connector, + &psb_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret) + goto err_free_connector; - drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; gma_connector_attach_encoder(gma_connector, gma_encoder); gma_encoder->type = INTEL_OUTPUT_LVDS; @@ -353,16 +359,26 @@ void oaktrail_lvds_init(struct drm_device *dev, edid = NULL; mutex_lock(&dev->mode_config.mutex); + i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); if (i2c_adap) edid = drm_get_edid(connector, i2c_adap); + if (edid == NULL && dev_priv->lpc_gpio_base) { - oaktrail_lvds_i2c_init(encoder); - if (gma_encoder->ddc_bus != NULL) { - i2c_adap = &gma_encoder->ddc_bus->base; + ddc_bus = oaktrail_lvds_i2c_init(dev); + if (!IS_ERR(ddc_bus)) { + i2c_adap = &ddc_bus->base; edid = drm_get_edid(connector, i2c_adap); } } + + /* + * Due to the logic in probing for i2c buses above we do not know the + * i2c_adap until now. Hence we cannot use drm_connector_init_with_ddc() + * but must instead set connector->ddc manually here. + */ + connector->ddc = i2c_adap; + /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. @@ -395,7 +411,7 @@ void oaktrail_lvds_init(struct drm_device *dev, /* If we still don't have a mode after all that, give up. */ if (!mode_dev->panel_fixed_mode) { dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } out: @@ -403,21 +419,15 @@ out: return; -failed_find: +err_unlock: mutex_unlock(&dev->mode_config.mutex); - - dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); - if (gma_encoder->ddc_bus) { - gma_i2c_destroy(gma_encoder->ddc_bus); - gma_encoder->ddc_bus = NULL; - } - -/* failed_ddc: */ - + gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); +err_free_connector: kfree(gma_connector); -failed_connector: +err_free_encoder: kfree(gma_encoder); } diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c index ee163fb972d9..06b5b2d70d48 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -129,16 +129,15 @@ static void set_data(void *data, int state_high) } } -void oaktrail_lvds_i2c_init(struct drm_encoder *encoder) +struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev) { - struct drm_device *dev = encoder->dev; - struct gma_encoder *gma_encoder = to_gma_encoder(encoder); struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct gma_i2c_chan *chan; + int ret; chan = kzalloc(sizeof(struct gma_i2c_chan), GFP_KERNEL); if (!chan) - return; + return ERR_PTR(-ENOMEM); chan->drm_dev = dev; chan->reg = dev_priv->lpc_gpio_base; @@ -160,10 +159,11 @@ void oaktrail_lvds_i2c_init(struct drm_encoder *encoder) set_clock(chan, 1); udelay(50); - if (i2c_bit_add_bus(&chan->base)) { + ret = i2c_bit_add_bus(&chan->base); + if (ret < 0) { kfree(chan); - return; + return ERR_PTR(ret); } - gma_encoder->ddc_bus = chan; + return chan; } diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 1c28288f36a0..8ccba116821b 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -105,7 +105,6 @@ struct gma_encoder { /* FIXME: Either make SDVO and LVDS store it's i2c here or give CDV it's own set of output privates */ struct gma_i2c_chan *i2c_bus; - struct gma_i2c_chan *ddc_bus; }; struct gma_connector { @@ -200,7 +199,7 @@ extern void oaktrail_lvds_init(struct drm_device *dev, extern void oaktrail_wait_for_INTR_PKT_SENT(struct drm_device *dev); extern void oaktrail_dsi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev); -extern void oaktrail_lvds_i2c_init(struct drm_encoder *encoder); +struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev); extern void mid_dsi_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev, int dsi_num); From e9ca4e9ea6e208feae82f72607818ac8e15115f4 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 1 Jun 2022 11:23:11 +0200 Subject: [PATCH 150/170] drm/gma500: Read EDID from the correct i2c adapter Someone made the mistake to try reading EDID from the backlight i2c adapter. This has been wrong for a very long time but since we read out the modes correctly on init and don't hotplug lvds it has been working anyway. Correct this by using connector->ddc instead of encoder->i2c_bus. Both PSB and CDV are affected but this bug. Signed-off-by: Patrik Jakobsson Acked-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220601092311.22648-9-patrik.r.jakobsson@gmail.com --- drivers/gpu/drm/gma500/cdv_intel_lvds.c | 3 +-- drivers/gpu/drm/gma500/psb_intel_lvds.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 846ce1546030..be6efcaaa3b3 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -298,11 +298,10 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int ret; - ret = psb_intel_ddc_get_modes(connector, &gma_encoder->i2c_bus->base); + ret = psb_intel_ddc_get_modes(connector, connector->ddc); if (ret) return ret; diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 1121bb155c5e..7ee6c8ce103b 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -491,12 +491,10 @@ static int psb_intel_lvds_get_modes(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; - struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv; int ret = 0; if (!IS_MRST(dev)) - ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->base); + ret = psb_intel_ddc_get_modes(connector, connector->ddc); if (ret) return ret; From 3800b1710946f7db3cb3a29cb2e218cf5df999d0 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:42 -0700 Subject: [PATCH 151/170] drm/dp: Add callbacks to make using DP AUX bus properly easier As talked about in this patch in the kerneldoc of of_dp_aux_populate_ep_device() and also in the past in commit a1e3667a9835 ("drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev"), it can be difficult for eDP controller drivers to know when the panel has finished probing when they're using of_dp_aux_populate_ep_devices(). The ti-sn65dsi86 driver managed to solve this because it was already broken up into a bunch of sub-drivers. That means we could solve the problem there by adding a new sub-driver to get the panel. We could use the traditional -EPROBE_DEFER retry mechansim to handle the case where the panel hadn't probed yet. In parade-ps8640 we didn't really solve this. The code just expects the panel to be ready right away. While reviewing the code originally I had managed to convince myself it was fine to just expect the panel right away, but additional testing has shown that not to be the case. We could fix parade-ps8640 like we did ti-sn65dsi86 but it's pretty cumbersome (since we're not already broken into multiple drivers) and requires a bunch of boilerplate code. After discussion [1] it seems like the best solution for most people is: - Accept that there's always at most one device that will probe as a result of the DP AUX bus (it may have sub-devices, but there will be one device _directly_ probed). - When that device finishes probing, we can just have a call back. This patch implements that idea. We'll now take a callback as an argument to the populate function. To make this easier to land in pieces, we'll make wrappers for the old functions. The functions with the new name (which make it clear that we only have one child) will take the callback and the functions with the old name will temporarily wrap. [1] https://lore.kernel.org/r/CAD=FV=Ur3afHhsXe7a3baWEnD=MFKFeKRbhFU+bt3P67G0MVzQ@mail.gmail.com Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.2.I4182ae27e00792842cb86f1433990a0ef9c0a073@changeid --- drivers/gpu/drm/display/drm_dp_aux_bus.c | 217 +++++++++++++++-------- include/drm/display/drm_dp_aux_bus.h | 34 +++- 2 files changed, 172 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_aux_bus.c b/drivers/gpu/drm/display/drm_dp_aux_bus.c index 552f949cff59..f5741b45ca07 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_bus.c +++ b/drivers/gpu/drm/display/drm_dp_aux_bus.c @@ -3,10 +3,10 @@ * Copyright 2021 Google Inc. * * The DP AUX bus is used for devices that are connected over a DisplayPort - * AUX bus. The devices on the far side of the bus are referred to as - * endpoints in this code. + * AUX bus. The device on the far side of the bus is referred to as an + * endpoint in this code. * - * Commonly there is only one device connected to the DP AUX bus: a panel. + * There is only one device connected to the DP AUX bus: an eDP panel. * Though historically panels (even DP panels) have been modeled as simple * platform devices, putting them under the DP AUX bus allows the panel driver * to perform transactions on that bus. @@ -22,6 +22,11 @@ #include #include +struct dp_aux_ep_device_with_data { + struct dp_aux_ep_device aux_ep; + int (*done_probing)(struct drm_dp_aux *aux); +}; + /** * dp_aux_ep_match() - The match function for the dp_aux_bus. * @dev: The device to match. @@ -48,6 +53,8 @@ static int dp_aux_ep_probe(struct device *dev) { struct dp_aux_ep_driver *aux_ep_drv = to_dp_aux_ep_drv(dev->driver); struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev); + struct dp_aux_ep_device_with_data *aux_ep_with_data = + container_of(aux_ep, struct dp_aux_ep_device_with_data, aux_ep); int ret; ret = dev_pm_domain_attach(dev, true); @@ -56,7 +63,32 @@ static int dp_aux_ep_probe(struct device *dev) ret = aux_ep_drv->probe(aux_ep); if (ret) - dev_pm_domain_detach(dev, true); + goto err_attached; + + if (aux_ep_with_data->done_probing) { + ret = aux_ep_with_data->done_probing(aux_ep->aux); + if (ret) { + /* + * The done_probing() callback should not return + * -EPROBE_DEFER to us. If it does, we treat it as an + * error. Passing it on as-is would cause the _panel_ + * to defer. + */ + if (ret == -EPROBE_DEFER) { + dev_err(dev, + "DP AUX done_probing() can't defer\n"); + ret = -EINVAL; + } + goto err_probed; + } + } + + return 0; +err_probed: + if (aux_ep_drv->remove) + aux_ep_drv->remove(aux_ep); +err_attached: + dev_pm_domain_detach(dev, true); return ret; } @@ -122,7 +154,11 @@ ATTRIBUTE_GROUPS(dp_aux_ep_dev); */ static void dp_aux_ep_dev_release(struct device *dev) { - kfree(to_dp_aux_ep_dev(dev)); + struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev); + struct dp_aux_ep_device_with_data *aux_ep_with_data = + container_of(aux_ep, struct dp_aux_ep_device_with_data, aux_ep); + + kfree(aux_ep_with_data); } static struct device_type dp_aux_device_type_type = { @@ -136,12 +172,14 @@ static struct device_type dp_aux_device_type_type = { * @dev: The device to destroy. * @data: Not used * - * This is just used as a callback by of_dp_aux_depopulate_ep_devices() and + * This is just used as a callback by of_dp_aux_depopulate_bus() and * is called for _all_ of the child devices of the device providing the AUX bus. * We'll only act on those that are of type "dp_aux_bus_type". * - * This function is effectively an inverse of what's in the loop - * in of_dp_aux_populate_ep_devices(). + * This function is effectively an inverse of what's in + * of_dp_aux_populate_bus(). NOTE: since we only populate one child + * then it's expected that only one device will match all the "if" tests in + * this function and get to the device_unregister(). * * Return: 0 if no error or negative error code. */ @@ -164,123 +202,150 @@ static int of_dp_aux_ep_destroy(struct device *dev, void *data) } /** - * of_dp_aux_depopulate_ep_devices() - Undo of_dp_aux_populate_ep_devices - * @aux: The AUX channel whose devices we want to depopulate + * of_dp_aux_depopulate_bus() - Undo of_dp_aux_populate_bus + * @aux: The AUX channel whose device we want to depopulate * - * This will destroy all devices that were created - * by of_dp_aux_populate_ep_devices(). + * This will destroy the device that was created + * by of_dp_aux_populate_bus(). */ -void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux) +void of_dp_aux_depopulate_bus(struct drm_dp_aux *aux) { device_for_each_child_reverse(aux->dev, NULL, of_dp_aux_ep_destroy); } -EXPORT_SYMBOL_GPL(of_dp_aux_depopulate_ep_devices); +EXPORT_SYMBOL_GPL(of_dp_aux_depopulate_bus); /** - * of_dp_aux_populate_ep_devices() - Populate the endpoint devices on the DP AUX - * @aux: The AUX channel whose devices we want to populate. It is required that + * of_dp_aux_populate_bus() - Populate the endpoint device on the DP AUX + * @aux: The AUX channel whose device we want to populate. It is required that * drm_dp_aux_init() has already been called for this AUX channel. + * @done_probing: Callback functions to call after EP device finishes probing. + * Will not be called if there are no EP devices and this + * function will return -ENODEV. * - * This will populate all the devices under the "aux-bus" node of the device - * providing the AUX channel (AKA aux->dev). + * This will populate the device (expected to be an eDP panel) under the + * "aux-bus" node of the device providing the AUX channel (AKA aux->dev). * * When this function finishes, it is _possible_ (but not guaranteed) that - * our sub-devices will have finished probing. It should be noted that if our - * sub-devices return -EPROBE_DEFER that we will not return any error codes - * ourselves but our sub-devices will _not_ have actually probed successfully - * yet. There may be other cases (maybe added in the future?) where sub-devices - * won't have been probed yet when this function returns, so it's best not to - * rely on that. + * our sub-device will have finished probing. It should be noted that if our + * sub-device returns -EPROBE_DEFER or is probing asynchronously for some + * reason that we will not return any error codes ourselves but our + * sub-device will _not_ have actually probed successfully yet. + * + * In many cases it's important for the caller of this function to be notified + * when our sub device finishes probing. Our sub device is expected to be an + * eDP panel and the caller is expected to be an eDP controller. The eDP + * controller needs to be able to get a reference to the panel when it finishes + * probing. For this reason the caller can pass in a function pointer that + * will be called when our sub-device finishes probing. * * If this function succeeds you should later make sure you call - * of_dp_aux_depopulate_ep_devices() to undo it, or just use the devm version + * of_dp_aux_depopulate_bus() to undo it, or just use the devm version * of this function. * - * Return: 0 if no error or negative error code. + * Return: 0 if no error or negative error code; returns -ENODEV if there are + * no children. The done_probing() function won't be called in that + * case. */ -int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +int of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)) { - struct device_node *bus, *np; + struct device_node *bus = NULL, *np = NULL; struct dp_aux_ep_device *aux_ep; + struct dp_aux_ep_device_with_data *aux_ep_with_data; int ret; /* drm_dp_aux_init() should have been called already; warn if not */ WARN_ON_ONCE(!aux->ddc.algo); if (!aux->dev->of_node) - return 0; - + return -ENODEV; bus = of_get_child_by_name(aux->dev->of_node, "aux-bus"); if (!bus) - return 0; + return -ENODEV; - for_each_available_child_of_node(bus, np) { - if (of_node_test_and_set_flag(np, OF_POPULATED)) - continue; + np = of_get_next_available_child(bus, NULL); + of_node_put(bus); + if (!np) + return -ENODEV; - aux_ep = kzalloc(sizeof(*aux_ep), GFP_KERNEL); - if (!aux_ep) - continue; - aux_ep->aux = aux; - - aux_ep->dev.parent = aux->dev; - aux_ep->dev.bus = &dp_aux_bus_type; - aux_ep->dev.type = &dp_aux_device_type_type; - aux_ep->dev.of_node = of_node_get(np); - dev_set_name(&aux_ep->dev, "aux-%s", dev_name(aux->dev)); - - ret = device_register(&aux_ep->dev); - if (ret) { - dev_err(aux->dev, "Failed to create AUX EP for %pOF: %d\n", np, ret); - of_node_clear_flag(np, OF_POPULATED); - of_node_put(np); - - /* - * As per docs of device_register(), call this instead - * of kfree() directly for error cases. - */ - put_device(&aux_ep->dev); - - /* - * Following in the footsteps of of_i2c_register_devices(), - * we won't fail the whole function here--we'll just - * continue registering any other devices we find. - */ - } + if (of_node_test_and_set_flag(np, OF_POPULATED)) { + dev_err(aux->dev, "DP AUX EP device already populated\n"); + ret = -EINVAL; + goto err_did_get_np; } - of_node_put(bus); + aux_ep_with_data = kzalloc(sizeof(*aux_ep_with_data), GFP_KERNEL); + if (!aux_ep_with_data) { + ret = -ENOMEM; + goto err_did_set_populated; + } + + aux_ep_with_data->done_probing = done_probing; + + aux_ep = &aux_ep_with_data->aux_ep; + aux_ep->aux = aux; + aux_ep->dev.parent = aux->dev; + aux_ep->dev.bus = &dp_aux_bus_type; + aux_ep->dev.type = &dp_aux_device_type_type; + aux_ep->dev.of_node = of_node_get(np); + dev_set_name(&aux_ep->dev, "aux-%s", dev_name(aux->dev)); + + ret = device_register(&aux_ep->dev); + if (ret) { + dev_err(aux->dev, "Failed to create AUX EP for %pOF: %d\n", np, ret); + + /* + * As per docs of device_register(), call this instead + * of kfree() directly for error cases. + */ + put_device(&aux_ep->dev); + + goto err_did_set_populated; + } return 0; -} -EXPORT_SYMBOL_GPL(of_dp_aux_populate_ep_devices); -static void of_dp_aux_depopulate_ep_devices_void(void *data) +err_did_set_populated: + of_node_clear_flag(np, OF_POPULATED); + +err_did_get_np: + of_node_put(np); + + return ret; +} +EXPORT_SYMBOL_GPL(of_dp_aux_populate_bus); + +static void of_dp_aux_depopulate_bus_void(void *data) { - of_dp_aux_depopulate_ep_devices(data); + of_dp_aux_depopulate_bus(data); } /** - * devm_of_dp_aux_populate_ep_devices() - devm wrapper for of_dp_aux_populate_ep_devices() - * @aux: The AUX channel whose devices we want to populate + * devm_of_dp_aux_populate_bus() - devm wrapper for of_dp_aux_populate_bus() + * @aux: The AUX channel whose device we want to populate + * @done_probing: Callback functions to call after EP device finishes probing. + * Will not be called if there are no EP devices and this + * function will return -ENODEV. * * Handles freeing w/ devm on the device "aux->dev". * - * Return: 0 if no error or negative error code. + * Return: 0 if no error or negative error code; returns -ENODEV if there are + * no children. The done_probing() function won't be called in that + * case. */ -int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +int devm_of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)) { int ret; - ret = of_dp_aux_populate_ep_devices(aux); + ret = of_dp_aux_populate_bus(aux, done_probing); if (ret) return ret; return devm_add_action_or_reset(aux->dev, - of_dp_aux_depopulate_ep_devices_void, - aux); + of_dp_aux_depopulate_bus_void, aux); } -EXPORT_SYMBOL_GPL(devm_of_dp_aux_populate_ep_devices); +EXPORT_SYMBOL_GPL(devm_of_dp_aux_populate_bus); int __dp_aux_dp_driver_register(struct dp_aux_ep_driver *drv, struct module *owner) { diff --git a/include/drm/display/drm_dp_aux_bus.h b/include/drm/display/drm_dp_aux_bus.h index 4f19b20b1dd6..8a0a486383c5 100644 --- a/include/drm/display/drm_dp_aux_bus.h +++ b/include/drm/display/drm_dp_aux_bus.h @@ -44,9 +44,37 @@ static inline struct dp_aux_ep_driver *to_dp_aux_ep_drv(struct device_driver *dr return container_of(drv, struct dp_aux_ep_driver, driver); } -int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux); -void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux); -int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux); +int of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)); +void of_dp_aux_depopulate_bus(struct drm_dp_aux *aux); +int devm_of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)); + +/* Deprecated versions of the above functions. To be removed when no callers. */ +static inline int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +{ + int ret; + + ret = of_dp_aux_populate_bus(aux, NULL); + + /* New API returns -ENODEV for no child case; adapt to old assumption */ + return (ret != -ENODEV) ? ret : 0; +} + +static inline int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +{ + int ret; + + ret = devm_of_dp_aux_populate_bus(aux, NULL); + + /* New API returns -ENODEV for no child case; adapt to old assumption */ + return (ret != -ENODEV) ? ret : 0; +} + +static inline void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux) +{ + of_dp_aux_depopulate_bus(aux); +} #define dp_aux_dp_driver_register(aux_ep_drv) \ __dp_aux_dp_driver_register(aux_ep_drv, THIS_MODULE) From 50e156bd8a9d0910ac4bae5fcff00ddb798db967 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:43 -0700 Subject: [PATCH 152/170] drm/bridge: Add devm_drm_bridge_add() This adds a devm managed version of drm_bridge_add(). Like other "devm" function listed in drm_bridge.h, this function takes an explicit "dev" to use for the lifetime management. A few notes: * In general we have a "struct device" for bridges that makes a good candidate for where the lifetime matches exactly what we want. * The "bridge->dev->dev" device appears to be the encoder device. That's not the right device to use for lifetime management. Suggested-by: Dmitry Baryshkov Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.3.Iba4b9bf6c7a1ee5ea2835ad7bd5eaf84d7688520@changeid --- drivers/gpu/drm/drm_bridge.c | 23 +++++++++++++++++++++++ include/drm/drm_bridge.h | 1 + 2 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c96847fc0ebc..e275b4ca344b 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -170,6 +170,29 @@ void drm_bridge_add(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_add); +static void drm_bridge_remove_void(void *bridge) +{ + drm_bridge_remove(bridge); +} + +/** + * devm_drm_bridge_add - devm managed version of drm_bridge_add() + * + * @dev: device to tie the bridge lifetime to + * @bridge: bridge control structure + * + * This is the managed version of drm_bridge_add() which automatically + * calls drm_bridge_remove() when @dev is unbound. + * + * Return: 0 if no error or negative error code. + */ +int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge) +{ + drm_bridge_add(bridge); + return devm_add_action_or_reset(dev, drm_bridge_remove_void, bridge); +} +EXPORT_SYMBOL(devm_drm_bridge_add); + /** * drm_bridge_remove - remove the given bridge from the global bridge list * diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index f27b4060faa2..42aec8612f37 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -796,6 +796,7 @@ drm_priv_to_bridge(struct drm_private_obj *priv) } void drm_bridge_add(struct drm_bridge *bridge); +int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous, From 10e619f1f31cf126885b3e0ac43a8de9744467fb Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:44 -0700 Subject: [PATCH 153/170] drm/bridge: parade-ps8640: Handle DP AUX more properly While it works, for the most part, to assume that the panel has finished probing when devm_of_dp_aux_populate_ep_devices() returns, it's a bit fragile. This is talked about at length in commit a1e3667a9835 ("drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev"). When reviewing the ps8640 code, I managed to convince myself that it was OK not to worry about it there and that maybe it wasn't really _that_ fragile. However, it turns out that it really is. Simply hardcoding panel_edp_probe() to return -EPROBE_DEFER was enough to put the boot process into an infinite loop. I believe this manages to trip the same issues that we used to trip with the main MSM code where something about our actions trigger Linux to re-probe previously deferred devices right away and each time we try again we re-trigger Linux to re-probe. Let's fix this using the callback introduced in the patch ("drm/dp: Callbacks to make it easier for drivers to use DP AUX bus properly"). When using the new callback, we have to be a little careful. The probe_done() callback is no longer always called in the context of our probe routine. That means we can't rely on being able to return -EPROBE_DEFER from it. We re-jigger the order of things a bit to account for that. With this change, the device still boots (though obviously the panel doesn't come up) if I force panel-edp to always return -EPROBE_DEFER. If I fake it and make the panel probe exactly once it also works. Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.4.Ia6324ebc848cd40b4dbd3ad3289a7ffb5c197779@changeid --- drivers/gpu/drm/bridge/parade-ps8640.c | 74 ++++++++++++++++---------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index e2467e58b5b7..ff4227f6d800 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -537,7 +537,7 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = { .pre_enable = ps8640_pre_enable, }; -static int ps8640_bridge_host_attach(struct device *dev, struct ps8640 *ps_bridge) +static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 *ps_bridge) { struct device_node *in_ep, *dsi_node; struct mipi_dsi_device *dsi; @@ -576,13 +576,40 @@ static int ps8640_bridge_host_attach(struct device *dev, struct ps8640 *ps_bridg dsi->format = MIPI_DSI_FMT_RGB888; dsi->lanes = NUM_MIPI_LANES; - return devm_mipi_dsi_attach(dev, dsi); + return 0; +} + +static int ps8640_bridge_link_panel(struct drm_dp_aux *aux) +{ + struct ps8640 *ps_bridge = aux_to_ps8640(aux); + struct device *dev = aux->dev; + struct device_node *np = dev->of_node; + int ret; + + /* + * NOTE about returning -EPROBE_DEFER from this function: if we + * return an error (most relevant to -EPROBE_DEFER) it will only + * be passed out to ps8640_probe() if it called this directly (AKA the + * panel isn't under the "aux-bus" node). That should be fine because + * if the panel is under "aux-bus" it's guaranteed to have probed by + * the time this function has been called. + */ + + /* port@1 is ps8640 output port */ + ps_bridge->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0); + if (IS_ERR(ps_bridge->panel_bridge)) + return PTR_ERR(ps_bridge->panel_bridge); + + ret = devm_drm_bridge_add(dev, &ps_bridge->bridge); + if (ret) + return ret; + + return devm_mipi_dsi_attach(dev, ps_bridge->dsi); } static int ps8640_probe(struct i2c_client *client) { struct device *dev = &client->dev; - struct device_node *np = dev->of_node; struct ps8640 *ps_bridge; int ret; u32 i; @@ -623,6 +650,14 @@ static int ps8640_probe(struct i2c_client *client) if (!ps8640_of_panel_on_aux_bus(&client->dev)) ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; + /* + * Get MIPI DSI resources early. These can return -EPROBE_DEFER so + * we want to get them out of the way sooner. + */ + ret = ps8640_bridge_get_dsi_resources(&client->dev, ps_bridge); + if (ret) + return ret; + ps_bridge->page[PAGE0_DP_CNTL] = client; ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config); @@ -665,35 +700,19 @@ static int ps8640_probe(struct i2c_client *client) if (ret) return ret; - devm_of_dp_aux_populate_ep_devices(&ps_bridge->aux); + ret = devm_of_dp_aux_populate_bus(&ps_bridge->aux, ps8640_bridge_link_panel); - /* port@1 is ps8640 output port */ - ps_bridge->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0); - if (IS_ERR(ps_bridge->panel_bridge)) - return PTR_ERR(ps_bridge->panel_bridge); + /* + * If devm_of_dp_aux_populate_bus() returns -ENODEV then it's up to + * usa to call ps8640_bridge_link_panel() directly. NOTE: in this case + * the function is allowed to -EPROBE_DEFER. + */ + if (ret == -ENODEV) + return ps8640_bridge_link_panel(&ps_bridge->aux); - drm_bridge_add(&ps_bridge->bridge); - - ret = ps8640_bridge_host_attach(dev, ps_bridge); - if (ret) - goto err_bridge_remove; - - return 0; - -err_bridge_remove: - drm_bridge_remove(&ps_bridge->bridge); return ret; } -static int ps8640_remove(struct i2c_client *client) -{ - struct ps8640 *ps_bridge = i2c_get_clientdata(client); - - drm_bridge_remove(&ps_bridge->bridge); - - return 0; -} - static const struct of_device_id ps8640_match[] = { { .compatible = "parade,ps8640" }, { } @@ -702,7 +721,6 @@ MODULE_DEVICE_TABLE(of, ps8640_match); static struct i2c_driver ps8640_driver = { .probe_new = ps8640_probe, - .remove = ps8640_remove, .driver = { .name = "ps8640", .of_match_table = ps8640_match, From c441d28945fb113220d48d6c86ebc0b090a2b677 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 11 May 2022 11:37:16 -0500 Subject: [PATCH 154/170] drm/nouveau: fix another off-by-one in nvbios_addr This check determines whether a given address is part of image 0 or image 1. Image 1 starts at offset image0_size, so that address should be included. Fixes: 4d4e9907ff572 ("drm/nouveau/bios: guard against out-of-bounds accesses to image") Cc: # v4.8+ Signed-off-by: Timur Tabi Reviewed-by: Karol Herbst Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220511163716.3520591-1-ttabi@nvidia.com --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 64e423dddd9e..6c318e41bde0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -33,7 +33,7 @@ nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size) { u32 p = *addr; - if (*addr > bios->image0_size && bios->imaged_addr) { + if (*addr >= bios->image0_size && bios->imaged_addr) { *addr -= bios->image0_size; *addr += bios->imaged_addr; } From e1402c6619df9be27518004eed75561a66718d9a Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 3 Jun 2022 19:33:48 +0530 Subject: [PATCH 155/170] dt-bindings: display: bridge: Add TI DLPC3433 DSI to DMD TI DLPC3433 is a MIPI DSI based display controller bridge for processing high resolution DMD based projectors. It has a flexible configuration of MIPI DSI and DPI signal input that produces a DMD output in RGB565, RGB666, RGB888 formats. It supports upto 720p resolution with 60 and 120 Hz refresh rates. Add dt-bingings for it. Signed-off-by: Christopher Vollo Signed-off-by: Jagan Teki Reviewed-by: Rob Herring Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220603140349.3563612-1-jagan@amarulasolutions.com --- .../bindings/display/bridge/ti,dlpc3433.yaml | 117 ++++++++++++++++++ MAINTAINERS | 5 + 2 files changed, 122 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml b/Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml new file mode 100644 index 000000000000..542193d77cdf --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ti,dlpc3433.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI DLPC3433 MIPI DSI to DMD bridge + +maintainers: + - Jagan Teki + - Christopher Vollo + +description: | + TI DLPC3433 is a MIPI DSI based display controller bridge + for processing high resolution DMD based projectors. + + It has a flexible configuration of MIPI DSI and DPI signal + input that produces a DMD output in RGB565, RGB666, RGB888 + formats. + + It supports upto 720p resolution with 60 and 120 Hz refresh + rates. + +properties: + compatible: + const: ti,dlpc3433 + + reg: + enum: + - 0x1b + - 0x1d + + enable-gpios: + description: PROJ_ON pin, chip powers up PROJ_ON is high. + + vcc_intf-supply: + description: A 1.8V/3.3V supply that power the Host I/O. + + vcc_flsh-supply: + description: A 1.8V/3.3V supply that power the Flash I/O. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: Video port for MIPI DSI input. + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + description: array of physical DSI data lane indexes. + minItems: 1 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for DMD output. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - enable-gpios + - ports + +additionalProperties: false + +examples: + - | + #include + + i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + bridge@1b { + compatible = "ti,dlpc3433"; + reg = <0x1b>; + enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + bridge_in_dsi: endpoint { + remote-endpoint = <&dsi_out_bridge>; + data-lanes = <1 2 3 4>; + }; + }; + + port@1 { + reg = <1>; + + bridge_out_panel: endpoint { + remote-endpoint = <&panel_out_bridge>; + }; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 11da16bfa123..aea0fe5156af 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6431,6 +6431,11 @@ DRM DRIVER FOR TDFX VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/tdfx/ +DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE +M: Jagan Teki +S: Maintained +F: Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml + DRM DRIVER FOR TI SN65DSI86 BRIDGE CHIP R: Douglas Anderson F: Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml From 6352cd451ddbb506ce061868a9e5465d294d4857 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 3 Jun 2022 19:33:49 +0530 Subject: [PATCH 156/170] drm: bridge: Add TI DLPC3433 DSI to DMD bridge TI DLPC3433 is a MIPI DSI based display controller bridge for processing high resolution DMD based projectors. It has a flexible configuration of MIPI DSI and DPI signal input that produces a DMD output in RGB565, RGB666, RGB888 formats. It supports upto 720p resolution with 60 and 120 Hz refresh rates. Add bridge driver for it. Signed-off-by: Christopher Vollo Signed-off-by: Jagan Teki Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220603140349.3563612-2-jagan@amarulasolutions.com --- MAINTAINERS | 1 + drivers/gpu/drm/bridge/Kconfig | 16 + drivers/gpu/drm/bridge/Makefile | 1 + drivers/gpu/drm/bridge/ti-dlpc3433.c | 417 +++++++++++++++++++++++++++ 4 files changed, 435 insertions(+) create mode 100644 drivers/gpu/drm/bridge/ti-dlpc3433.c diff --git a/MAINTAINERS b/MAINTAINERS index aea0fe5156af..ede21cc48708 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6435,6 +6435,7 @@ DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki S: Maintained F: Documentation/devicetree/bindings/display/bridge/ti,dlpc3433.yaml +F: drivers/gpu/drm/bridge/ti-dlpc3433.c DRM DRIVER FOR TI SN65DSI86 BRIDGE CHIP R: Douglas Anderson diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 146ab069838f..4b28f939fff6 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -321,6 +321,22 @@ config DRM_TOSHIBA_TC358775 help Toshiba TC358775 DSI/LVDS bridge chip driver. +config DRM_TI_DLPC3433 + tristate "TI DLPC3433 Display controller" + depends on DRM && DRM_PANEL + depends on OF + select DRM_MIPI_DSI + help + TI DLPC3433 is a MIPI DSI based display controller bridge + for processing high resolution DMD based projectors. + + It has a flexible configuration of MIPI DSI and DPI signal + input that produces a DMD output in RGB565, RGB666, RGB888 + formats. + + It supports upto 720p resolution with 60 and 120 Hz refresh + rates. + config DRM_TI_TFP410 tristate "TI TFP410 DVI/HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index f6c0a95de549..043b499545e3 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ +obj-$(CONFIG_DRM_TI_DLPC3433) += ti-dlpc3433.o obj-$(CONFIG_DRM_TI_SN65DSI83) += ti-sn65dsi83.o obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c new file mode 100644 index 000000000000..06e519798ac5 --- /dev/null +++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 RenewOutReach + * Copyright (C) 2021 Amarula Solutions(India) + * + * Author: + * Jagan Teki + * Christopher Vollo + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +enum cmd_registers { + WR_INPUT_SOURCE = 0x05, /* Write Input Source Select */ + WR_EXT_SOURCE_FMT = 0x07, /* Write External Video Source Format */ + WR_IMAGE_CROP = 0x10, /* Write Image Crop */ + WR_DISPLAY_SIZE = 0x12, /* Write Display Size */ + WR_IMAGE_FREEZE = 0x1A, /* Write Image Freeze */ + WR_INPUT_IMAGE_SIZE = 0x2E, /* Write External Input Image Size */ + WR_RGB_LED_EN = 0x52, /* Write RGB LED Enable */ + WR_RGB_LED_CURRENT = 0x54, /* Write RGB LED Current */ + WR_RGB_LED_MAX_CURRENT = 0x5C, /* Write RGB LED Max Current */ + WR_DSI_HS_CLK = 0xBD, /* Write DSI HS Clock */ + RD_DEVICE_ID = 0xD4, /* Read Controller Device ID */ + WR_DSI_PORT_EN = 0xD7, /* Write DSI Port Enable */ +}; + +enum input_source { + INPUT_EXTERNAL_VIDEO = 0, + INPUT_TEST_PATTERN, + INPUT_SPLASH_SCREEN, +}; + +#define DEV_ID_MASK GENMASK(3, 0) +#define IMAGE_FREESE_EN BIT(0) +#define DSI_PORT_EN 0 +#define EXT_SOURCE_FMT_DSI 0 +#define RED_LED_EN BIT(0) +#define GREEN_LED_EN BIT(1) +#define BLUE_LED_EN BIT(2) +#define LED_MASK GENMASK(2, 0) +#define MAX_BYTE_SIZE 8 + +struct dlpc { + struct device *dev; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct device_node *host_node; + struct mipi_dsi_device *dsi; + struct drm_display_mode mode; + + struct gpio_desc *enable_gpio; + struct regulator *vcc_intf; + struct regulator *vcc_flsh; + struct regmap *regmap; + unsigned int dsi_lanes; +}; + +static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge) +{ + return container_of(bridge, struct dlpc, bridge); +} + +static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WR_IMAGE_CROP: + case WR_DISPLAY_SIZE: + case WR_INPUT_IMAGE_SIZE: + case WR_DSI_HS_CLK: + return true; + default: + return false; + } +} + +static const struct regmap_range dlpc_volatile_ranges[] = { + { .range_min = 0x10, .range_max = 0xBF }, +}; + +static const struct regmap_access_table dlpc_volatile_table = { + .yes_ranges = dlpc_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges), +}; + +static struct regmap_config dlpc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = WR_DSI_PORT_EN, + .writeable_noinc_reg = dlpc_writeable_noinc_reg, + .volatile_table = &dlpc_volatile_table, + .cache_type = REGCACHE_RBTREE, + .name = "dlpc3433", +}; + +static void dlpc_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct dlpc *dlpc = bridge_to_dlpc(bridge); + struct device *dev = dlpc->dev; + struct drm_display_mode *mode = &dlpc->mode; + struct regmap *regmap = dlpc->regmap; + char buf[MAX_BYTE_SIZE]; + unsigned int devid; + + regmap_read(regmap, RD_DEVICE_ID, &devid); + devid &= DEV_ID_MASK; + + DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid); + + if (devid != 0x01) { + DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid); + return; + } + + /* disable image freeze */ + regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN); + + /* enable DSI port */ + regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN); + + memset(buf, 0, MAX_BYTE_SIZE); + + /* set image crop */ + buf[4] = mode->hdisplay & 0xff; + buf[5] = (mode->hdisplay & 0xff00) >> 8; + buf[6] = mode->vdisplay & 0xff; + buf[7] = (mode->vdisplay & 0xff00) >> 8; + regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE); + + /* set display size */ + buf[4] = mode->hdisplay & 0xff; + buf[5] = (mode->hdisplay & 0xff00) >> 8; + buf[6] = mode->vdisplay & 0xff; + buf[7] = (mode->vdisplay & 0xff00) >> 8; + regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE); + + /* set input image size */ + buf[0] = mode->hdisplay & 0xff; + buf[1] = (mode->hdisplay & 0xff00) >> 8; + buf[2] = mode->vdisplay & 0xff; + buf[3] = (mode->vdisplay & 0xff00) >> 8; + regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4); + + /* set external video port */ + regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO); + + /* set external video format select as DSI */ + regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI); + + /* disable image freeze */ + regmap_write(regmap, WR_IMAGE_FREEZE, 0x00); + + /* enable RGB led */ + regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK, + RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN); + + msleep(10); +} + +static void dlpc_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct dlpc *dlpc = bridge_to_dlpc(bridge); + int ret; + + gpiod_set_value(dlpc->enable_gpio, 1); + + msleep(500); + + ret = regulator_enable(dlpc->vcc_intf); + if (ret) + DRM_DEV_ERROR(dlpc->dev, + "failed to enable VCC_INTF regulator: %d\n", ret); + + ret = regulator_enable(dlpc->vcc_flsh); + if (ret) + DRM_DEV_ERROR(dlpc->dev, + "failed to enable VCC_FLSH regulator: %d\n", ret); + + msleep(10); +} + +static void dlpc_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) +{ + struct dlpc *dlpc = bridge_to_dlpc(bridge); + + regulator_disable(dlpc->vcc_flsh); + regulator_disable(dlpc->vcc_intf); + + msleep(10); + + gpiod_set_value(dlpc->enable_gpio, 0); + + msleep(500); +} + +#define MAX_INPUT_SEL_FORMATS 1 + +static u32 * +dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts; + + *num_input_fmts = 0; + + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + /* This is the DSI-end bus format */ + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; + *num_input_fmts = 1; + + return input_fmts; +} + +static void dlpc_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct dlpc *dlpc = bridge_to_dlpc(bridge); + + drm_mode_copy(&dlpc->mode, adjusted_mode); +} + +static int dlpc_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct dlpc *dlpc = bridge_to_dlpc(bridge); + + return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags); +} + +static const struct drm_bridge_funcs dlpc_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_get_input_bus_fmts = dlpc_atomic_get_input_bus_fmts, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_pre_enable = dlpc_atomic_pre_enable, + .atomic_enable = dlpc_atomic_enable, + .atomic_post_disable = dlpc_atomic_post_disable, + .mode_set = dlpc_mode_set, + .attach = dlpc_attach, +}; + +static int dlpc3433_parse_dt(struct dlpc *dlpc) +{ + struct device *dev = dlpc->dev; + struct device_node *endpoint; + int ret; + + dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(dlpc->enable_gpio)) + return PTR_ERR(dlpc->enable_gpio); + + dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf"); + if (IS_ERR(dlpc->vcc_intf)) + return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf), + "failed to get VCC_INTF supply\n"); + + dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh"); + if (IS_ERR(dlpc->vcc_flsh)) + return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh), + "failed to get VCC_FLSH supply\n"); + + dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + if (IS_ERR(dlpc->next_bridge)) + return PTR_ERR(dlpc->next_bridge); + + endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); + dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); + if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) { + ret = -EINVAL; + goto err_put_endpoint; + } + + dlpc->host_node = of_graph_get_remote_port_parent(endpoint); + if (!dlpc->host_node) { + ret = -ENODEV; + goto err_put_host; + } + + of_node_put(endpoint); + + return 0; + +err_put_host: + of_node_put(dlpc->host_node); +err_put_endpoint: + of_node_put(endpoint); + return ret; +} + +static int dlpc_host_attach(struct dlpc *dlpc) +{ + struct device *dev = dlpc->dev; + struct mipi_dsi_host *host; + struct mipi_dsi_device_info info = { + .type = "dlpc3433", + .channel = 0, + .node = NULL, + }; + + host = of_find_mipi_dsi_host_by_node(dlpc->host_node); + if (!host) { + DRM_DEV_ERROR(dev, "failed to find dsi host\n"); + return -EPROBE_DEFER; + } + + dlpc->dsi = mipi_dsi_device_register_full(host, &info); + if (IS_ERR(dlpc->dsi)) { + DRM_DEV_ERROR(dev, "failed to create dsi device\n"); + return PTR_ERR(dlpc->dsi); + } + + dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; + dlpc->dsi->format = MIPI_DSI_FMT_RGB565; + dlpc->dsi->lanes = dlpc->dsi_lanes; + + return devm_mipi_dsi_attach(dev, dlpc->dsi); +} + +static int dlpc3433_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct dlpc *dlpc; + int ret; + + dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL); + if (!dlpc) + return -ENOMEM; + + dlpc->dev = dev; + + dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config); + if (IS_ERR(dlpc->regmap)) + return PTR_ERR(dlpc->regmap); + + ret = dlpc3433_parse_dt(dlpc); + if (ret) + return ret; + + dev_set_drvdata(dev, dlpc); + i2c_set_clientdata(client, dlpc); + + dlpc->bridge.funcs = &dlpc_bridge_funcs; + dlpc->bridge.of_node = dev->of_node; + drm_bridge_add(&dlpc->bridge); + + ret = dlpc_host_attach(dlpc); + if (ret) { + DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); + goto err_remove_bridge; + } + + return 0; + +err_remove_bridge: + drm_bridge_remove(&dlpc->bridge); + return ret; +} + +static int dlpc3433_remove(struct i2c_client *client) +{ + struct dlpc *dlpc = i2c_get_clientdata(client); + + drm_bridge_remove(&dlpc->bridge); + of_node_put(dlpc->host_node); + + return 0; +} + +static const struct i2c_device_id dlpc3433_id[] = { + { "ti,dlpc3433", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, dlpc3433_id); + +static const struct of_device_id dlpc3433_match_table[] = { + { .compatible = "ti,dlpc3433" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dlpc3433_match_table); + +static struct i2c_driver dlpc3433_driver = { + .probe_new = dlpc3433_probe, + .remove = dlpc3433_remove, + .id_table = dlpc3433_id, + .driver = { + .name = "ti-dlpc3433", + .of_match_table = dlpc3433_match_table, + }, +}; +module_i2c_driver(dlpc3433_driver); + +MODULE_AUTHOR("Jagan Teki "); +MODULE_AUTHOR("Christopher Vollo "); +MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge"); +MODULE_LICENSE("GPL"); From fae7d186403ee5a9375ec75938e0de99718e066a Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 1 Jun 2022 11:23:24 -0700 Subject: [PATCH 157/170] drm/probe-helper: Default to 640x480 if no EDID on DP If we're unable to read the EDID for a display because it's corrupt / bogus / invalid then we'll add a set of standard modes for the display. Since we have no true information about the connected display, these modes are essentially guesses but better than nothing. At the moment, none of the modes returned is marked as preferred, but the modes are sorted such that the higher resolution modes are listed first. When userspace sees these modes presented by the kernel it needs to figure out which one to pick. At least one userspace, ChromeOS [1] seems to use the rules (which seem pretty reasonable): 1. Try to pick the first mode marked as preferred. 2. Try to pick the mode which matches the first detailed timing descriptor in the EDID. 3. If no modes were marked as preferred then pick the first mode. Unfortunately, userspace's rules combined with what the kernel is doing causes us to fail section 4.2.2.6 (EDID Corruption Detection) of the DP 1.4a Link CTS. That test case says that, while it's OK to allow some implementation-specific fall-back modes if the EDID is bad that userspace should _default_ to 640x480. Let's fix this by marking 640x480 as default for DP in the no-EDID case. NOTES: - In the discussion around v3 of this patch [2] there was talk about solving this in userspace and I even implemented a patch that would have solved this for ChromeOS, but then the discussion turned back to solving this in the kernel. - Also in the discussion of v3 [2] it was requested to limit this change to just DP since folks were worried that it would break some subtle corner case on VGA or HDMI. [1] https://source.chromium.org/chromium/chromium/src/+/a051f741d0a15caff2251301efe081c30e0f4a96:ui/ozone/platform/drm/common/drm_util.cc;l=488 [2] https://lore.kernel.org/r/20220513130533.v3.1.I31ec454f8d4ffce51a7708a8092f8a6f9c929092@changeid Signed-off-by: Douglas Anderson Reviewed-by: Abhinav Kumar Reviewed-by: Dmitry Baryshkov Acked-by: Jani Nikula Reviewed-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220601112302.v4.1.I31ec454f8d4ffce51a7708a8092f8a6f9c929092@changeid --- drivers/gpu/drm/drm_probe_helper.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 425f56280d51..75a71649b64d 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -569,8 +569,17 @@ retry: count = drm_add_override_edid_modes(connector); if (count == 0 && (connector->status == connector_status_connected || - connector->status == connector_status_unknown)) + connector->status == connector_status_unknown)) { count = drm_add_modes_noedid(connector, 1024, 768); + + /* + * Section 4.2.2.6 (EDID Corruption Detection) of the DP 1.4a + * Link CTS specifies that 640x480 (the official "failsafe" + * mode) needs to be the default if there's no EDID. + */ + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + drm_set_preferred_mode(connector, 640, 480); + } count += drm_helper_probe_add_cmdline_mode(connector); if (count != 0) { ret = __drm_helper_update_and_validate(connector, maxX, maxY, &ctx); From 73f54d5d968264148ef81941d9dc07e35025a120 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:13 +0200 Subject: [PATCH 158/170] drm/mgag200: Remove special case for G200SE with <2 MiB Remove old test for 32-bit vs 16-bit colors. Prefer 24-bit color depth on all devices. 32-bit color depth doesn't exist, it should have always been 24-bit. G200SE with less than 2 MiB of video memory have defaulted to 16-bit color depth, as the original revision of the G200SE had only 1.75 MiB of video memory. Using 16-bit colors enabled XGA resolution. But we now already limit these devices to VGA resolutions as the memory-bandwith test assumes 32-bit pixel size. So drop the special case from color-depth selection. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-2-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 028c6ba7124c..8cb72e11a2ea 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1072,14 +1072,6 @@ static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -static unsigned int mgag200_preferred_depth(struct mga_device *mdev) -{ - if (IS_G200_SE(mdev) && mdev->vram_fb_available < (2048*1024)) - return 16; - else - return 32; -} - int mgag200_modeset_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; @@ -1100,11 +1092,8 @@ int mgag200_modeset_init(struct mga_device *mdev) dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; - - dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev); - + dev->mode_config.preferred_depth = 24; dev->mode_config.fb_base = mdev->mc.vram_base; - dev->mode_config.funcs = &mgag200_mode_config_funcs; ret = mgag200_i2c_init(mdev, i2c); From 85397f6bc4ff13a6bc5259facb8ebebb1986d666 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:14 +0200 Subject: [PATCH 159/170] drm/mgag200: Initialize each model in separate function Add a separate initializer function for each model. Add separate devic structures for G200 and G200SE, which require additional information. Also move G200's and G200SE's helpers for reading the BIOS and version id into model-specific code. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-3-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/Makefile | 15 +- drivers/gpu/drm/mgag200/mgag200_drv.c | 206 ++++------------------ drivers/gpu/drm/mgag200/mgag200_drv.h | 59 +++++-- drivers/gpu/drm/mgag200/mgag200_g200.c | 170 ++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_g200eh.c | 43 +++++ drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 44 +++++ drivers/gpu/drm/mgag200/mgag200_g200er.c | 43 +++++ drivers/gpu/drm/mgag200/mgag200_g200ev.c | 43 +++++ drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 44 +++++ drivers/gpu/drm/mgag200/mgag200_g200se.c | 58 ++++++ drivers/gpu/drm/mgag200/mgag200_g200wb.c | 43 +++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 25 +-- drivers/gpu/drm/mgag200/mgag200_pll.c | 12 +- 13 files changed, 603 insertions(+), 202 deletions(-) create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200eh.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200eh3.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200er.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200ev.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200ew3.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200se.c create mode 100644 drivers/gpu/drm/mgag200/mgag200_g200wb.c diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile index d4f766522483..0c515a3b073d 100644 --- a/drivers/gpu/drm/mgag200/Makefile +++ b/drivers/gpu/drm/mgag200/Makefile @@ -1,4 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-only -mgag200-y := mgag200_drv.o mgag200_i2c.o mgag200_mm.o mgag200_mode.o mgag200_pll.o +mgag200-y := \ + mgag200_drv.o \ + mgag200_g200.o \ + mgag200_g200eh.o \ + mgag200_g200eh3.o \ + mgag200_g200er.o \ + mgag200_g200ev.o \ + mgag200_g200ew3.o \ + mgag200_g200se.o \ + mgag200_g200wb.o \ + mgag200_i2c.o \ + mgag200_mm.o \ + mgag200_mode.o \ + mgag200_pll.o obj-$(CONFIG_DRM_MGAG200) += mgag200.o diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 08839460606f..e5f06f44ec90 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -60,7 +60,7 @@ static bool mgag200_has_sgram(struct mga_device *mdev) return !!(option & PCI_MGA_OPTION_HARDPWMSK); } -static int mgag200_regs_init(struct mga_device *mdev) +int mgag200_regs_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; struct pci_dev *pdev = to_pci_dev(dev->dev); @@ -133,178 +133,6 @@ static int mgag200_regs_init(struct mga_device *mdev) return 0; } -static void mgag200_g200_interpret_bios(struct mga_device *mdev, - const unsigned char *bios, - size_t size) -{ - static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'}; - static const unsigned int expected_length[6] = { - 0, 64, 64, 64, 128, 128 - }; - struct drm_device *dev = &mdev->base; - const unsigned char *pins; - unsigned int pins_len, version; - int offset; - int tmp; - - /* Test for MATROX string. */ - if (size < 45 + sizeof(matrox)) - return; - if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0) - return; - - /* Get the PInS offset. */ - if (size < MGA_BIOS_OFFSET + 2) - return; - offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; - - /* Get PInS data structure. */ - - if (size < offset + 6) - return; - pins = bios + offset; - if (pins[0] == 0x2e && pins[1] == 0x41) { - version = pins[5]; - pins_len = pins[2]; - } else { - version = 1; - pins_len = pins[0] + (pins[1] << 8); - } - - if (version < 1 || version > 5) { - drm_warn(dev, "Unknown BIOS PInS version: %d\n", version); - return; - } - if (pins_len != expected_length[version]) { - drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n", - pins_len, expected_length[version]); - return; - } - if (size < offset + pins_len) - return; - - drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", - version, pins_len); - - /* Extract the clock values */ - - switch (version) { - case 1: - tmp = pins[24] + (pins[25] << 8); - if (tmp) - mdev->model.g200.pclk_max = tmp * 10; - break; - case 2: - if (pins[41] != 0xff) - mdev->model.g200.pclk_max = (pins[41] + 100) * 1000; - break; - case 3: - if (pins[36] != 0xff) - mdev->model.g200.pclk_max = (pins[36] + 100) * 1000; - if (pins[52] & 0x20) - mdev->model.g200.ref_clk = 14318; - break; - case 4: - if (pins[39] != 0xff) - mdev->model.g200.pclk_max = pins[39] * 4 * 1000; - if (pins[92] & 0x01) - mdev->model.g200.ref_clk = 14318; - break; - case 5: - tmp = pins[4] ? 8000 : 6000; - if (pins[123] != 0xff) - mdev->model.g200.pclk_min = pins[123] * tmp; - if (pins[38] != 0xff) - mdev->model.g200.pclk_max = pins[38] * tmp; - if (pins[110] & 0x01) - mdev->model.g200.ref_clk = 14318; - break; - default: - break; - } -} - -static void mgag200_g200_init_refclk(struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - unsigned char __iomem *rom; - unsigned char *bios; - size_t size; - - mdev->model.g200.pclk_min = 50000; - mdev->model.g200.pclk_max = 230000; - mdev->model.g200.ref_clk = 27050; - - rom = pci_map_rom(pdev, &size); - if (!rom) - return; - - bios = vmalloc(size); - if (!bios) - goto out; - memcpy_fromio(bios, rom, size); - - if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) - mgag200_g200_interpret_bios(mdev, bios, size); - - drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", - mdev->model.g200.pclk_min, mdev->model.g200.pclk_max, - mdev->model.g200.ref_clk); - - vfree(bios); -out: - pci_unmap_rom(pdev, rom); -} - -static void mgag200_g200se_init_unique_id(struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - - /* stash G200 SE model number for later use */ - mdev->model.g200se.unique_rev_id = RREG32(0x1e24); - - drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", - mdev->model.g200se.unique_rev_id); -} - -static struct mga_device * -mgag200_device_create(struct pci_dev *pdev, enum mga_type type, unsigned long flags) -{ - struct mga_device *mdev; - struct drm_device *dev; - int ret; - - mdev = devm_drm_dev_alloc(&pdev->dev, &mgag200_driver, struct mga_device, base); - if (IS_ERR(mdev)) - return mdev; - dev = &mdev->base; - - pci_set_drvdata(pdev, dev); - - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); - if (ret) - return ERR_PTR(ret); - - if (mdev->type == G200_PCI || mdev->type == G200_AGP) - mgag200_g200_init_refclk(mdev); - else if (IS_G200_SE(mdev)) - mgag200_g200se_init_unique_id(mdev); - - ret = mgag200_mm_init(mdev); - if (ret) - return ERR_PTR(ret); - - ret = mgag200_modeset_init(mdev); - if (ret) - return ERR_PTR(ret); - - return mdev; -} - /* * PCI driver */ @@ -354,7 +182,37 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - mdev = mgag200_device_create(pdev, type, flags); + switch (type) { + case G200_PCI: + case G200_AGP: + mdev = mgag200_g200_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_SE_A: + case G200_SE_B: + mdev = mgag200_g200se_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_WB: + mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_EV: + mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_EH: + mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_EH3: + mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_ER: + mdev = mgag200_g200er_device_create(pdev, &mgag200_driver, type, flags); + break; + case G200_EW3: + mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver, type, flags); + break; + default: + dev_err(&pdev->dev, "Device type %d is unsupported\n", type); + return -ENODEV; + } if (IS_ERR(mdev)) return PTR_ERR(mdev); dev = &mdev->base; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 5634fc003ca4..99a9446b7df5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -218,18 +218,6 @@ struct mga_device { enum mga_type type; - union { - struct { - long ref_clk; - long pclk_min; - long pclk_max; - } g200; - struct { - /* SE model number stored in reg 0x1e24 */ - u32 unique_rev_id; - } g200se; - } model; - struct mgag200_pll pixpll; struct mga_i2c_chan i2c; struct drm_connector connector; @@ -241,6 +229,53 @@ static inline struct mga_device *to_mga_device(struct drm_device *dev) return container_of(dev, struct mga_device, base); } +struct mgag200_g200_device { + struct mga_device base; + + /* PLL constants */ + long ref_clk; + long pclk_min; + long pclk_max; +}; + +static inline struct mgag200_g200_device *to_mgag200_g200_device(struct drm_device *dev) +{ + return container_of(to_mga_device(dev), struct mgag200_g200_device, base); +} + +struct mgag200_g200se_device { + struct mga_device base; + + /* SE model number stored in reg 0x1e24 */ + u32 unique_rev_id; +}; + +static inline struct mgag200_g200se_device *to_mgag200_g200se_device(struct drm_device *dev) +{ + return container_of(to_mga_device(dev), struct mgag200_g200se_device, base); +} + + /* mgag200_drv.c */ +int mgag200_regs_init(struct mga_device *mdev); + + /* mgag200_.c */ +struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); +struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags); + /* mgag200_mode.c */ int mgag200_modeset_init(struct mga_device *mdev); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c new file mode 100644 index 000000000000..ca9522daf6e1 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM Device + */ + +static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, + const unsigned char *bios, size_t size) +{ + static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'}; + static const unsigned int expected_length[6] = { + 0, 64, 64, 64, 128, 128 + }; + struct mga_device *mdev = &g200->base; + struct drm_device *dev = &mdev->base; + const unsigned char *pins; + unsigned int pins_len, version; + int offset; + int tmp; + + /* Test for MATROX string. */ + if (size < 45 + sizeof(matrox)) + return; + if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0) + return; + + /* Get the PInS offset. */ + if (size < MGA_BIOS_OFFSET + 2) + return; + offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; + + /* Get PInS data structure. */ + + if (size < offset + 6) + return; + pins = bios + offset; + if (pins[0] == 0x2e && pins[1] == 0x41) { + version = pins[5]; + pins_len = pins[2]; + } else { + version = 1; + pins_len = pins[0] + (pins[1] << 8); + } + + if (version < 1 || version > 5) { + drm_warn(dev, "Unknown BIOS PInS version: %d\n", version); + return; + } + if (pins_len != expected_length[version]) { + drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n", + pins_len, expected_length[version]); + return; + } + if (size < offset + pins_len) + return; + + drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", version, pins_len); + + /* Extract the clock values */ + + switch (version) { + case 1: + tmp = pins[24] + (pins[25] << 8); + if (tmp) + g200->pclk_max = tmp * 10; + break; + case 2: + if (pins[41] != 0xff) + g200->pclk_max = (pins[41] + 100) * 1000; + break; + case 3: + if (pins[36] != 0xff) + g200->pclk_max = (pins[36] + 100) * 1000; + if (pins[52] & 0x20) + g200->ref_clk = 14318; + break; + case 4: + if (pins[39] != 0xff) + g200->pclk_max = pins[39] * 4 * 1000; + if (pins[92] & 0x01) + g200->ref_clk = 14318; + break; + case 5: + tmp = pins[4] ? 8000 : 6000; + if (pins[123] != 0xff) + g200->pclk_min = pins[123] * tmp; + if (pins[38] != 0xff) + g200->pclk_max = pins[38] * tmp; + if (pins[110] & 0x01) + g200->ref_clk = 14318; + break; + default: + break; + } +} + +static void mgag200_g200_init_refclk(struct mgag200_g200_device *g200) +{ + struct mga_device *mdev = &g200->base; + struct drm_device *dev = &mdev->base; + struct pci_dev *pdev = to_pci_dev(dev->dev); + unsigned char __iomem *rom; + unsigned char *bios; + size_t size; + + g200->pclk_min = 50000; + g200->pclk_max = 230000; + g200->ref_clk = 27050; + + rom = pci_map_rom(pdev, &size); + if (!rom) + return; + + bios = vmalloc(size); + if (!bios) + goto out; + memcpy_fromio(bios, rom, size); + + if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) + mgag200_g200_interpret_bios(g200, bios, size); + + drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", + g200->pclk_min, g200->pclk_max, g200->ref_clk); + + vfree(bios); +out: + pci_unmap_rom(pdev, rom); +} + +struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mgag200_g200_device *g200; + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + g200 = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200_device, base.base); + if (IS_ERR(g200)) + return ERR_CAST(g200); + mdev = &g200->base; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + mgag200_g200_init_refclk(g200); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c new file mode 100644 index 000000000000..67c7c75ea791 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c new file mode 100644 index 000000000000..b7a3f9551bfd --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c new file mode 100644 index 000000000000..1c5e757ec016 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c new file mode 100644 index 000000000000..f8afd05913fd --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c new file mode 100644 index 000000000000..f65bb94e0b3d --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c new file mode 100644 index 000000000000..d809cc680024 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) +{ + struct mga_device *mdev = &g200se->base; + struct drm_device *dev = &mdev->base; + + /* stash G200 SE model number for later use */ + g200se->unique_rev_id = RREG32(0x1e24); + + drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id); +} + +struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mgag200_g200se_device *g200se; + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base); + if (IS_ERR(g200se)) + return ERR_CAST(g200se); + mdev = &g200se->base; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + mgag200_g200se_init_unique_id(g200se); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c new file mode 100644 index 000000000000..67b28646386d --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include + +#include + +#include "mgag200_drv.h" + +/* + * DRM device + */ + +struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, + enum mga_type type, unsigned long flags) +{ + struct mga_device *mdev; + struct drm_device *dev; + int ret; + + mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); + if (IS_ERR(mdev)) + return mdev; + dev = &mdev->base; + + pci_set_drvdata(pdev, dev); + + mdev->flags = flags; + mdev->type = type; + + ret = mgag200_regs_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_mm_init(mdev); + if (ret) + return ERR_PTR(ret); + + ret = mgag200_modeset_init(mdev); + if (ret) + return ERR_PTR(ret); + + return mdev; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 8cb72e11a2ea..2b034255a4af 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -583,13 +583,13 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, const struct drm_display_mode *mode, const struct drm_framebuffer *fb) { - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base); unsigned int hiprilvl; u8 crtcext6; - if (unique_rev_id >= 0x04) { + if (g200se->unique_rev_id >= 0x04) { hiprilvl = 0; - } else if (unique_rev_id >= 0x02) { + } else if (g200se->unique_rev_id >= 0x02) { unsigned int bpp; unsigned long mb; @@ -614,7 +614,7 @@ static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, else hiprilvl = 5; - } else if (unique_rev_id >= 0x01) { + } else if (g200se->unique_rev_id >= 0x01) { hiprilvl = 3; } else { hiprilvl = 4; @@ -725,17 +725,19 @@ static enum drm_mode_status mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, const struct drm_display_mode *mode) { - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); + struct drm_device *dev = pipe->crtc.dev; + struct mga_device *mdev = to_mga_device(dev); + struct mgag200_g200se_device *g200se; if (IS_G200_SE(mdev)) { - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + g200se = to_mgag200_g200se_device(dev); - if (unique_rev_id == 0x01) { + if (g200se->unique_rev_id == 0x01) { if (mode->hdisplay > 1600) return MODE_VIRTUAL_X; if (mode->vdisplay > 1200) return MODE_VIRTUAL_Y; - } else if (unique_rev_id == 0x02) { + } else if (g200se->unique_rev_id == 0x02) { if (mode->hdisplay > 1920) return MODE_VIRTUAL_X; if (mode->vdisplay > 1200) @@ -1026,6 +1028,7 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888 struct mga_device *mdev = to_mga_device(dev); unsigned long fbsize, fbpages, max_fbpages; + struct mgag200_g200se_device *g200se; max_fbpages = mdev->vram_fb_available >> PAGE_SHIFT; @@ -1036,12 +1039,12 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de return MODE_MEM; if (IS_G200_SE(mdev)) { - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + g200se = to_mgag200_g200se_device(dev); - if (unique_rev_id == 0x01) { + if (g200se->unique_rev_id == 0x01) { if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (24400 * 1024)) return MODE_BAD; - } else if (unique_rev_id == 0x02) { + } else if (g200se->unique_rev_id == 0x02) { if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (30100 * 1024)) return MODE_BAD; } else { diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c index 52be08b744ad..8065ca5d8de9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_pll.c +++ b/drivers/gpu/drm/mgag200/mgag200_pll.c @@ -13,6 +13,7 @@ static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock, { struct mga_device *mdev = pixpll->mdev; struct drm_device *dev = &mdev->base; + struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev); const int post_div_max = 7; const int in_div_min = 1; const int in_div_max = 6; @@ -23,9 +24,9 @@ static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock, long f_vco; long computed; long delta, tmp_delta; - long ref_clk = mdev->model.g200.ref_clk; - long p_clk_min = mdev->model.g200.pclk_min; - long p_clk_max = mdev->model.g200.pclk_max; + long ref_clk = g200->ref_clk; + long p_clk_min = g200->pclk_min; + long p_clk_max = g200->pclk_max; if (clock > p_clk_max) { drm_err(dev, "Pixel Clock %ld too high\n", clock); @@ -951,6 +952,7 @@ static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = { int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev) { struct drm_device *dev = &mdev->base; + struct mgag200_g200se_device *g200se; pixpll->mdev = mdev; @@ -961,7 +963,9 @@ int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev) break; case G200_SE_A: case G200_SE_B: - if (mdev->model.g200se.unique_rev_id >= 0x04) + g200se = to_mgag200_g200se_device(dev); + + if (g200se->unique_rev_id >= 0x04) pixpll->funcs = &mgag200_pixpll_funcs_g200se_04; else pixpll->funcs = &mgag200_pixpll_funcs_g200se_00; From ce19021fd99ab2c915f2b44b0df39bef75f11d18 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:15 +0200 Subject: [PATCH 160/170] drm/mgag200: Move PCI-option setup into model-specific code Split the PCI code into a single call for each model. G200 and G200SE each contain a dedicated helper with additional instructions. Noteably, the G200ER has no code for PCI setup. In a later patch, the magic numbers should be replaced by descriptive constants. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-4-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.c | 81 ++++++++--------------- drivers/gpu/drm/mgag200/mgag200_drv.h | 1 + drivers/gpu/drm/mgag200/mgag200_g200.c | 27 ++++++++ drivers/gpu/drm/mgag200/mgag200_g200eh.c | 4 ++ drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 4 ++ drivers/gpu/drm/mgag200/mgag200_g200ev.c | 4 ++ drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 4 ++ drivers/gpu/drm/mgag200/mgag200_g200se.c | 26 ++++++++ drivers/gpu/drm/mgag200/mgag200_g200wb.c | 4 ++ 9 files changed, 100 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index e5f06f44ec90..ea765c1abcc1 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -24,6 +24,32 @@ int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) +{ + struct device *dev = &pdev->dev; + int err; + + err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); + if (err != PCIBIOS_SUCCESSFUL) { + dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err); + return pcibios_err_to_errno(err); + } + + err = pci_write_config_dword(pdev, PCI_MGA_OPTION, option); + if (err != PCIBIOS_SUCCESSFUL) { + dev_err(dev, "pci_write_config_dword(PCI_MGA_OPTION) failed: %d\n", err); + return pcibios_err_to_errno(err); + } + + err = pci_write_config_dword(pdev, PCI_MGA_OPTION2, option2); + if (err != PCIBIOS_SUCCESSFUL) { + dev_err(dev, "pci_write_config_dword(PCI_MGA_OPTION2) failed: %d\n", err); + return pcibios_err_to_errno(err); + } + + return 0; +} + /* * DRM driver */ @@ -46,25 +72,10 @@ static const struct drm_driver mgag200_driver = { * DRM device */ -static bool mgag200_has_sgram(struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - u32 option; - int ret; - - ret = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); - if (drm_WARN(dev, ret, "failed to read PCI config dword: %d\n", ret)) - return false; - - return !!(option & PCI_MGA_OPTION_HARDPWMSK); -} - int mgag200_regs_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; struct pci_dev *pdev = to_pci_dev(dev->dev); - u32 option, option2; u8 crtcext3; int ret; @@ -72,46 +83,6 @@ int mgag200_regs_init(struct mga_device *mdev) if (ret) return ret; - switch (mdev->type) { - case G200_PCI: - case G200_AGP: - if (mgag200_has_sgram(mdev)) - option = 0x4049cd21; - else - option = 0x40499121; - option2 = 0x00008000; - break; - case G200_SE_A: - case G200_SE_B: - option = 0x40049120; - if (mgag200_has_sgram(mdev)) - option |= PCI_MGA_OPTION_HARDPWMSK; - option2 = 0x00008000; - break; - case G200_WB: - case G200_EW3: - option = 0x41049120; - option2 = 0x0000b000; - break; - case G200_EV: - option = 0x00000120; - option2 = 0x0000b000; - break; - case G200_EH: - case G200_EH3: - option = 0x00000120; - option2 = 0x0000b000; - break; - default: - option = 0; - option2 = 0; - } - - if (option) - pci_write_config_dword(pdev, PCI_MGA_OPTION, option); - if (option2) - pci_write_config_dword(pdev, PCI_MGA_OPTION2, option2); - /* BAR 1 contains registers */ mdev->rmmio_base = pci_resource_start(pdev, 1); mdev->rmmio_size = pci_resource_len(pdev, 1); diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 99a9446b7df5..d188382d60ca 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -256,6 +256,7 @@ static inline struct mgag200_g200se_device *to_mgag200_g200se_device(struct drm_ } /* mgag200_drv.c */ +int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); int mgag200_regs_init(struct mga_device *mdev); /* mgag200_.c */ diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index ca9522daf6e1..b9ec6367719c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -6,6 +6,29 @@ #include "mgag200_drv.h" +static int mgag200_g200_init_pci_options(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + bool has_sgram; + u32 option; + int err; + + err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); + if (err != PCIBIOS_SUCCESSFUL) { + dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err); + return pcibios_err_to_errno(err); + } + + has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK); + + if (has_sgram) + option = 0x4049cd21; + else + option = 0x40499121; + + return mgag200_init_pci_options(pdev, option, 0x00008000); +} + /* * DRM Device */ @@ -149,6 +172,10 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct pci_set_drvdata(pdev, dev); + ret = mgag200_g200_init_pci_options(pdev); + if (ret) + return ERR_PTR(ret); + mdev->flags = flags; mdev->type = type; diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 67c7c75ea791..3a531148c523 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -27,6 +27,10 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru mdev->flags = flags; mdev->type = type; + ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); + if (ret) + return ERR_PTR(ret); + ret = mgag200_regs_init(mdev); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index b7a3f9551bfd..fbb53e624d90 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -28,6 +28,10 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, mdev->flags = flags; mdev->type = type; + ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); + if (ret) + return ERR_PTR(ret); + ret = mgag200_regs_init(mdev); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index f8afd05913fd..e55dd01ed42e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -24,6 +24,10 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru pci_set_drvdata(pdev, dev); + ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); + if (ret) + return ERR_PTR(ret); + mdev->flags = flags; mdev->type = type; diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index f65bb94e0b3d..6dd62135f0b2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -25,6 +25,10 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); + ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000); + if (ret) + return ERR_PTR(ret); + mdev->flags = flags; mdev->type = type; diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index d809cc680024..75d284abb2a2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -6,6 +6,28 @@ #include "mgag200_drv.h" +static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + bool has_sgram; + u32 option; + int err; + + err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option); + if (err != PCIBIOS_SUCCESSFUL) { + dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err); + return pcibios_err_to_errno(err); + } + + has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK); + + option = 0x40049120; + if (has_sgram) + option |= PCI_MGA_OPTION_HARDPWMSK; + + return mgag200_init_pci_options(pdev, option, 0x00008000); +} + /* * DRM device */ @@ -37,6 +59,10 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru pci_set_drvdata(pdev, dev); + ret = mgag200_g200se_init_pci_options(pdev); + if (ret) + return ERR_PTR(ret); + mdev->flags = flags; mdev->type = type; diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 67b28646386d..c622d5418731 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -24,6 +24,10 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru pci_set_drvdata(pdev, dev); + ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000); + if (ret) + return ERR_PTR(ret); + mdev->flags = flags; mdev->type = type; From d45e32c9d98ce7c22a4bafe69cee58165b59533b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:16 +0200 Subject: [PATCH 161/170] drm/mgag200: Call mgag200_device_probe_vram() from per-model init Call mgag200_device_probe_vram() from each model's initializer. The G200EW3 uses a special helper with additional instructions. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-5-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.c | 39 +++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_drv.h | 6 ++- drivers/gpu/drm/mgag200/mgag200_g200.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200er.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 14 ++++++- drivers/gpu/drm/mgag200/mgag200_g200se.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 5 ++- drivers/gpu/drm/mgag200/mgag200_mm.c | 47 +---------------------- drivers/gpu/drm/mgag200/mgag200_mode.c | 11 +++++- 12 files changed, 94 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index ea765c1abcc1..1d53ddcc00df 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -50,6 +50,45 @@ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) return 0; } +resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size) +{ + int offset; + int orig; + int test1, test2; + int orig1, orig2; + size_t vram_size; + + /* Probe */ + orig = ioread16(mem); + iowrite16(0, mem); + + vram_size = size; + + for (offset = 0x100000; offset < vram_size; offset += 0x4000) { + orig1 = ioread8(mem + offset); + orig2 = ioread8(mem + offset + 0x100); + + iowrite16(0xaa55, mem + offset); + iowrite16(0xaa55, mem + offset + 0x100); + + test1 = ioread16(mem + offset); + test2 = ioread16(mem); + + iowrite16(orig1, mem + offset); + iowrite16(orig2, mem + offset + 0x100); + + if (test1 != 0xaa55) + break; + + if (test2) + break; + } + + iowrite16(orig, mem); + + return offset - 65536; +} + /* * DRM driver */ diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index d188382d60ca..21c7a689ed33 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -214,7 +214,7 @@ struct mga_device { struct mga_mc mc; void __iomem *vram; - size_t vram_fb_available; + resource_size_t vram_available; enum mga_type type; @@ -257,6 +257,7 @@ static inline struct mgag200_g200se_device *to_mgag200_g200se_device(struct drm_ /* mgag200_drv.c */ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); +resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size); int mgag200_regs_init(struct mga_device *mdev); /* mgag200_.c */ @@ -278,7 +279,8 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const str enum mga_type type, unsigned long flags); /* mgag200_mode.c */ -int mgag200_modeset_init(struct mga_device *mdev); +resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); +int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_available); /* mgag200_i2c.c */ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index b9ec6367719c..4e30b54a2677 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -162,6 +162,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct struct mgag200_g200_device *g200; struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; g200 = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200_device, base.base); @@ -189,7 +190,9 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 3a531148c523..a16493db0512 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -15,6 +15,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -39,7 +40,9 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index fbb53e624d90..478ca578b839 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -16,6 +16,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -40,7 +41,9 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 1c5e757ec016..2f38fb470f4e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -15,6 +15,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -35,7 +36,9 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index e55dd01ed42e..ff3c7b17ac44 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -15,6 +15,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -39,7 +40,9 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 6dd62135f0b2..971d40874cf3 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -10,12 +10,22 @@ * DRM device */ +static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) +{ + resource_size_t vram_size = mdev->mc.vram_size; + + if (vram_size >= 0x1000000) + vram_size = vram_size - 0x400000; + return mgag200_probe_vram(mdev->vram, vram_size); +} + struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -40,7 +50,9 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_g200ew3_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 75d284abb2a2..cd2987b58fcb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -49,6 +49,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru struct mgag200_g200se_device *g200se; struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; g200se = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200se_device, base.base); @@ -76,7 +77,9 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index c622d5418731..38e374c00419 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -15,6 +15,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru { struct mga_device *mdev; struct drm_device *dev; + resource_size_t vram_available; int ret; mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); @@ -39,7 +40,9 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_modeset_init(mdev); + vram_available = mgag200_device_probe_vram(mdev); + + ret = mgag200_modeset_init(mdev, vram_available); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_mm.c b/drivers/gpu/drm/mgag200/mgag200_mm.c index fa996d46feed..fc19c2369641 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mm.c +++ b/drivers/gpu/drm/mgag200/mgag200_mm.c @@ -32,49 +32,6 @@ #include "mgag200_drv.h" -static size_t mgag200_probe_vram(struct mga_device *mdev, void __iomem *mem, - size_t size) -{ - int offset; - int orig; - int test1, test2; - int orig1, orig2; - size_t vram_size; - - /* Probe */ - orig = ioread16(mem); - iowrite16(0, mem); - - vram_size = size; - - if ((mdev->type == G200_EW3) && (vram_size >= 0x1000000)) - vram_size = vram_size - 0x400000; - - for (offset = 0x100000; offset < vram_size; offset += 0x4000) { - orig1 = ioread8(mem + offset); - orig2 = ioread8(mem + offset + 0x100); - - iowrite16(0xaa55, mem + offset); - iowrite16(0xaa55, mem + offset + 0x100); - - test1 = ioread16(mem + offset); - test2 = ioread16(mem); - - iowrite16(orig1, mem + offset); - iowrite16(orig2, mem + offset + 0x100); - - if (test1 != 0xaa55) - break; - - if (test2) - break; - } - - iowrite16(orig, mem); - - return offset - 65536; -} - int mgag200_mm_init(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; @@ -106,11 +63,9 @@ int mgag200_mm_init(struct mga_device *mdev) if (!mdev->vram) return -ENOMEM; - mdev->mc.vram_size = mgag200_probe_vram(mdev, mdev->vram, len); + mdev->mc.vram_size = len; mdev->mc.vram_base = start; mdev->mc.vram_window = len; - mdev->vram_fb_available = mdev->mc.vram_size; - return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 2b034255a4af..c254988e5bcb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -32,6 +32,11 @@ * This file contains setup code for the CRTC. */ +resource_size_t mgag200_device_probe_vram(struct mga_device *mdev) +{ + return mgag200_probe_vram(mdev->vram, mdev->mc.vram_size); +} + static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, const struct drm_format_info *format) { @@ -1030,7 +1035,7 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de unsigned long fbsize, fbpages, max_fbpages; struct mgag200_g200se_device *g200se; - max_fbpages = mdev->vram_fb_available >> PAGE_SHIFT; + max_fbpages = mdev->vram_available >> PAGE_SHIFT; fbsize = mode->hdisplay * mode->vdisplay * max_bpp; fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); @@ -1075,7 +1080,7 @@ static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -int mgag200_modeset_init(struct mga_device *mdev) +int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available) { struct drm_device *dev = &mdev->base; struct mga_i2c_chan *i2c = &mdev->i2c; @@ -1086,6 +1091,8 @@ int mgag200_modeset_init(struct mga_device *mdev) mgag200_init_regs(mdev); + mdev->vram_available = vram_available; + ret = drmm_mode_config_init(dev); if (ret) { drm_err(dev, "drmm_mode_config_init() failed, error %d\n", From b62d943e9686e791dd39f8bde302fc27446cdca9 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:17 +0200 Subject: [PATCH 162/170] drm/mgag200: Implement new init logic Rework mgag200_regs_init() and mgag200_mm_init() into device preinit and init functions. The preinit function, mgag200_device_preinit(), requests and maps a device's I/O and video memory. The init function, mgag200_device_init() initializes the state of struct mga_device. Splitting the initialization between the two functions is necessary to perform per-model operations between the two calls, such as reading the unique revision ID on G200SEs. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-6-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/Makefile | 1 - drivers/gpu/drm/mgag200/mgag200_drv.c | 80 ++++++++++++++++++----- drivers/gpu/drm/mgag200/mgag200_drv.h | 21 ++---- drivers/gpu/drm/mgag200/mgag200_g200.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200er.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 9 +-- drivers/gpu/drm/mgag200/mgag200_g200se.c | 7 +- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 7 +- drivers/gpu/drm/mgag200/mgag200_mm.c | 71 -------------------- drivers/gpu/drm/mgag200/mgag200_mode.c | 7 +- 13 files changed, 89 insertions(+), 149 deletions(-) delete mode 100644 drivers/gpu/drm/mgag200/mgag200_mm.c diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile index 0c515a3b073d..89558549c3af 100644 --- a/drivers/gpu/drm/mgag200/Makefile +++ b/drivers/gpu/drm/mgag200/Makefile @@ -10,7 +10,6 @@ mgag200-y := \ mgag200_g200se.o \ mgag200_g200wb.o \ mgag200_i2c.o \ - mgag200_mm.o \ mgag200_mode.o \ mgag200_pll.o diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 1d53ddcc00df..8f636db4a723 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -111,35 +111,85 @@ static const struct drm_driver mgag200_driver = { * DRM device */ -int mgag200_regs_init(struct mga_device *mdev) +resource_size_t mgag200_device_probe_vram(struct mga_device *mdev) +{ + return mgag200_probe_vram(mdev->vram, resource_size(mdev->vram_res)); +} + +int mgag200_device_preinit(struct mga_device *mdev) { struct drm_device *dev = &mdev->base; struct pci_dev *pdev = to_pci_dev(dev->dev); - u8 crtcext3; + resource_size_t start, len; + struct resource *res; + + /* BAR 1 contains registers */ + + start = pci_resource_start(pdev, 1); + len = pci_resource_len(pdev, 1); + + res = devm_request_mem_region(dev->dev, start, len, "mgadrmfb_mmio"); + if (!res) { + drm_err(dev, "devm_request_mem_region(MMIO) failed\n"); + return -ENXIO; + } + mdev->rmmio_res = res; + + mdev->rmmio = pcim_iomap(pdev, 1, 0); + if (!mdev->rmmio) + return -ENOMEM; + + /* BAR 0 is VRAM */ + + start = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + + res = devm_request_mem_region(dev->dev, start, len, "mgadrmfb_vram"); + if (!res) { + drm_err(dev, "devm_request_mem_region(VRAM) failed\n"); + return -ENXIO; + } + mdev->vram_res = res; + + /* Don't fail on errors, but performance might be reduced. */ + devm_arch_io_reserve_memtype_wc(dev->dev, res->start, resource_size(res)); + devm_arch_phys_wc_add(dev->dev, res->start, resource_size(res)); + + mdev->vram = devm_ioremap(dev->dev, res->start, resource_size(res)); + if (!mdev->vram) + return -ENOMEM; + + return 0; +} + +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags) +{ + struct drm_device *dev = &mdev->base; + u8 crtcext3, misc; int ret; + mdev->flags = flags; + mdev->type = type; + ret = drmm_mutex_init(dev, &mdev->rmmio_lock); if (ret) return ret; - /* BAR 1 contains registers */ - mdev->rmmio_base = pci_resource_start(pdev, 1); - mdev->rmmio_size = pci_resource_len(pdev, 1); - - if (!devm_request_mem_region(dev->dev, mdev->rmmio_base, - mdev->rmmio_size, "mgadrmfb_mmio")) { - drm_err(dev, "can't reserve mmio registers\n"); - return -ENOMEM; - } - - mdev->rmmio = pcim_iomap(pdev, 1, 0); - if (mdev->rmmio == NULL) - return -ENOMEM; + mutex_lock(&mdev->rmmio_lock); RREG_ECRT(0x03, crtcext3); crtcext3 |= MGAREG_CRTCEXT3_MGAMODE; WREG_ECRT(0x03, crtcext3); + WREG_ECRT(0x04, 0x00); + + misc = RREG8(MGA_MISC_IN); + misc |= MGAREG_MISC_RAMMAPEN | + MGAREG_MISC_HIGH_PG_SEL; + WREG8(MGA_MISC_OUT, misc); + + mutex_unlock(&mdev->rmmio_lock); + return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 21c7a689ed33..9abecf366268 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -175,12 +175,6 @@ struct mga_i2c_chan { int data, clock; }; -struct mga_mc { - resource_size_t vram_size; - resource_size_t vram_base; - resource_size_t vram_window; -}; - enum mga_type { G200_PCI, G200_AGP, @@ -206,13 +200,11 @@ struct mga_device { struct drm_device base; unsigned long flags; - struct mutex rmmio_lock; /* Protects access to rmmio */ - resource_size_t rmmio_base; - resource_size_t rmmio_size; + struct resource *rmmio_res; void __iomem *rmmio; + struct mutex rmmio_lock; /* Protects access to rmmio */ - struct mga_mc mc; - + struct resource *vram_res; void __iomem *vram; resource_size_t vram_available; @@ -258,7 +250,9 @@ static inline struct mgag200_g200se_device *to_mgag200_g200se_device(struct drm_ /* mgag200_drv.c */ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size); -int mgag200_regs_init(struct mga_device *mdev); +resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); +int mgag200_device_preinit(struct mga_device *mdev); +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags); /* mgag200_.c */ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, @@ -285,9 +279,6 @@ int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_availa /* mgag200_i2c.c */ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c); - /* mgag200_mm.c */ -int mgag200_mm_init(struct mga_device *mdev); - /* mgag200_pll.c */ int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 4e30b54a2677..4300a472c0a3 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -177,16 +177,13 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct if (ret) return ERR_PTR(ret); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); mgag200_g200_init_refclk(g200); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index a16493db0512..7af9bdfb03c7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -25,18 +25,15 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru pci_set_drvdata(pdev, dev); - mdev->flags = flags; - mdev->type = type; - ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); if (ret) return ERR_PTR(ret); - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 478ca578b839..c0695d5c4f68 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -26,18 +26,15 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); - mdev->flags = flags; - mdev->type = type; - ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000); if (ret) return ERR_PTR(ret); - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 2f38fb470f4e..281317450fad 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -25,14 +25,11 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru pci_set_drvdata(pdev, dev); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index ff3c7b17ac44..41f948962b93 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -29,14 +29,11 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 971d40874cf3..89346815e107 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -12,7 +12,7 @@ static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { - resource_size_t vram_size = mdev->mc.vram_size; + resource_size_t vram_size = resource_size(mdev->vram_res); if (vram_size >= 0x1000000) vram_size = vram_size - 0x400000; @@ -39,14 +39,11 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index cd2987b58fcb..b23459710372 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -64,16 +64,13 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); mgag200_g200se_init_unique_id(g200se); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 38e374c00419..776bad867b4d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -29,14 +29,11 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - mdev->flags = flags; - mdev->type = type; - - ret = mgag200_regs_init(mdev); + ret = mgag200_device_preinit(mdev); if (ret) return ERR_PTR(ret); - ret = mgag200_mm_init(mdev); + ret = mgag200_device_init(mdev, type, flags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_mm.c b/drivers/gpu/drm/mgag200/mgag200_mm.c deleted file mode 100644 index fc19c2369641..000000000000 --- a/drivers/gpu/drm/mgag200/mgag200_mm.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - */ -/* - * Authors: Dave Airlie - */ - -#include - -#include - -#include "mgag200_drv.h" - -int mgag200_mm_init(struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - u8 misc; - resource_size_t start, len; - - WREG_ECRT(0x04, 0x00); - - misc = RREG8(MGA_MISC_IN); - misc |= MGAREG_MISC_RAMMAPEN | - MGAREG_MISC_HIGH_PG_SEL; - WREG8(MGA_MISC_OUT, misc); - - /* BAR 0 is VRAM */ - start = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - - if (!devm_request_mem_region(dev->dev, start, len, "mgadrmfb_vram")) { - drm_err(dev, "can't reserve VRAM\n"); - return -ENXIO; - } - - /* Don't fail on errors, but performance might be reduced. */ - devm_arch_io_reserve_memtype_wc(dev->dev, start, len); - devm_arch_phys_wc_add(dev->dev, start, len); - - mdev->vram = devm_ioremap(dev->dev, start, len); - if (!mdev->vram) - return -ENOMEM; - - mdev->mc.vram_size = len; - mdev->mc.vram_base = start; - mdev->mc.vram_window = len; - - return 0; -} diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index c254988e5bcb..effe5160bb79 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -32,11 +32,6 @@ * This file contains setup code for the CRTC. */ -resource_size_t mgag200_device_probe_vram(struct mga_device *mdev) -{ - return mgag200_probe_vram(mdev->vram, mdev->mc.vram_size); -} - static void mgag200_crtc_set_gamma_linear(struct mga_device *mdev, const struct drm_format_info *format) { @@ -1103,7 +1098,7 @@ int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; dev->mode_config.preferred_depth = 24; - dev->mode_config.fb_base = mdev->mc.vram_base; + dev->mode_config.fb_base = mdev->vram_res->start; dev->mode_config.funcs = &mgag200_mode_config_funcs; ret = mgag200_i2c_init(mdev, i2c); From b9a577a407d99638522ba6a0fc4fb360aacc01d0 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:18 +0200 Subject: [PATCH 163/170] drm/mgag200: Add struct mgag200_device_info While currently empty, struct mgag200_device_info, will provide static, constant information on each device model. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-7-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.c | 4 +++- drivers/gpu/drm/mgag200/mgag200_drv.h | 12 +++++++++++- drivers/gpu/drm/mgag200/mgag200_g200.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200er.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200se.c | 5 ++++- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 5 ++++- 10 files changed, 46 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 8f636db4a723..90ed7770ff72 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -162,13 +162,15 @@ int mgag200_device_preinit(struct mga_device *mdev) return 0; } -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags) +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags, + const struct mgag200_device_info *info) { struct drm_device *dev = &mdev->base; u8 crtcext3, misc; int ret; mdev->flags = flags; + mdev->info = info; mdev->type = type; ret = drmm_mutex_init(dev, &mdev->rmmio_lock); diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 9abecf366268..89cb4e476119 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -196,10 +196,19 @@ enum mga_type { #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) +struct mgag200_device_info { +}; + +#define MGAG200_DEVICE_INFO_INIT() \ + { \ + } + struct mga_device { struct drm_device base; unsigned long flags; + const struct mgag200_device_info *info; + struct resource *rmmio_res; void __iomem *rmmio; struct mutex rmmio_lock; /* Protects access to rmmio */ @@ -252,7 +261,8 @@ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size); resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); int mgag200_device_preinit(struct mga_device *mdev); -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags); +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags, + const struct mgag200_device_info *info); /* mgag200_.c */ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 4300a472c0a3..b2969a1f1e0b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -33,6 +33,9 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) * DRM Device */ +static const struct mgag200_device_info mgag200_g200_device_info = + MGAG200_DEVICE_INFO_INIT(); + static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, const unsigned char *bios, size_t size) { @@ -183,7 +186,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct mgag200_g200_init_refclk(g200); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 7af9bdfb03c7..6284fedc1b8a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200eh_device_info = + MGAG200_DEVICE_INFO_INIT(); + struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) { @@ -33,7 +36,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200eh_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index c0695d5c4f68..c8e46b89286f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200eh3_device_info = + MGAG200_DEVICE_INFO_INIT(); + struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) @@ -34,7 +37,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200eh3_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 281317450fad..ef16ce4adecd 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200er_device_info = + MGAG200_DEVICE_INFO_INIT(); + struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) { @@ -29,7 +32,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200er_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 41f948962b93..75d08fb503bb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200ev_device_info = + MGAG200_DEVICE_INFO_INIT(); + struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) { @@ -33,7 +36,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200ev_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 89346815e107..7cb18685b98d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200ew3_device_info = + MGAG200_DEVICE_INFO_INIT(); + static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { resource_size_t vram_size = resource_size(mdev->vram_res); @@ -43,7 +46,7 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200ew3_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index b23459710372..69a17f057b32 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -32,6 +32,9 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) * DRM device */ +static const struct mgag200_device_info mgag200_g200se_device_info = + MGAG200_DEVICE_INFO_INIT(); + static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) { struct mga_device *mdev = &g200se->base; @@ -70,7 +73,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru mgag200_g200se_init_unique_id(g200se); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200se_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 776bad867b4d..921c55ec309e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -10,6 +10,9 @@ * DRM device */ +static const struct mgag200_device_info mgag200_g200wb_device_info = + MGAG200_DEVICE_INFO_INIT(); + struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type, unsigned long flags) { @@ -33,7 +36,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags); + ret = mgag200_device_init(mdev, type, flags, &mgag200_g200wb_device_info); if (ret) return ERR_PTR(ret); From 21e74bf99596d91411b6b51340c05ff92a7a4a01 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:19 +0200 Subject: [PATCH 164/170] drm/mgag200: Store HW_BUG_NO_STARTADD flag in device info Flag devices with broken handling of the startadd field in struct mgag200_device_info, instead of PCI driver data. This reduces the driver data to a simple type constant. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-8-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.c | 36 +++++++---------------- drivers/gpu/drm/mgag200/mgag200_drv.h | 35 +++++++++++----------- drivers/gpu/drm/mgag200/mgag200_g200.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200er.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_g200se.c | 23 ++++++++++++--- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 6 ++-- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +- 11 files changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 90ed7770ff72..361eb7dffda1 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -162,14 +162,13 @@ int mgag200_device_preinit(struct mga_device *mdev) return 0; } -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags, +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, const struct mgag200_device_info *info) { struct drm_device *dev = &mdev->base; u8 crtcext3, misc; int ret; - mdev->flags = flags; mdev->info = info; mdev->type = type; @@ -202,8 +201,7 @@ int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned lo static const struct pci_device_id mgag200_pciidlist[] = { { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI }, { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_AGP }, - { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - G200_SE_A | MGAG200_FLAG_HW_BUG_NO_STARTADD}, + { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A }, { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV }, { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB }, @@ -216,22 +214,10 @@ static const struct pci_device_id mgag200_pciidlist[] = { MODULE_DEVICE_TABLE(pci, mgag200_pciidlist); -static enum mga_type mgag200_type_from_driver_data(kernel_ulong_t driver_data) -{ - return (enum mga_type)(driver_data & MGAG200_TYPE_MASK); -} - -static unsigned long mgag200_flags_from_driver_data(kernel_ulong_t driver_data) -{ - return driver_data & MGAG200_FLAG_MASK; -} - static int mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - kernel_ulong_t driver_data = ent->driver_data; - enum mga_type type = mgag200_type_from_driver_data(driver_data); - unsigned long flags = mgag200_flags_from_driver_data(driver_data); + enum mga_type type = (enum mga_type)ent->driver_data; struct mga_device *mdev; struct drm_device *dev; int ret; @@ -247,29 +233,29 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) switch (type) { case G200_PCI: case G200_AGP: - mdev = mgag200_g200_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200_device_create(pdev, &mgag200_driver, type); break; case G200_SE_A: case G200_SE_B: - mdev = mgag200_g200se_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200se_device_create(pdev, &mgag200_driver, type); break; case G200_WB: - mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver, type); break; case G200_EV: - mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver, type); break; case G200_EH: - mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver, type); break; case G200_EH3: - mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver, type); break; case G200_ER: - mdev = mgag200_g200er_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200er_device_create(pdev, &mgag200_driver, type); break; case G200_EW3: - mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver, type, flags); + mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver, type); break; default: dev_err(&pdev->dev, "Device type %d is unsupported\n", type); diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 89cb4e476119..b05becb3d4b7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -188,24 +188,23 @@ enum mga_type { G200_EW3, }; -/* HW does not handle 'startadd' field correct. */ -#define MGAG200_FLAG_HW_BUG_NO_STARTADD (1ul << 8) - -#define MGAG200_TYPE_MASK (0x000000ff) -#define MGAG200_FLAG_MASK (0x00ffff00) - #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) struct mgag200_device_info { + /* + * HW does not handle 'startadd' register correctly. Always set + * it's value to 0. + */ + bool bug_no_startadd:1; }; -#define MGAG200_DEVICE_INFO_INIT() \ +#define MGAG200_DEVICE_INFO_INIT(_bug_no_startadd) \ { \ + .bug_no_startadd = (_bug_no_startadd), \ } struct mga_device { - struct drm_device base; - unsigned long flags; + struct drm_device base; const struct mgag200_device_info *info; @@ -261,26 +260,26 @@ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size); resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); int mgag200_device_preinit(struct mga_device *mdev); -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, unsigned long flags, +int mgag200_device_init(struct mga_device *mdev, enum mga_type type, const struct mgag200_device_info *info); /* mgag200_.c */ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags); + enum mga_type type); /* mgag200_mode.c */ resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index b2969a1f1e0b..90b33a7352e5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, const unsigned char *bios, size_t size) @@ -160,7 +160,7 @@ out: } struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mgag200_g200_device *g200; struct mga_device *mdev; @@ -186,7 +186,7 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct mgag200_g200_init_refclk(g200); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 6284fedc1b8a..14bec513e441 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -11,10 +11,10 @@ */ static const struct mgag200_device_info mgag200_g200eh_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -36,7 +36,7 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200eh_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index c8e46b89286f..c982533de9e7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -11,11 +11,11 @@ */ static const struct mgag200_device_info mgag200_g200eh3_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -37,7 +37,7 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200eh3_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200eh3_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index ef16ce4adecd..d84039eef982 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -11,10 +11,10 @@ */ static const struct mgag200_device_info mgag200_g200er_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -32,7 +32,7 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200er_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200er_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 75d08fb503bb..14a891d47270 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -11,10 +11,10 @@ */ static const struct mgag200_device_info mgag200_g200ev_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -36,7 +36,7 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200ev_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200ev_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 7cb18685b98d..b09f345ba29b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ew3_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { @@ -24,7 +24,7 @@ static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -46,7 +46,7 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200ew3_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200ew3_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 69a17f057b32..9c0fc57366f2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -32,8 +32,11 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) * DRM device */ -static const struct mgag200_device_info mgag200_g200se_device_info = - MGAG200_DEVICE_INFO_INIT(); +static const struct mgag200_device_info mgag200_g200se_a_device_info = + MGAG200_DEVICE_INFO_INIT(true); + +static const struct mgag200_device_info mgag200_g200se_b_device_info = + MGAG200_DEVICE_INFO_INIT(false); static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) { @@ -47,9 +50,10 @@ static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) } struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mgag200_g200se_device *g200se; + const struct mgag200_device_info *info; struct mga_device *mdev; struct drm_device *dev; resource_size_t vram_available; @@ -73,7 +77,18 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru mgag200_g200se_init_unique_id(g200se); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200se_device_info); + switch (type) { + case G200_SE_A: + info = &mgag200_g200se_a_device_info; + break; + case G200_SE_B: + info = &mgag200_g200se_b_device_info; + break; + default: + return ERR_PTR(-EINVAL); + } + + ret = mgag200_device_init(mdev, type, info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 921c55ec309e..c9bf2176726e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -11,10 +11,10 @@ */ static const struct mgag200_device_info mgag200_g200wb_device_info = - MGAG200_DEVICE_INFO_INIT(); + MGAG200_DEVICE_INFO_INIT(false); struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type, unsigned long flags) + enum mga_type type) { struct mga_device *mdev; struct drm_device *dev; @@ -36,7 +36,7 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, flags, &mgag200_g200wb_device_info); + ret = mgag200_device_init(mdev, type, &mgag200_g200wb_device_info); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index effe5160bb79..f5e1a89e0bfe 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -245,7 +245,7 @@ static void mgag200_set_startadd(struct mga_device *mdev, startadd = offset / 8; if (startadd > 0) - drm_WARN_ON_ONCE(dev, mdev->flags & MGAG200_FLAG_HW_BUG_NO_STARTADD); + drm_WARN_ON_ONCE(dev, mdev->info->bug_no_startadd); /* * Can't store addresses any higher than that, but we also From 98da4b99a0525c222dab7cd8e73153eaea062dc3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:20 +0200 Subject: [PATCH 165/170] drm/mgag200: Store maximum resolution and memory bandwidth in device info The maximum resolution and memory bandwidth are model-specific limits. Both are used during display-mode validation. Store the values in struct mgag200_device_info and simplify the validation code. v2: * 'bandwith' -> 'bandwidth' in commit message Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-9-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.h | 15 +++++- drivers/gpu/drm/mgag200/mgag200_g200.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200se.c | 44 ++++++++++++--- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 2 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 65 +++++++---------------- 10 files changed, 75 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index b05becb3d4b7..f0fb13238f4f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -191,6 +191,15 @@ enum mga_type { #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) struct mgag200_device_info { + u16 max_hdisplay; + u16 max_vdisplay; + + /* + * Maximum memory bandwidth (MiB/sec). Setting this to zero disables + * the rsp test during mode validation. + */ + unsigned long max_mem_bandwidth; + /* * HW does not handle 'startadd' register correctly. Always set * it's value to 0. @@ -198,8 +207,12 @@ struct mgag200_device_info { bool bug_no_startadd:1; }; -#define MGAG200_DEVICE_INFO_INIT(_bug_no_startadd) \ +#define MGAG200_DEVICE_INFO_INIT(_max_hdisplay, _max_vdisplay, _max_mem_bandwidth, \ + _bug_no_startadd) \ { \ + .max_hdisplay = (_max_hdisplay), \ + .max_vdisplay = (_max_vdisplay), \ + .max_mem_bandwidth = (_max_mem_bandwidth), \ .bug_no_startadd = (_bug_no_startadd), \ } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 90b33a7352e5..4ec1b18ab170 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, const unsigned char *bios, size_t size) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 14bec513e441..a35ba2fdfc0e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false); struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index c982533de9e7..649559be1482 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh3_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index d84039eef982..e661fad2f8b2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200er_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 14a891d47270..07a3862d69de 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ev_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false); struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index b09f345ba29b..7f3987435085 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ew3_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 9c0fc57366f2..78120470b7be 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -32,21 +32,37 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) * DRM device */ -static const struct mgag200_device_info mgag200_g200se_a_device_info = - MGAG200_DEVICE_INFO_INIT(true); +static const struct mgag200_device_info mgag200_g200se_a_01_device_info = + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, true); -static const struct mgag200_device_info mgag200_g200se_b_device_info = - MGAG200_DEVICE_INFO_INIT(false); +static const struct mgag200_device_info mgag200_g200se_a_02_device_info = + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, true); -static void mgag200_g200se_init_unique_id(struct mgag200_g200se_device *g200se) +static const struct mgag200_device_info mgag200_g200se_a_03_device_info = + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); + +static const struct mgag200_device_info mgag200_g200se_b_01_device_info = + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false); + +static const struct mgag200_device_info mgag200_g200se_b_02_device_info = + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false); + +static const struct mgag200_device_info mgag200_g200se_b_03_device_info = + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); + +static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se) { struct mga_device *mdev = &g200se->base; struct drm_device *dev = &mdev->base; /* stash G200 SE model number for later use */ g200se->unique_rev_id = RREG32(0x1e24); + if (!g200se->unique_rev_id) + return -ENODEV; drm_dbg(dev, "G200 SE unique revision id is 0x%x\n", g200se->unique_rev_id); + + return 0; } struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, @@ -75,14 +91,26 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - mgag200_g200se_init_unique_id(g200se); + ret = mgag200_g200se_init_unique_rev_id(g200se); + if (ret) + return ERR_PTR(ret); switch (type) { case G200_SE_A: - info = &mgag200_g200se_a_device_info; + if (g200se->unique_rev_id >= 0x03) + info = &mgag200_g200se_a_03_device_info; + else if (g200se->unique_rev_id >= 0x02) + info = &mgag200_g200se_a_02_device_info; + else + info = &mgag200_g200se_a_01_device_info; break; case G200_SE_B: - info = &mgag200_g200se_b_device_info; + if (g200se->unique_rev_id >= 0x03) + info = &mgag200_g200se_b_03_device_info; + else if (g200se->unique_rev_id >= 0x02) + info = &mgag200_g200se_b_02_device_info; + else + info = &mgag200_g200se_b_01_device_info; break; default: return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index c9bf2176726e..0943ad2a9999 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200wb_device_info = - MGAG200_DEVICE_INFO_INIT(false); + MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, false); struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index f5e1a89e0bfe..aa85558faa1b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -725,30 +725,17 @@ static enum drm_mode_status mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, const struct drm_display_mode *mode) { - struct drm_device *dev = pipe->crtc.dev; - struct mga_device *mdev = to_mga_device(dev); - struct mgag200_g200se_device *g200se; + struct mga_device *mdev = to_mga_device(pipe->crtc.dev); + const struct mgag200_device_info *info = mdev->info; - if (IS_G200_SE(mdev)) { - g200se = to_mgag200_g200se_device(dev); - - if (g200se->unique_rev_id == 0x01) { - if (mode->hdisplay > 1600) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1200) - return MODE_VIRTUAL_Y; - } else if (g200se->unique_rev_id == 0x02) { - if (mode->hdisplay > 1920) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1200) - return MODE_VIRTUAL_Y; - } - } else if (mdev->type == G200_WB) { - if (mode->hdisplay > 1280) - return MODE_VIRTUAL_X; - if (mode->vdisplay > 1024) - return MODE_VIRTUAL_Y; - } + /* + * Some devices have additional limits on the size of the + * display mode. + */ + if (mode->hdisplay > info->max_hdisplay) + return MODE_VIRTUAL_X; + if (mode->vdisplay > info->max_vdisplay) + return MODE_VIRTUAL_Y; if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { @@ -1028,7 +1015,7 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888 struct mga_device *mdev = to_mga_device(dev); unsigned long fbsize, fbpages, max_fbpages; - struct mgag200_g200se_device *g200se; + const struct mgag200_device_info *info = mdev->info; max_fbpages = mdev->vram_available >> PAGE_SHIFT; @@ -1038,30 +1025,14 @@ static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *de if (fbpages > max_fbpages) return MODE_MEM; - if (IS_G200_SE(mdev)) { - g200se = to_mgag200_g200se_device(dev); + /* + * Test the mode's required memory bandwidth if the device + * specifies a maximum. Not all devices do though. + */ + if (info->max_mem_bandwidth) { + uint32_t mode_bandwidth = mgag200_calculate_mode_bandwidth(mode, max_bpp * 8); - if (g200se->unique_rev_id == 0x01) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (24400 * 1024)) - return MODE_BAD; - } else if (g200se->unique_rev_id == 0x02) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (30100 * 1024)) - return MODE_BAD; - } else { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024)) - return MODE_BAD; - } - } else if (mdev->type == G200_WB) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (31877 * 1024)) - return MODE_BAD; - } else if (mdev->type == G200_EV) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (32700 * 1024)) - return MODE_BAD; - } else if (mdev->type == G200_EH) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (37500 * 1024)) - return MODE_BAD; - } else if (mdev->type == G200_ER) { - if (mgag200_calculate_mode_bandwidth(mode, max_bpp * 8) > (55000 * 1024)) + if (mode_bandwidth > (info->max_mem_bandwidth * 1024)) return MODE_BAD; } From d1e40d8e4b4df3f705c7898b264b2cfb60bdafc4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:21 +0200 Subject: [PATCH 166/170] drm/mgag200: Store vidrst flag in device info Set new vidrst flag in device info for models that synchronize with external sources (i.e., BMCs). In modesetting, set the corresponding bits from the device-info flag. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-10-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.h | 6 +++++- drivers/gpu/drm/mgag200/mgag200_g200.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200se.c | 12 ++++++------ drivers/gpu/drm/mgag200/mgag200_g200wb.c | 2 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 7 ++++--- drivers/gpu/drm/mgag200/mgag200_reg.h | 2 ++ 11 files changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index f0fb13238f4f..1ceb19a987e2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -200,6 +200,9 @@ struct mgag200_device_info { */ unsigned long max_mem_bandwidth; + /* HW has external source (e.g., BMC) to synchronize with */ + bool has_vidrst:1; + /* * HW does not handle 'startadd' register correctly. Always set * it's value to 0. @@ -208,11 +211,12 @@ struct mgag200_device_info { }; #define MGAG200_DEVICE_INFO_INIT(_max_hdisplay, _max_vdisplay, _max_mem_bandwidth, \ - _bug_no_startadd) \ + _has_vidrst, _bug_no_startadd) \ { \ .max_hdisplay = (_max_hdisplay), \ .max_vdisplay = (_max_vdisplay), \ .max_mem_bandwidth = (_max_mem_bandwidth), \ + .has_vidrst = (_has_vidrst), \ .bug_no_startadd = (_bug_no_startadd), \ } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 4ec1b18ab170..58ae5d067263 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, false); static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, const unsigned char *bios, size_t size) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index a35ba2fdfc0e..ee38d918c727 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, false); struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 649559be1482..4b69206296ee 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh3_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, false); struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index e661fad2f8b2..7e44fcc7bb59 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200er_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 07a3862d69de..87a9497ab805 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ev_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, false); struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 7f3987435085..61f944319bc9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ew3_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, false); static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 78120470b7be..0ccec9358529 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -33,22 +33,22 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200se_a_01_device_info = - MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, true); + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, true); static const struct mgag200_device_info mgag200_g200se_a_02_device_info = - MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, true); + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, true); static const struct mgag200_device_info mgag200_g200se_a_03_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); static const struct mgag200_device_info mgag200_g200se_b_01_device_info = - MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false); + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, false); static const struct mgag200_device_info mgag200_g200se_b_02_device_info = - MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false); + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, false); static const struct mgag200_device_info mgag200_g200se_b_03_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se) { diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 0943ad2a9999..97002c08da41 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200wb_device_info = - MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, false); + MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, false); struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index aa85558faa1b..e339f50d6bc8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -377,6 +377,7 @@ static void mgag200_init_regs(struct mga_device *mdev) static void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode) { + const struct mgag200_device_info *info = mdev->info; unsigned int hdisplay, hsyncstart, hsyncend, htotal; unsigned int vdisplay, vsyncstart, vsyncend, vtotal; u8 misc, crtcext1, crtcext2, crtcext5; @@ -411,9 +412,9 @@ static void mgag200_set_mode_regs(struct mga_device *mdev, ((hdisplay & 0x100) >> 7) | ((hsyncstart & 0x100) >> 6) | (htotal & 0x40); - if (mdev->type == G200_WB || mdev->type == G200_EW3) - crtcext1 |= BIT(7) | /* vrsten */ - BIT(3); /* hrsten */ + if (info->has_vidrst) + crtcext1 |= MGAREG_CRTCEXT1_VRSTEN | + MGAREG_CRTCEXT1_HRSTEN; crtcext2 = ((vtotal & 0xc00) >> 10) | ((vdisplay & 0x400) >> 8) | diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h index 60e705283fe8..99a9ab7d9119 100644 --- a/drivers/gpu/drm/mgag200/mgag200_reg.h +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h @@ -252,8 +252,10 @@ #define MGAREG_CRTCEXT0_OFFSET_MASK GENMASK(5, 4) +#define MGAREG_CRTCEXT1_VRSTEN BIT(7) #define MGAREG_CRTCEXT1_VSYNCOFF BIT(5) #define MGAREG_CRTCEXT1_HSYNCOFF BIT(4) +#define MGAREG_CRTCEXT1_HRSTEN BIT(3) #define MGAREG_CRTCEXT3_MGAMODE BIT(7) From da1efdb2a3e8593a9428c81a531bfd8a0c3dd66e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 1 Jun 2022 13:25:22 +0200 Subject: [PATCH 167/170] drm/mgag200: Store positions of I2C data and clock bits in device info The bits for accessing I2C data and clock channels varies among models. Store them in the device-info structure for consumption by the DDC code. Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220601112522.5774-11-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_drv.h | 12 +++++++++- drivers/gpu/drm/mgag200/mgag200_g200.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200er.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ev.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 +- drivers/gpu/drm/mgag200/mgag200_g200se.c | 12 +++++----- drivers/gpu/drm/mgag200/mgag200_g200wb.c | 2 +- drivers/gpu/drm/mgag200/mgag200_i2c.c | 27 +++-------------------- 10 files changed, 27 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 1ceb19a987e2..301c4ab46539 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -203,6 +203,11 @@ struct mgag200_device_info { /* HW has external source (e.g., BMC) to synchronize with */ bool has_vidrst:1; + struct { + unsigned data_bit:3; + unsigned clock_bit:3; + } i2c; + /* * HW does not handle 'startadd' register correctly. Always set * it's value to 0. @@ -211,12 +216,17 @@ struct mgag200_device_info { }; #define MGAG200_DEVICE_INFO_INIT(_max_hdisplay, _max_vdisplay, _max_mem_bandwidth, \ - _has_vidrst, _bug_no_startadd) \ + _has_vidrst, _i2c_data_bit, _i2c_clock_bit, \ + _bug_no_startadd) \ { \ .max_hdisplay = (_max_hdisplay), \ .max_vdisplay = (_max_vdisplay), \ .max_mem_bandwidth = (_max_mem_bandwidth), \ .has_vidrst = (_has_vidrst), \ + .i2c = { \ + .data_bit = (_i2c_data_bit), \ + .clock_bit = (_i2c_clock_bit), \ + }, \ .bug_no_startadd = (_bug_no_startadd), \ } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 58ae5d067263..616e11391e02 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -34,7 +34,7 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 3, false); static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200, const unsigned char *bios, size_t size) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index ee38d918c727..1b9a22728744 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false); struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 4b69206296ee..438cda1b14c9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200eh3_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false); struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 7e44fcc7bb59..0790d4e6463d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200er_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false); struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 87a9497ab805..5353422d0eef 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ev_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false); struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 61f944319bc9..3bfc1324cf78 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200ew3_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false); static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 0ccec9358529..0a3e66695e22 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -33,22 +33,22 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) */ static const struct mgag200_device_info mgag200_g200se_a_01_device_info = - MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, true); + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, true); static const struct mgag200_device_info mgag200_g200se_a_02_device_info = - MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, true); + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, true); static const struct mgag200_device_info mgag200_g200se_a_03_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false); static const struct mgag200_device_info mgag200_g200se_b_01_device_info = - MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, false); + MGAG200_DEVICE_INFO_INIT(1600, 1200, 24400, false, 0, 1, false); static const struct mgag200_device_info mgag200_g200se_b_02_device_info = - MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, false); + MGAG200_DEVICE_INFO_INIT(1920, 1200, 30100, false, 0, 1, false); static const struct mgag200_device_info mgag200_g200se_b_03_device_info = - MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, false); + MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 0, 1, false); static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200se) { diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index 97002c08da41..c8450ac8eaec 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -11,7 +11,7 @@ */ static const struct mgag200_device_info mgag200_g200wb_device_info = - MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, false); + MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false); struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index f57b33917152..0c48bdf3e7f8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -96,36 +96,15 @@ static void mgag200_i2c_release(void *res) int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) { struct drm_device *dev = &mdev->base; + const struct mgag200_device_info *info = mdev->info; int ret; - int data, clock; WREG_DAC(MGA1064_GEN_IO_CTL2, 1); WREG_DAC(MGA1064_GEN_IO_DATA, 0xff); WREG_DAC(MGA1064_GEN_IO_CTL, 0); - switch (mdev->type) { - case G200_SE_A: - case G200_SE_B: - case G200_EV: - case G200_WB: - case G200_EW3: - data = 1; - clock = 2; - break; - case G200_EH: - case G200_EH3: - case G200_ER: - data = 2; - clock = 1; - break; - default: - data = 2; - clock = 8; - break; - } - - i2c->data = data; - i2c->clock = clock; + i2c->data = BIT(info->i2c.data_bit); + i2c->clock = BIT(info->i2c.clock_bit); i2c->adapter.owner = THIS_MODULE; i2c->adapter.class = I2C_CLASS_DDC; i2c->adapter.dev.parent = dev->dev; From 7d255ddbbf679aa47e041cbf68520fd985ed2279 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 1 Jun 2022 07:39:26 +0400 Subject: [PATCH 168/170] drm/meson: encoder_cvbs: Fix refcount leak in meson_encoder_cvbs_init of_graph_get_remote_node() returns remote device nodepointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak. Fixes: 318ba02cd8a8 ("drm/meson: encoder_cvbs: switch to bridge with ATTACH_NO_CONNECTOR") Signed-off-by: Miaoqian Lin Reviewed-by: Martin Blumenstingl Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20220601033927.47814-2-linmq006@gmail.com --- drivers/gpu/drm/meson/meson_encoder_cvbs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c index fd8db97ba8ba..8110a6e39320 100644 --- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c +++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c @@ -238,6 +238,7 @@ int meson_encoder_cvbs_init(struct meson_drm *priv) } meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote); + of_node_put(remote); if (!meson_encoder_cvbs->next_bridge) { dev_err(priv->dev, "Failed to find CVBS Connector bridge\n"); return -EPROBE_DEFER; From d82a5a4aae9d0203234737caed1bf470aa317568 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 1 Jun 2022 07:39:27 +0400 Subject: [PATCH 169/170] drm/meson: encoder_hdmi: Fix refcount leak in meson_encoder_hdmi_init of_graph_get_remote_node() returns remote device nodepointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak. Fixes: e67f6037ae1b ("drm/meson: split out encoder from meson_dw_hdmi") Signed-off-by: Miaoqian Lin Reviewed-by: Martin Blumenstingl Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20220601033927.47814-3-linmq006@gmail.com --- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 2593c542ad41..2f616c55c271 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -371,7 +371,8 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote); if (!meson_encoder_hdmi->next_bridge) { dev_err(priv->dev, "Failed to find HDMI transceiver bridge\n"); - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto err_put_node; } /* HDMI Encoder Bridge */ @@ -389,7 +390,7 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) DRM_MODE_ENCODER_TMDS); if (ret) { dev_err(priv->dev, "Failed to init HDMI encoder: %d\n", ret); - return ret; + goto err_put_node; } meson_encoder_hdmi->encoder.possible_crtcs = BIT(0); @@ -399,7 +400,7 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { dev_err(priv->dev, "Failed to attach bridge: %d\n", ret); - return ret; + goto err_put_node; } /* Initialize & attach Bridge Connector */ @@ -407,7 +408,8 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) &meson_encoder_hdmi->encoder); if (IS_ERR(meson_encoder_hdmi->connector)) { dev_err(priv->dev, "Unable to create HDMI bridge connector\n"); - return PTR_ERR(meson_encoder_hdmi->connector); + ret = PTR_ERR(meson_encoder_hdmi->connector); + goto err_put_node; } drm_connector_attach_encoder(meson_encoder_hdmi->connector, &meson_encoder_hdmi->encoder); @@ -434,6 +436,7 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) meson_encoder_hdmi->connector->ycbcr_420_allowed = true; pdev = of_find_device_by_node(remote); + of_node_put(remote); if (pdev) { struct cec_connector_info conn_info; struct cec_notifier *notifier; @@ -452,4 +455,8 @@ int meson_encoder_hdmi_init(struct meson_drm *priv) dev_dbg(priv->dev, "HDMI encoder initialized\n"); return 0; + +err_put_node: + of_node_put(remote); + return ret; } From dfa687bffc8a4a21ed929c7dececf01b8f1f52ee Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 1 Jun 2022 16:38:18 -0700 Subject: [PATCH 170/170] drm/bridge: lt9611uxc: Cancel only driver's work During device remove care needs to be taken that no work is pending before it removes the underlying DRM bridge etc, but this can be done on the specific work rather than waiting for the flush of the system-wide workqueue. Fixes: bc6fa8676ebb ("drm/bridge/lontium-lt9611uxc: move HPD notification out of IRQ handler") Signed-off-by: Bjorn Andersson Reviewed-by: Neil Armstrong Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220601233818.1877963-1-bjorn.andersson@linaro.org --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 3d62e6bf6892..310b3b194491 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -982,7 +982,7 @@ static int lt9611uxc_remove(struct i2c_client *client) struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client); disable_irq(client->irq); - flush_scheduled_work(); + cancel_work_sync(<9611uxc->work); lt9611uxc_audio_exit(lt9611uxc); drm_bridge_remove(<9611uxc->bridge);