<html><head></head><body><div class="ydp3129e8e2yahoo-style-wrap" style="font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:16px;"><div dir="ltr" data-setdir="false"><div><div>Hi!</div><div><br></div><div>This is my first patch ever to DRM/amdgpu (technically I didn't write the patch, I just kept rebasing it over 4 years, and did lots of testing).</div><div><br></div><div>I'm following the advise from:</div><div>https://gitlab.freedesktop.org/drm/amd/-/issues/476#note_2628536</div><div><br></div><div dir="ltr" data-setdir="false">Why this patch? Because it fix a practical problem with certain monitors that auto-select <span>ycbcr444 when they should be set to "<span>rgb" (this issue also happens on Windows) when plugging an HDMI monitor to a DisplayPort via passive adapter</span></span>.</div><div><br></div><div><br></div><div dir="ltr" data-setdir="false">IMPORTANT remarks about the public API:</div><div><br></div><div>1. This API adds "pixel encoding" which has options "auto" (Default), "rgb", "ycbcr444", and "ycbcr420"</div><div><br></div><div dir="ltr" data-setdir="false">2. Intel has "RGB Broadcast". Its options are "Full" and "Limited 16:235". There is a lot of overlap here. On Windows AMD Control Panel offers the option "Pixel Encoding" and its options are:</div><div> - RGB (full)</div><div> - RGB (limited)</div><div> - ycbcr444</div><div> - ycbcr420</div><div dir="ltr" data-setdir="false"> - <span><span style="color: rgb(0, 0, 0); font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 16px;">ycbcr</span></span>422</div><div><br></div><div>Which means that it may be worth reserving more keywords for this patch.</div><div dir="ltr" data-setdir="false">I don't know why ycbcr444/ycbcr420 do not offer full/limited variants on Windows, but I suspect it's because the driver can automatically tell whether to use Full vs Limited for <span>ycbcr</span> variants..</div><div><br></div><div>3. amdgpu already has "Colorspace" option. However this is a different (although related) option. But there is quite the overlap:</div><div><br></div><div>- Full/Limited options are sometimes included as part of the colorspace, such is the case of COLOR_SPACE_2020_RGB_FULLRANGE vs COLOR_SPACE_2020_RGB_LIMITEDRANGE, but there is no "LIMITED"/"FULL" variants for COLOR_SPACE_2020_YCBCR. Yet there are for YCBCR601 and YCBCR709. This may be a spec thing (I don’t know).</div><div>- AFAIK amdgpu’s Limited/Full variants are not controllable from the public user-space API.</div><div dir="ltr" data-setdir="false">- Certain options in "Colorspace" only makes sense in specific pixel encoding. For example the option "opRGB" currently glitches when amdgpu is using <span>ycbcr</span> encoding (you can tell the monitor is interpreting the RGB signal as YUV, thus white becomes purple and black becomes green).</div><div>- The kernel has DRM_MODE_COLORIMETRY_BT2020_RGB and DRM_MODE_COLORIMETRY_BT2020_YCC. AMDGPU kernel currently forces COLOR_SPACE_2020_RGB_FULLRANGE or COLOR_SPACE_2020_YCBCR based on the current pixel encoding (e.g. if using RGB encodings and colorspace == DRM_MODE_COLORIMETRY_BT2020_YCC, it will be changed for COLOR_SPACE_2020_RGB_FULLRANGE with currently no choice for Limited range).</div><div dir="ltr" data-setdir="false">- amdgpu seems to be able to automatically distinguish between Full and Limited for <span>ycbcr</span>  formats via the presence of flags.Y_ONLY bit. There is no such auto-detection for RGB.</div><div><br></div><div><br></div><div>The way I see it, there are 3 configurations that can be arranged together:</div><div><br></div><div dir="ltr" data-setdir="false">- Pixel Encoding (RGB vs  <span><span style="color: rgb(0, 0, 0); font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 16px;">ycbcr</span></span>444 vs  <span>ycbcr</span>420).</div><div>- Colorspace (YCBCR709 vs BT.2020 etc).</div><div>- Full vs Limited.</div><div><br></div><div>However not all options are compatible with everything.</div><div><br></div><div>I suspect doing the same as what AMD does on Windows (offer RGB/Full + RGB/Limited + all the ycbcr variants for "pixel encoding") is the best choice (and leave the "Colorspace" option as is, for very advanced manipulation).</div></div><div><br></div><div dir="ltr" data-setdir="false">4. Xaver Hugl expressed his concerns with the current patch that having an option called "auto" with no way of querying what is the current auto-selected encoding is sub-optimal.</div><div><br></div><div><br></div><div dir="ltr" data-setdir="false">Cheers</div><div dir="ltr" data-setdir="false">Matias</div><br></div><div><br></div><div><br></div><div>From 6806baac51f1ac2028c49bcab216c19f26a7e92b Mon Sep 17 00:00:00 2001</div><div>From: "Matias N. Goldberg" <dark_sylinc@yahoo.com.ar></div><div>Date: Sun, 6 Oct 2024 21:04:11 -0300</div><div>Subject: [PATCH] [amdgpu] Add "pixel_encoding" to switch between RGB & YUV</div><div> color modes</div><div><br></div><div>Usage:</div><div>xrandr --output DisplayPort-1 --set "pixel encoding" rgb</div><div><br></div><div>Supported options are: "auto" (Default), "rgb", "ycbcr444", and</div><div>"ycbcr420"</div><div><br></div><div>This patch allows users to switch between pixel encodings, which is</div><div>specially important when auto gets it wrong (probably because of</div><div>monitor's manufacturer mistake) and needs user intervention.</div><div><br></div><div>Original patch by Yassine Imounachen</div><div>Rebased by Matias N. Goldberg <dark_sylinc@yahoo.com.ar></div><div><br></div><div>Full discussion:</div><div>https://gitlab.freedesktop.org/drm/amd/-/issues/476#note_2628536</div><div>---</div><div> drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  35 +++</div><div> drivers/gpu/drm/amd/amdgpu/amdgpu_display.h   |   3 +</div><div> drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h      |   2 +</div><div> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 215 +++++++++++++++++-</div><div> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   1 +</div><div> drivers/gpu/drm/amd/display/dc/core/dc.c      |   8 +</div><div> drivers/gpu/drm/amd/display/dc/dc_stream.h    |   2 +</div><div> drivers/gpu/drm/drm_modes.c                   |  29 +++</div><div> include/drm/drm_connector.h                   |   7 +</div><div> 9 files changed, 290 insertions(+), 12 deletions(-)</div><div><br></div><div>diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c</div><div>index b119d27271c1..9d201f368b6e 100644</div><div>--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c</div><div>+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c</div><div>@@ -1362,6 +1362,33 @@ static const struct drm_prop_enum_list amdgpu_dither_enum_list[] = {</div><div> <span>      </span>{ AMDGPU_FMT_DITHER_ENABLE, "on" },</div><div> };</div><div> </div><div>+static const struct drm_prop_enum_list amdgpu_user_pixenc_list[] = {</div><div>+<span>  </span>{ 0, "auto" },</div><div>+<span>       </span>{ DRM_COLOR_FORMAT_RGB444, "rgb" },</div><div>+<span>  </span>{ DRM_COLOR_FORMAT_YCBCR444, "ycbcr444" },</div><div>+<span>   </span>{ DRM_COLOR_FORMAT_YCBCR420, "ycbcr420" },</div><div>+};</div><div>+</div><div>+bool amdgpu_user_pixenc_from_name(</div><div>+<span>       </span>unsigned int *user_pixenc,</div><div>+<span>     </span>const char *pixenc_name)</div><div>+{</div><div>+<span>      </span>bool found = false;</div><div>+</div><div>+<span>    </span>if (pixenc_name && (*pixenc_name != '\0')) {</div><div>+<span>           </span>const int sz = ARRAY_SIZE(amdgpu_user_pixenc_list);</div><div>+<span>            </span>int i;</div><div>+</div><div>+<span>         </span>for (i = 0; !found && i < sz; ++i) {</div><div>+<span>                        </span>if (strcmp(pixenc_name, amdgpu_user_pixenc_list[i].name) == 0) {</div><div>+<span>                               </span>*user_pixenc = amdgpu_user_pixenc_list[i].type;</div><div>+<span>                                </span>found = true;</div><div>+<span>                  </span>}</div><div>+<span>              </span>}</div><div>+<span>      </span>}</div><div>+<span>      </span>return found;</div><div>+}</div><div>+</div><div> int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)</div><div> {</div><div> <span>      </span>int sz;</div><div>@@ -1408,6 +1435,14 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)</div><div> <span>                                  </span> "dither",</div><div> <span>                                      </span> amdgpu_dither_enum_list, sz);</div><div> </div><div>+<span>    </span>sz = ARRAY_SIZE(amdgpu_user_pixenc_list);</div><div>+<span>      </span>adev->mode_info.pixel_encoding_property =</div><div>+<span>           </span>drm_property_create_enum(adev_to_drm(adev), 0,</div><div>+<span>                 </span>"pixel encoding",</div><div>+<span>                    </span>amdgpu_user_pixenc_list, sz);</div><div>+<span>  </span>if (!adev->mode_info.pixel_encoding_property)</div><div>+<span>               </span>return -ENOMEM;</div><div>+</div><div> <span>   </span>return 0;</div><div> }</div><div> </div><div>diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h</div><div>index 9d19940f73c8..ee1ad49fa123 100644</div><div>--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h</div><div>+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h</div><div>@@ -49,4 +49,7 @@ amdgpu_lookup_format_info(u32 format, uint64_t modifier);</div><div> int amdgpu_display_suspend_helper(struct amdgpu_device *adev);</div><div> int amdgpu_display_resume_helper(struct amdgpu_device *adev);</div><div> </div><div>+bool amdgpu_user_pixenc_from_name(unsigned int *user_pixenc,</div><div>+<span>                                </span>  const char *pixenc_name);</div><div>+</div><div> #endif</div><div>diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h</div><div>index 5e3faefc5510..b984e66a5d75 100644</div><div>--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h</div><div>+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h</div><div>@@ -326,6 +326,8 @@ struct amdgpu_mode_info {</div><div> <span>    </span>struct drm_property *audio_property;</div><div> <span>      </span>/* FMT dithering */</div><div> <span>       </span>struct drm_property *dither_property;</div><div>+<span>  </span>/* User HDMI pixel encoding override */</div><div>+<span>        </span>struct drm_property *pixel_encoding_property;</div><div> <span>     </span>/* hardcoded DFP edid from BIOS */</div><div> <span>        </span>const struct drm_edid *bios_hardcoded_edid;</div><div> </div><div>diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</div><div>index bbfc47f6595f..2c03e0733178 100644</div><div>--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</div><div>+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c</div><div>@@ -6069,6 +6069,115 @@ static bool adjust_colour_depth_from_display_info(</div><div> <span>      </span>return false;</div><div> }</div><div> </div><div>+/* convert an pixel encoding property value to a dc_pixel_encoding */</div><div>+static bool drm_prop_to_dc_pixel_encoding(</div><div>+<span>        </span>enum dc_pixel_encoding *dc_pixenc,</div><div>+<span>     </span>unsigned int propval)</div><div>+{</div><div>+<span> </span>bool ret = false;</div><div>+</div><div>+<span>      </span>switch (propval) {</div><div>+<span>     </span>case 0:</div><div>+<span>                </span>*dc_pixenc = PIXEL_ENCODING_UNDEFINED;</div><div>+<span>         </span>ret = true;</div><div>+<span>            </span>break;</div><div>+<span> </span>case DRM_COLOR_FORMAT_RGB444:</div><div>+<span>          </span>*dc_pixenc = PIXEL_ENCODING_RGB;</div><div>+<span>               </span>ret = true;</div><div>+<span>            </span>break;</div><div>+<span> </span>case DRM_COLOR_FORMAT_YCBCR444:</div><div>+<span>                </span>*dc_pixenc = PIXEL_ENCODING_YCBCR444;</div><div>+<span>          </span>ret = true;</div><div>+<span>            </span>break;</div><div>+<span> </span>case DRM_COLOR_FORMAT_YCBCR420:</div><div>+<span>                </span>*dc_pixenc = PIXEL_ENCODING_YCBCR420;</div><div>+<span>          </span>ret = true;</div><div>+<span>            </span>break;</div><div>+<span> </span>default:</div><div>+<span>               </span>break;</div><div>+<span> </span>}</div><div>+<span>      </span>return ret;</div><div>+}</div><div>+</div><div>+/* convert an dc_pixel_encoding to a pixel encoding property value */</div><div>+static unsigned int dc_pixel_encoding_to_drm_prop(</div><div>+<span>    </span>enum dc_pixel_encoding pixel_encoding)</div><div>+{</div><div>+<span>        </span>unsigned int propval = 0;</div><div>+</div><div>+<span>      </span>switch (pixel_encoding) {</div><div>+<span>      </span>case PIXEL_ENCODING_RGB:</div><div>+<span>               </span>propval = DRM_COLOR_FORMAT_RGB444;</div><div>+<span>             </span>break;</div><div>+<span> </span>case PIXEL_ENCODING_YCBCR444:</div><div>+<span>          </span>propval = DRM_COLOR_FORMAT_YCBCR444;</div><div>+<span>           </span>break;</div><div>+<span> </span>case PIXEL_ENCODING_YCBCR420:</div><div>+<span>          </span>propval = DRM_COLOR_FORMAT_YCBCR420;</div><div>+<span>           </span>break;</div><div>+<span> </span>default:</div><div>+<span>               </span>break;</div><div>+<span> </span>}</div><div>+<span>      </span>return propval;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * Tries to read 'pixel_encoding' from the pixel_encoding DRM property on</div><div>+ * 'state'. Returns true if a supported, acceptable, non-undefined value is</div><div>+ * found; false otherwise. Only modifies 'pixel_encoding' if returning true.</div><div>+ */</div><div>+bool get_connector_state_pixel_encoding(</div><div>+<span>  </span>enum dc_pixel_encoding *pixel_encoding,</div><div>+<span>        </span>const struct drm_connector_state *state,</div><div>+<span>       </span>const struct drm_display_info *info,</div><div>+<span>   </span>const struct drm_display_mode *mode_in)</div><div>+{</div><div>+<span>       </span>bool ret = false;</div><div>+<span>      </span>struct dm_connector_state *dm_state;</div><div>+</div><div>+<span>   </span>dm_state = to_dm_connector_state(state);</div><div>+<span>       </span>if (!dm_state)</div><div>+<span>         </span>return false;</div><div>+</div><div>+<span>  </span>/* check encoding is supported */</div><div>+<span>      </span>switch (dm_state->pixel_encoding) {</div><div>+<span> </span>case PIXEL_ENCODING_RGB:</div><div>+<span>               </span>ret = (info->color_formats & DRM_COLOR_FORMAT_RGB444);</div><div>+<span>          </span>break;</div><div>+<span> </span>case PIXEL_ENCODING_YCBCR444:</div><div>+<span>          </span>ret = (info->color_formats & DRM_COLOR_FORMAT_YCBCR444);</div><div>+<span>                </span>break;</div><div>+<span> </span>case PIXEL_ENCODING_YCBCR420:</div><div>+<span>          </span>ret = drm_mode_is_420(info, mode_in);</div><div>+<span>          </span>break;</div><div>+<span> </span>default:</div><div>+<span>               </span>break;</div><div>+<span> </span>}</div><div>+</div><div>+<span>      </span>if (ret)</div><div>+<span>               </span>*pixel_encoding = dm_state->pixel_encoding;</div><div>+</div><div>+<span> </span>return ret;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * Writes 'pixel_encoding' to the pixel_encoding DRM property on 'state', if</div><div>+ * the enum value is valid and supported; otherwise writes</div><div>+ * PIXEL_ENCODING_UNDEFINED which corresponds to the "auto" property state.</div><div>+ */</div><div>+void set_connector_state_pixel_encoding(</div><div>+<span>   </span>const struct drm_connector_state *state,</div><div>+<span>       </span>enum dc_pixel_encoding pixel_encoding)</div><div>+{</div><div>+<span>        </span>struct dm_connector_state *dm_state;</div><div>+</div><div>+<span>   </span>dm_state = to_dm_connector_state(state);</div><div>+<span>       </span>if (!dm_state)</div><div>+<span>         </span>return;</div><div>+</div><div>+<span>        </span>dm_state->pixel_encoding = pixel_encoding;</div><div>+}</div><div>+</div><div> static void fill_stream_properties_from_drm_display_mode(</div><div> <span>      </span>struct dc_stream_state *stream,</div><div> <span>   </span>const struct drm_display_mode *mode_in,</div><div>@@ -6093,19 +6202,23 @@ static void fill_stream_properties_from_drm_display_mode(</div><div> <span>   </span>timing_out->h_border_right = 0;</div><div> <span>        </span>timing_out->v_border_top = 0;</div><div> <span>  </span>timing_out->v_border_bottom = 0;</div><div>-<span>    </span>/* TODO: un-hardcode */</div><div>-<span>        </span>if (drm_mode_is_420_only(info, mode_in)</div><div>+</div><div>+<span>        </span>if (!get_connector_state_pixel_encoding(&timing_out->pixel_encoding,</div><div>+<span>            </span>connector_state, info, mode_in)) {</div><div>+<span>             </span>/* auto-select a pixel encoding */</div><div>+<span>             </span>if (drm_mode_is_420_only(info, mode_in)</div><div> <span>                   </span>&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)</div><div>-<span>               </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;</div><div>-<span>       </span>else if (drm_mode_is_420_also(info, mode_in)</div><div>+<span>                   </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;</div><div>+<span>               </span>else if (drm_mode_is_420_also(info, mode_in)</div><div> <span>                      </span>&& aconnector</div><div> <span>                     </span>&& aconnector->force_yuv420_output)</div><div>-<span>         </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;</div><div>-<span>       </span>else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)</div><div>-<span>                    </span>&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)</div><div>-<span>               </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;</div><div>-<span>       </span>else</div><div>-<span>           </span>timing_out->pixel_encoding = PIXEL_ENCODING_RGB;</div><div>+<span>                    </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;</div><div>+<span>               </span>else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)</div><div>+<span>                            </span>&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)</div><div>+<span>                       </span>timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;</div><div>+<span>               </span>else</div><div>+<span>                   </span>timing_out->pixel_encoding = PIXEL_ENCODING_RGB;</div><div>+<span>    </span>}</div><div> </div><div> <span>    </span>timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;</div><div> <span>  </span>timing_out->display_color_depth = convert_color_depth_from_display_info(</div><div>@@ -6169,6 +6282,9 @@ static void fill_stream_properties_from_drm_display_mode(</div><div> <span>         </span>}</div><div> <span> </span>}</div><div> </div><div>+<span> </span>/* write back final choice of pixel encoding */</div><div>+<span>        </span>set_connector_state_pixel_encoding(connector_state, timing_out->pixel_encoding);</div><div>+</div><div> <span>       </span>stream->output_color_space = get_output_color_space(timing_out, connector_state);</div><div> <span>      </span>stream->content_type = get_output_content_type(connector_state);</div><div> }</div><div>@@ -6875,6 +6991,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,</div><div> <span>        </span>} else if (property == adev->mode_info.underscan_property) {</div><div> <span>           </span>dm_new_state->underscan_enable = val;</div><div> <span>          </span>ret = 0;</div><div>+<span>       </span>} else if (property == adev->mode_info.pixel_encoding_property) {</div><div>+<span>           </span>if (drm_prop_to_dc_pixel_encoding(&dm_new_state->pixel_encoding, val))</div><div>+<span>                  </span>ret = 0;</div><div> <span>  </span>}</div><div> </div><div> <span>    </span>return ret;</div><div>@@ -6917,6 +7036,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,</div><div> <span>      </span>} else if (property == adev->mode_info.underscan_property) {</div><div> <span>           </span>*val = dm_state->underscan_enable;</div><div> <span>             </span>ret = 0;</div><div>+<span>       </span>} else if (property == adev->mode_info.pixel_encoding_property) {</div><div>+<span>           </span>*val = dc_pixel_encoding_to_drm_prop(dm_state->pixel_encoding);</div><div>+<span>             </span>ret = 0;</div><div> <span>  </span>}</div><div> </div><div> <span>    </span>return ret;</div><div>@@ -7088,6 +7210,20 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)</div><div> <span>                            </span>state->abm_level = amdgpu_dm_abm_level;</div><div> <span>                </span>}</div><div> </div><div>+<span>         </span>switch (connector->cmdline_mode.pixel_encoding) {</div><div>+<span>           </span>case DRM_COLOR_FORMAT_RGB444:</div><div>+<span>                  </span>state->pixel_encoding = PIXEL_ENCODING_RGB;</div><div>+<span>                 </span>break;</div><div>+<span>         </span>case DRM_COLOR_FORMAT_YCBCR444:</div><div>+<span>                        </span>state->pixel_encoding = PIXEL_ENCODING_YCBCR444;</div><div>+<span>                    </span>break;</div><div>+<span>         </span>case DRM_COLOR_FORMAT_YCBCR420:</div><div>+<span>                        </span>state->pixel_encoding = PIXEL_ENCODING_YCBCR420;</div><div>+<span>                    </span>break;</div><div>+<span>         </span>default:</div><div>+<span>                       </span>break;</div><div>+<span>         </span>}</div><div>+</div><div> <span>         </span>__drm_atomic_helper_connector_reset(connector, &state->base);</div><div> <span>      </span>}</div><div> }</div><div>@@ -7114,6 +7250,7 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)</div><div> <span>   </span>new_state->underscan_vborder = state->underscan_vborder;</div><div> <span>    </span>new_state->vcpi_slots = state->vcpi_slots;</div><div> <span>  </span>new_state->pbn = state->pbn;</div><div>+<span>     </span>new_state->pixel_encoding = state->pixel_encoding;</div><div> <span>  </span>return &new_state->base;</div><div> }</div><div> </div><div>@@ -8175,6 +8312,12 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,</div><div> </div><div> <span>              </span>if (adev->dm.hdcp_workqueue)</div><div> <span>                   </span>drm_connector_attach_content_protection_property(&aconnector->base, true);</div><div>+</div><div>+<span>              </span>if (adev->mode_info.pixel_encoding_property) {</div><div>+<span>                      </span>drm_object_attach_property(&aconnector->base.base,</div><div>+<span>                              </span>adev->mode_info.pixel_encoding_property, 0);</div><div>+<span>                        </span>DRM_DEBUG_DRIVER("amdgpu: attached pixel encoding drm property");</div><div>+<span>            </span>}</div><div> <span> </span>}</div><div> }</div><div> </div><div>@@ -9377,6 +9520,38 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev,</div><div> <span>      </span>}</div><div> }</div><div> </div><div>+static void update_stream_for_pixel_encoding(</div><div>+<span>      </span>struct dc_stream_update *stream_update,</div><div>+<span>        </span>struct drm_connector *connector,</div><div>+<span>       </span>struct dm_crtc_state *dm_old_crtc_state,</div><div>+<span>       </span>struct dm_crtc_state *dm_new_crtc_state,</div><div>+<span>       </span>struct dm_connector_state *dm_new_con_state)</div><div>+{</div><div>+<span>  </span>struct amdgpu_dm_connector *aconnector =</div><div>+<span>               </span>to_amdgpu_dm_connector(connector);</div><div>+<span>     </span>struct dc_stream_state *new_stream = NULL;</div><div>+</div><div>+<span>     </span>if (aconnector)</div><div>+<span>                </span>new_stream = create_validate_stream_for_sink(</div><div>+<span>                  </span>aconnector,</div><div>+<span>                    </span>&dm_new_crtc_state->base.mode,</div><div>+<span>                  </span>dm_new_con_state,</div><div>+<span>                      </span>dm_old_crtc_state->stream);</div><div>+<span> </span>if (new_stream) {</div><div>+<span>              </span>dm_new_crtc_state->stream->timing =</div><div>+<span>                      </span>new_stream->timing;</div><div>+<span>         </span>stream_update->timing_for_pixel_encoding =</div><div>+<span>                  </span>&dm_new_crtc_state->stream->timing;</div><div>+</div><div>+<span>          </span>dm_new_crtc_state->stream->output_color_space =</div><div>+<span>                  </span>new_stream->output_color_space;</div><div>+<span>             </span>stream_update->output_color_space =</div><div>+<span>                 </span>&dm_new_crtc_state->stream->output_color_space;</div><div>+</div><div>+<span>              </span>dc_stream_release(new_stream);</div><div>+<span> </span>}</div><div>+}</div><div>+</div><div> /*</div><div>  * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC</div><div>  * @crtc_state: the DRM CRTC state</div><div>@@ -9850,7 +10025,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</div><div> <span>            </span>struct dc_stream_update stream_update;</div><div> <span>            </span>struct dc_info_packet hdr_packet;</div><div> <span>         </span>struct dc_stream_status *status = NULL;</div><div>-<span>                </span>bool abm_changed, hdr_changed, scaling_changed;</div><div>+<span>                </span>bool abm_changed, hdr_changed, scaling_changed, pixenc_changed;</div><div> </div><div> <span>              </span>memset(&stream_update, 0, sizeof(stream_update));</div><div> </div><div>@@ -9875,7 +10050,10 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</div><div> <span>         </span>hdr_changed =</div><div> <span>                     </span>!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state);</div><div> </div><div>-<span>           </span>if (!scaling_changed && !abm_changed && !hdr_changed)</div><div>+<span>          </span>pixenc_changed = dm_new_con_state->pixel_encoding !=</div><div>+<span>                                </span> dm_old_con_state->pixel_encoding;</div><div>+</div><div>+<span>          </span>if (!scaling_changed && !abm_changed && !hdr_changed && !pixenc_changed)</div><div> <span>                  </span>continue;</div><div> </div><div> <span>            </span>stream_update.stream = dm_new_crtc_state->stream;</div><div>@@ -9898,6 +10076,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)</div><div> <span>                       </span>stream_update.hdr_static_metadata = &hdr_packet;</div><div> <span>              </span>}</div><div> </div><div>+<span>         </span>if (pixenc_changed) {</div><div>+<span>                  </span>update_stream_for_pixel_encoding(&stream_update,</div><div>+<span>                           </span>connector,</div><div>+<span>                             </span>dm_old_crtc_state, dm_new_crtc_state,</div><div>+<span>                          </span>dm_new_con_state);</div><div>+<span>             </span>}</div><div>+</div><div> <span>         </span>status = dc_stream_get_status(dm_new_crtc_state->stream);</div><div> </div><div> <span>         </span>if (WARN_ON(!status))</div><div>@@ -11403,6 +11588,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,</div><div> <span>            </span>if (dm_old_con_state->abm_level != dm_new_con_state->abm_level ||</div><div> <span>           </span>    dm_old_con_state->scaling != dm_new_con_state->scaling)</div><div> <span>                       </span>new_crtc_state->connectors_changed = true;</div><div>+</div><div>+<span>          </span>if (dm_old_con_state->pixel_encoding !=</div><div>+<span>             </span>    dm_new_con_state->pixel_encoding) {</div><div>+<span>                   </span>new_crtc_state->connectors_changed = true;</div><div>+<span>                  </span>new_crtc_state->mode_changed = true;</div><div>+<span>                </span>}</div><div> <span> </span>}</div><div> </div><div> <span>    </span>if (dc_resource_is_dsc_encoding_supported(dc)) {</div><div>diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h</div><div>index 25e95775c45c..132944272c18 100644</div><div>--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h</div><div>+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h</div><div>@@ -918,6 +918,7 @@ struct dm_connector_state {</div><div> <span> </span>uint8_t abm_level;</div><div> <span>        </span>int vcpi_slots;</div><div> <span>   </span>uint64_t pbn;</div><div>+<span>  </span>enum dc_pixel_encoding pixel_encoding;</div><div> };</div><div> </div><div> #define to_dm_connector_state(x)\</div><div>diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c</div><div>index 5a12fc75f97f..4ac004536707 100644</div><div>--- a/drivers/gpu/drm/amd/display/dc/core/dc.c</div><div>+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c</div><div>@@ -2765,6 +2765,11 @@ static enum surface_update_type check_update_surfaces_for_stream(</div><div> <span>            </span>if (stream_update->output_csc_transform || stream_update->output_color_space)</div><div> <span>                       </span>su_flags->bits.out_csc = 1;</div><div> </div><div>+<span>            </span>if (stream_update->timing_for_pixel_encoding) {</div><div>+<span>                     </span>su_flags->bits.pixel_encoding = 1;</div><div>+<span>                  </span>elevate_update_type(&overall_type, UPDATE_TYPE_FULL);</div><div>+<span>              </span>}</div><div>+</div><div> <span>         </span>/* Output transfer function changes do not require bandwidth recalculation,</div><div> <span>               </span> * so don't trigger a full update</div><div> <span>         </span> */</div><div>@@ -3112,6 +3117,8 @@ static void copy_stream_update_to_stream(struct dc *dc,</div><div> <span>           </span>stream->scaler_sharpener_update = *update->scaler_sharpener_update;</div><div> <span> </span>if (update->sharpening_required)</div><div> <span>               </span>stream->sharpening_required = *update->sharpening_required;</div><div>+<span>      </span>if (update->timing_for_pixel_encoding)</div><div>+<span>              </span>stream->timing = *update->timing_for_pixel_encoding;</div><div> }</div><div> </div><div> static void backup_planes_and_stream_state(</div><div>@@ -3361,6 +3368,7 @@ static void commit_planes_do_stream_update(struct dc *dc,</div><div> <span>                                       </span>stream_update->vsc_infopacket ||</div><div> <span>                                       </span>stream_update->vsp_infopacket ||</div><div> <span>                                       </span>stream_update->hfvsif_infopacket ||</div><div>+<span>                                 </span>stream_update->timing_for_pixel_encoding ||</div><div> <span>                                    </span>stream_update->adaptive_sync_infopacket ||</div><div> <span>                                     </span>stream_update->vtem_infopacket) {</div><div> <span>                              </span>resource_build_info_frame(pipe_ctx);</div><div>diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h</div><div>index 413970588a26..de7f02f330d8 100644</div><div>--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h</div><div>+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h</div><div>@@ -144,6 +144,7 @@ union stream_update_flags {</div><div> <span>         </span>uint32_t fams_changed : 1;</div><div> <span>                </span>uint32_t scaler_sharpener : 1;</div><div> <span>            </span>uint32_t sharpening_required : 1;</div><div>+<span>              </span>uint32_t pixel_encoding:1;</div><div> <span>        </span>} bits;</div><div> </div><div> <span>      </span>uint32_t raw;</div><div>@@ -350,6 +351,7 @@ struct dc_stream_update {</div><div> <span> </span>struct dc_mst_stream_bw_update *mst_bw_update;</div><div> <span>    </span>struct dc_transfer_func *func_shaper;</div><div> <span>     </span>struct dc_3dlut *lut3d_func;</div><div>+<span>   </span>struct dc_crtc_timing *timing_for_pixel_encoding;</div><div> </div><div> <span>    </span>struct test_pattern *pending_test_pattern;</div><div> <span>        </span>struct dc_crtc_timing_adjust *crtc_timing_adjust;</div><div>diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c</div><div>index 1a0890083aee..b5ce8f93b672 100644</div><div>--- a/drivers/gpu/drm/drm_modes.c</div><div>+++ b/drivers/gpu/drm/drm_modes.c</div><div>@@ -2161,6 +2161,32 @@ static int drm_mode_parse_tv_mode(const char *delim,</div><div> <span>    </span>return 0;</div><div> }</div><div> </div><div>+static int drm_mode_parse_pixel_encoding(const char *delim,</div><div>+<span>                                        </span> struct drm_cmdline_mode *mode)</div><div>+{</div><div>+<span>       </span>const char *value;</div><div>+</div><div>+<span>     </span>if (*delim != '=')</div><div>+<span>             </span>return -EINVAL;</div><div>+</div><div>+<span>        </span>value = delim + 1;</div><div>+<span>     </span>delim = strchr(value, ',');</div><div>+<span>    </span>if (!delim)</div><div>+<span>            </span>delim = value + strlen(value);</div><div>+</div><div>+<span> </span>if (!strncmp(value, "auto", delim - value))</div><div>+<span>          </span>mode->pixel_encoding = 0;</div><div>+<span>   </span>else if (!strncmp(value, "rgb", delim - value))</div><div>+<span>              </span>mode->pixel_encoding = DRM_COLOR_FORMAT_RGB444;</div><div>+<span>     </span>else if (!strncmp(value, "ycbcr444", delim - value))</div><div>+<span>         </span>mode->pixel_encoding = DRM_COLOR_FORMAT_YCBCR444;</div><div>+<span>   </span>else if (!strncmp(value, "ycbcr420", delim - value))</div><div>+<span>         </span>mode->pixel_encoding = DRM_COLOR_FORMAT_YCBCR420;</div><div>+<span>   </span>else</div><div>+<span>           </span>return -EINVAL;</div><div>+</div><div>+<span>        </span>return 0;</div><div>+}</div><div> static int drm_mode_parse_cmdline_options(const char *str,</div><div> <span>                                 </span>  bool freestanding,</div><div> <span>                                 </span>  const struct drm_connector *connector,</div><div>@@ -2233,6 +2259,9 @@ static int drm_mode_parse_cmdline_options(const char *str,</div><div> <span>              </span>} else if (!strncmp(option, "tv_mode", delim - option)) {</div><div> <span>                       </span>if (drm_mode_parse_tv_mode(delim, mode))</div><div> <span>                          </span>return -EINVAL;</div><div>+<span>                </span>} else if (!strncmp(option, "pixel_encoding", delim - option)) {</div><div>+<span>                     </span>if (drm_mode_parse_pixel_encoding(delim, mode))</div><div>+<span>                                </span>return -EINVAL;</div><div> <span>           </span>} else {</div><div> <span>                  </span>return -EINVAL;</div><div> <span>           </span>}</div><div>diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h</div><div>index c754651044d4..89c0f42873df 100644</div><div>--- a/include/drm/drm_connector.h</div><div>+++ b/include/drm/drm_connector.h</div><div>@@ -1666,6 +1666,13 @@ struct drm_cmdline_mode {</div><div> <span>       </span> * Did the mode have a preferred TV mode?</div><div> <span> </span> */</div><div> <span>       </span>bool tv_mode_specified;</div><div>+</div><div>+<span>        </span>/**</div><div>+<span>    </span> * @pixel_encoding:</div><div>+<span>    </span> *</div><div>+<span>     </span> * Initial pixel encoding.</div><div>+<span>     </span> */</div><div>+<span>    </span>unsigned int pixel_encoding;</div><div> };</div><div> </div><div> /*</div><div>-- </div><div>2.43.0</div></div></body></html>