diff options
author | Jeka | 2023-08-18 15:43:39 +0300 |
---|---|---|
committer | Jeka | 2023-08-18 15:43:39 +0300 |
commit | ce5e811f08877f45fbe8a2db2a2505c0e7ff616e (patch) | |
tree | 15904a0dff3827b71513ebccfe97eebf6389566e | |
parent | e25597378330efad314f8c624653820d0b2b8c27 (diff) | |
download | aur-ce5e811f08877f45fbe8a2db2a2505c0e7ff616e.tar.gz |
kernel release 6.4.11
21 files changed, 8105 insertions, 14 deletions
@@ -1,6 +1,6 @@ pkgbase = linux-jcore pkgdesc = Kernel for Manjaro/EndeavourOS/Arch (ACS override patch include) - pkgver = 6.4.8 + pkgver = 6.4.11 pkgrel = 1 url = https://www.kernel.org/ arch = x86_64 @@ -21,22 +21,44 @@ pkgbase = linux-jcore replaces = linux-acs-manjaro replaces = linux-acs-manjaro-headers options = !strip - source = https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.4.8.tar.xz + source = https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.4.11.tar.xz source = config source = 0101-ZEN_Add_sysctl_and_CONFIG_to_disallow_unprivileged_CLONE_NEWUSER.patch - source = 0102-mm-disable_CONFIG_PER_VMA_LOCK.patch + source = e65a5fe09577d17e2fded61067f759f2bf02f6c0.patch source = 0203-asus-ally-asus-hid-6.3-v2.patch source = 0204-mt7921e_Perform_FLR_to_recovery_the_device.patch source = 0206-asus-ally-bluetooth.patch source = 0999-acs.gitpatch - sha256sums = c59f34e19e84db30206b9373041abf893f9d8a08765d163586570a5238c458b6 - sha256sums = 01d2816ad5365884470a76f719593dd529fa9c32e1781d52d0144ef7c81d31ab + source = 0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch + source = 0002-ALSA-cs35l41-Poll-for-Power-Up-Down-rather-than-wait.patch + source = 0003-ALSA-hda-cs35l41-Check-mailbox-status-of-pause-comma.patch + source = 0004-ALSA-hda-cs35l41-Ensure-we-correctly-re-sync-regmap-.patch + source = 0005-ALSA-hda-cs35l41-Ensure-we-pass-up-any-errors-during.patch + source = 0006-ALSA-hda-cs35l41-Move-Play-and-Pause-into-separate-f.patch + source = 0007-ALSA-hda-hda_component-Add-pre-and-post-playback-hoo.patch + source = 0008-ALSA-hda-cs35l41-Use-pre-and-post-playback-hooks.patch + source = 0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch + source = 0010-ALSA-hda-cs35l41-Add-device_link-between-HDA-and-cs3.patch + source = 0011-ALSA-hda-cs35l41-Ensure-amp-is-only-unmuted-during-p.patch + sha256sums = 546b68b5097d3c0d74722de62aae217729d98e45fbb6bd458b490ac21ea40918 + sha256sums = f55c1744ab79ba72a987c333c1feaf2290d5dcec709596a0d9f84f00839a51a7 sha256sums = 05f04019d4a2ee072238c32860fa80d673687d84d78ef436ae9332b6fb788467 - sha256sums = 7e79a1cc688189c66837611aa42ecf65a4f2fb071920830e9f4db923a13e9105 + sha256sums = 36a32f67a9725ae96ad0ba0fb8a6262f666c53e304cc142e88826daa0afc65aa sha256sums = a38b50b8c73332d3d16950bf8adcae7ead34391a60f74d05a58935cd3dc8a12d sha256sums = d673d034fbcd80426fd8d9c6af56537c5fe5b55fe49d74e313474d7fc285ecc1 sha256sums = d5f95fe43882fb68c0a7e1ce8d831788e222f841de3e636e85a89ea655fed40e sha256sums = 458d7e024d33d4965b14b9b987f01a2884ff28761cff5da7c6a54132a95e9f36 + sha256sums = 27aaf7e14c7f5e127f5b658352ca5c3650477a92462139557aefb73bcea2b418 + sha256sums = 74da118887929f06afb57eaee716ff433ee5972c9dc91166fc08e66f44edb8e8 + sha256sums = c5ac510677e58ac6b189939ac853e64bf9ad026a614a47f4cb535ad62bf41163 + sha256sums = 88f0d69dad01ccfef899b6b08abe162fc7743d40571232dff9a7d9093890d0a8 + sha256sums = 826bfa21b613d9c198d375d902958c90bb30171aee602c1806aaf99212abbb40 + sha256sums = 0dae5e24249b712f1501ead600c8ef4a5df21484e39e06a1dbafb57929c4999f + sha256sums = 8dddf5537e3feedbf9f9c67f3c19fa7412d9e01b4f78023262b8fa340d3f47b2 + sha256sums = 3774b4eba753eb5f3768a28a68eb1a17557c0347275c19b8133f9f74d64a80df + sha256sums = a5daf210a6f72dde5b477d4b6d38a162b2698cac6c5fcfd4e4fd606274f34cec + sha256sums = b9298bde48a9f6c5d028150d627c05c71880e2693933ef2fe070f090e80876a5 + sha256sums = 4d53a6853b63c0f01b60b408bee61fa729656f925e50fa55ae3cba309668242a pkgname = linux-jcore pkgdesc = Kernel for Manjaro/EndeavourOS/Arch (ACS override patch include) diff --git a/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch b/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch new file mode 100644 index 000000000000..57823933eba4 --- /dev/null +++ b/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch @@ -0,0 +1,238 @@ +From c21139c6470a5b08c7463e451f2ff404e55f652f Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:06 +0100 +Subject: [PATCH 01/11] ALSA: cs35l41: Use mbox command to enable speaker + output for external boost + +To enable the speaker output in external boost mode, 2 registers must +be set, one after another. The longer the time between the writes of +the two registers, the more likely, and more loudly a pop may occur. +To minimize this, an mbox command can be used to allow the firmware +to perform this action, minimizing any delay between write, thus +minimizing any pop or click as a result. The old method will remain +when running without firmware. + +Acked-by: Mark Brown <broonie@kernel.org> +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + include/sound/cs35l41.h | 5 ++- + sound/pci/hda/cs35l41_hda.c | 9 ++-- + sound/soc/codecs/cs35l41-lib.c | 76 +++++++++++++++++++++++++++------- + sound/soc/codecs/cs35l41.c | 8 ++-- + 4 files changed, 74 insertions(+), 24 deletions(-) + +diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h +index 7239d943942c..1bf757901d02 100644 +--- a/include/sound/cs35l41.h ++++ b/include/sound/cs35l41.h +@@ -829,6 +829,7 @@ enum cs35l41_cspl_mbox_cmd { + CSPL_MBOX_CMD_STOP_PRE_REINIT = 4, + CSPL_MBOX_CMD_HIBERNATE = 5, + CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6, ++ CSPL_MBOX_CMD_SPK_OUT_ENABLE = 7, + CSPL_MBOX_CMD_UNKNOWN_CMD = -1, + CSPL_MBOX_CMD_INVALID_SEQUENCE = -2, + }; +@@ -901,7 +902,7 @@ int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap); + int cs35l41_init_boost(struct device *dev, struct regmap *regmap, + struct cs35l41_hw_cfg *hw_cfg); + bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type); +-int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, +- struct completion *pll_lock); ++int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, ++ int enable, struct completion *pll_lock, bool firmware_running); + + #endif /* __CS35L41_H */ +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index ce5faa620517..f9c97270db6f 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -514,13 +514,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) + break; + case HDA_GEN_PCM_ACT_PREPARE: + mutex_lock(&cs35l41->fw_mutex); +- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1, NULL); ++ ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, ++ cs35l41->firmware_running); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + mutex_lock(&cs35l41->fw_mutex); + regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); +- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0, NULL); ++ ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, ++ cs35l41->firmware_running); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLOSE: +@@ -672,7 +674,8 @@ static int cs35l41_runtime_suspend(struct device *dev) + if (cs35l41->playback_started) { + regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, + ARRAY_SIZE(cs35l41_hda_mute)); +- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, NULL); ++ cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, ++ NULL, cs35l41->firmware_running); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); + if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) +diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c +index 1e4205295a0d..a7556fa33cdd 100644 +--- a/sound/soc/codecs/cs35l41-lib.c ++++ b/sound/soc/codecs/cs35l41-lib.c +@@ -1080,28 +1080,32 @@ static const struct reg_sequence cs35l41_safe_to_reset[] = { + { 0x00000040, 0x00000033 }, + }; + +-static const struct reg_sequence cs35l41_active_to_safe[] = { ++static const struct reg_sequence cs35l41_active_to_safe_start[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x00007438, 0x00585941 }, + { CS35L41_PWR_CTRL1, 0x00000000 }, +- { 0x0000742C, 0x00000009, 3000 }, ++ { 0x0000742C, 0x00000009 }, ++}; ++ ++static const struct reg_sequence cs35l41_active_to_safe_end[] = { + { 0x00007438, 0x00580941 }, + { 0x00000040, 0x000000CC }, + { 0x00000040, 0x00000033 }, + }; + +-static const struct reg_sequence cs35l41_safe_to_active[] = { ++static const struct reg_sequence cs35l41_safe_to_active_start[] = { + { 0x00000040, 0x00000055 }, + { 0x00000040, 0x000000AA }, + { 0x0000742C, 0x0000000F }, + { 0x0000742C, 0x00000079 }, + { 0x00007438, 0x00585941 }, +- { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1 ++ { CS35L41_PWR_CTRL1, 0x00000001 }, // GLOBAL_EN = 1 ++}; ++ ++static const struct reg_sequence cs35l41_safe_to_active_en_spk[] = { + { 0x0000742C, 0x000000F9 }, + { 0x00007438, 0x00580941 }, +- { 0x00000040, 0x000000CC }, +- { 0x00000040, 0x00000033 }, + }; + + static const struct reg_sequence cs35l41_reset_to_safe[] = { +@@ -1188,11 +1192,11 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type) + } + EXPORT_SYMBOL_GPL(cs35l41_safe_reset); + +-int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, +- struct completion *pll_lock) ++int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type, ++ int enable, struct completion *pll_lock, bool firmware_running) + { + int ret; +- unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3; ++ unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status; + struct reg_sequence cs35l41_mdsync_down_seq[] = { + {CS35L41_PWR_CTRL3, 0}, + {CS35L41_GPIO_PAD_CONTROL, 0}, +@@ -1204,6 +1208,14 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, + {CS35L41_PWR_CTRL1, 0x00000001, 3000}, + }; + ++ if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) { ++ dev_dbg(dev, "Cannot set Global Enable - already set.\n"); ++ return 0; ++ } else if (!(pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && !enable) { ++ dev_dbg(dev, "Cannot unset Global Enable - not set.\n"); ++ return 0; ++ } ++ + switch (b_type) { + case CS35L41_SHD_BOOST_ACTV: + case CS35L41_SHD_BOOST_PASS: +@@ -1244,16 +1256,48 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, + case CS35L41_INT_BOOST: + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, + enable << CS35L41_GLOBAL_EN_SHIFT); ++ if (ret) { ++ dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret); ++ return ret; ++ } + usleep_range(3000, 3100); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: +- if (enable) +- ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active, +- ARRAY_SIZE(cs35l41_safe_to_active)); +- else +- ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe, +- ARRAY_SIZE(cs35l41_active_to_safe)); ++ if (enable) { ++ /* Test Key is unlocked here */ ++ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_start, ++ ARRAY_SIZE(cs35l41_safe_to_active_start)); ++ if (ret) ++ return ret; ++ ++ usleep_range(3000, 3100); ++ ++ if (firmware_running) ++ ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, ++ CSPL_MBOX_CMD_SPK_OUT_ENABLE); ++ else ++ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_en_spk, ++ ARRAY_SIZE(cs35l41_safe_to_active_en_spk)); ++ ++ /* Lock the test key, it was unlocked during the multi_reg_write */ ++ cs35l41_test_key_lock(dev, regmap); ++ } else { ++ /* Test Key is unlocked here */ ++ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_start, ++ ARRAY_SIZE(cs35l41_active_to_safe_start)); ++ if (ret) { ++ /* Lock the test key, it was unlocked during the multi_reg_write */ ++ cs35l41_test_key_lock(dev, regmap); ++ return ret; ++ } ++ ++ usleep_range(3000, 3100); ++ ++ /* Test Key is locked here */ ++ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end, ++ ARRAY_SIZE(cs35l41_active_to_safe_end)); ++ } + break; + default: + ret = -EINVAL; +@@ -1344,6 +1388,8 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd, + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_STOP_PRE_REINIT: + return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); ++ case CSPL_MBOX_CMD_SPK_OUT_ENABLE: ++ return (sts == CSPL_MBOX_STS_RUNNING); + default: + return false; + } +diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c +index 6ac501f008ec..d4e9c9d9b50a 100644 +--- a/sound/soc/codecs/cs35l41.c ++++ b/sound/soc/codecs/cs35l41.c +@@ -500,12 +500,12 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + cs35l41_pup_patch, + ARRAY_SIZE(cs35l41_pup_patch)); + +- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1, +- &cs35l41->pll_lock); ++ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, ++ 1, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); + break; + case SND_SOC_DAPM_POST_PMD: +- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, +- &cs35l41->pll_lock); ++ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, ++ 0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); + + ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + val, val & CS35L41_PDN_DONE_MASK, +-- +2.41.0 + diff --git a/0002-ALSA-cs35l41-Poll-for-Power-Up-Down-rather-than-wait.patch b/0002-ALSA-cs35l41-Poll-for-Power-Up-Down-rather-than-wait.patch new file mode 100644 index 000000000000..396384f9a457 --- /dev/null +++ b/0002-ALSA-cs35l41-Poll-for-Power-Up-Down-rather-than-wait.patch @@ -0,0 +1,141 @@ +From 437f5415c5ac8e49b0675f74132b6e1308b6e5c7 Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:07 +0100 +Subject: [PATCH 02/11] ALSA: cs35l41: Poll for Power Up/Down rather than + waiting a fixed delay + +To ensure the chip has correctly powered up or down before continuing, +the driver will now poll a register, rather than wait a fixed delay. + +Acked-by: Mark Brown <broonie@kernel.org> +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/soc/codecs/cs35l41-lib.c | 48 +++++++++++++++++++++++++++++++--- + sound/soc/codecs/cs35l41.c | 10 ------- + 2 files changed, 44 insertions(+), 14 deletions(-) + +diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c +index a7556fa33cdd..a9c559a676e7 100644 +--- a/sound/soc/codecs/cs35l41-lib.c ++++ b/sound/soc/codecs/cs35l41-lib.c +@@ -1196,7 +1196,8 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + int enable, struct completion *pll_lock, bool firmware_running) + { + int ret; +- unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status; ++ unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask; ++ unsigned int pwr_ctl1_val; + struct reg_sequence cs35l41_mdsync_down_seq[] = { + {CS35L41_PWR_CTRL3, 0}, + {CS35L41_GPIO_PAD_CONTROL, 0}, +@@ -1208,6 +1209,12 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + {CS35L41_PWR_CTRL1, 0x00000001, 3000}, + }; + ++ pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK; ++ ++ ret = regmap_read(regmap, CS35L41_PWR_CTRL1, &pwr_ctl1_val); ++ if (ret) ++ return ret; ++ + if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) { + dev_dbg(dev, "Cannot set Global Enable - already set.\n"); + return 0; +@@ -1252,6 +1259,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_up_seq, + ARRAY_SIZE(cs35l41_mdsync_up_seq)); + } ++ ++ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, ++ int_status, int_status & pup_pdn_mask, ++ 1000, 100000); ++ if (ret) ++ dev_err(dev, "Enable(%d) failed: %d\n", enable, ret); ++ ++ // Clear PUP/PDN status ++ regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask); + break; + case CS35L41_INT_BOOST: + ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, +@@ -1260,7 +1276,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret); + return ret; + } +- usleep_range(3000, 3100); ++ ++ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, ++ int_status, int_status & pup_pdn_mask, ++ 1000, 100000); ++ if (ret) ++ dev_err(dev, "Enable(%d) failed: %d\n", enable, ret); ++ ++ /* Clear PUP/PDN status */ ++ regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask); + break; + case CS35L41_EXT_BOOST: + case CS35L41_EXT_BOOST_NO_VSPK_SWITCH: +@@ -1271,7 +1295,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + if (ret) + return ret; + +- usleep_range(3000, 3100); ++ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status, ++ int_status & CS35L41_PUP_DONE_MASK, 1000, 100000); ++ if (ret) { ++ dev_err(dev, "Failed waiting for CS35L41_PUP_DONE_MASK: %d\n", ret); ++ /* Lock the test key, it was unlocked during the multi_reg_write */ ++ cs35l41_test_key_lock(dev, regmap); ++ return ret; ++ } ++ regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PUP_DONE_MASK); + + if (firmware_running) + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, +@@ -1292,7 +1324,15 @@ int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l4 + return ret; + } + +- usleep_range(3000, 3100); ++ ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status, ++ int_status & CS35L41_PDN_DONE_MASK, 1000, 100000); ++ if (ret) { ++ dev_err(dev, "Failed waiting for CS35L41_PDN_DONE_MASK: %d\n", ret); ++ /* Lock the test key, it was unlocked during the multi_reg_write */ ++ cs35l41_test_key_lock(dev, regmap); ++ return ret; ++ } ++ regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PDN_DONE_MASK); + + /* Test Key is locked here */ + ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end, +diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c +index d4e9c9d9b50a..2b3c36f02edb 100644 +--- a/sound/soc/codecs/cs35l41.c ++++ b/sound/soc/codecs/cs35l41.c +@@ -491,7 +491,6 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + { + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component); +- unsigned int val; + int ret = 0; + + switch (event) { +@@ -507,15 +506,6 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, + 0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running); + +- ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, +- val, val & CS35L41_PDN_DONE_MASK, +- 1000, 100000); +- if (ret) +- dev_warn(cs35l41->dev, "PDN failed: %d\n", ret); +- +- regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, +- CS35L41_PDN_DONE_MASK); +- + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pdn_patch, + ARRAY_SIZE(cs35l41_pdn_patch)); +-- +2.41.0 + diff --git a/0003-ALSA-hda-cs35l41-Check-mailbox-status-of-pause-comma.patch b/0003-ALSA-hda-cs35l41-Check-mailbox-status-of-pause-comma.patch new file mode 100644 index 000000000000..6eb272a81b13 --- /dev/null +++ b/0003-ALSA-hda-cs35l41-Check-mailbox-status-of-pause-comma.patch @@ -0,0 +1,36 @@ +From 796af5ec6c6bb2eadf78a96f629e2c7fba11123b Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:08 +0100 +Subject: [PATCH 03/11] ALSA: hda: cs35l41: Check mailbox status of pause + command after firmware load + +Currently, we do not check the return status of the pause command, +immediately after we load firmware. If the pause has failed, +the firmware is not running. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index f9c97270db6f..29f1dce45f1d 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -781,7 +781,12 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41) + goto clean_dsp; + } + +- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE); ++ ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE); ++ if (ret) { ++ dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret); ++ goto clean_dsp; ++ } ++ + cs35l41->firmware_running = true; + + return 0; +-- +2.41.0 + diff --git a/0004-ALSA-hda-cs35l41-Ensure-we-correctly-re-sync-regmap-.patch b/0004-ALSA-hda-cs35l41-Ensure-we-correctly-re-sync-regmap-.patch new file mode 100644 index 000000000000..d7cce6083559 --- /dev/null +++ b/0004-ALSA-hda-cs35l41-Ensure-we-correctly-re-sync-regmap-.patch @@ -0,0 +1,74 @@ +From 9684d3a1fbe55573eccd6c7e5f72dd519a4e406b Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:09 +0100 +Subject: [PATCH 04/11] ALSA: hda: cs35l41: Ensure we correctly re-sync regmap + before system suspending. + +In order to properly system suspend, it is necessary to unload the firmware +and ensure the chip is ready for shutdown (if necessary). If the system +is currently in runtime suspend, it is necessary to wake up the device, +and then make it ready. Currently, the wake does not correctly resync +the device, which may mean it cannot suspend correctly. Fix this by +performaing a resync. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index 29f1dce45f1d..f42457147ce4 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -574,21 +574,43 @@ static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsi + rx_slot); + } + +-static void cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) ++static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) + { ++ int ret = 0; ++ + mutex_lock(&cs35l41->fw_mutex); + if (cs35l41->firmware_running) { + + regcache_cache_only(cs35l41->regmap, false); + +- cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); ++ ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); ++ if (ret) { ++ dev_warn(cs35l41->dev, "Unable to exit Hibernate."); ++ goto err; ++ } ++ ++ /* Test key needs to be unlocked to allow the OTP settings to re-apply */ ++ cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap); ++ ret = regcache_sync(cs35l41->regmap); ++ cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap); ++ if (ret) { ++ dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret); ++ goto err; ++ } ++ ++ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) ++ cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg); ++ + cs35l41_shutdown_dsp(cs35l41); + cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); +- +- regcache_cache_only(cs35l41->regmap, true); +- regcache_mark_dirty(cs35l41->regmap); + } ++err: ++ regcache_cache_only(cs35l41->regmap, true); ++ regcache_mark_dirty(cs35l41->regmap); ++ + mutex_unlock(&cs35l41->fw_mutex); ++ ++ return ret; + } + + static int cs35l41_system_suspend(struct device *dev) +-- +2.41.0 + diff --git a/0005-ALSA-hda-cs35l41-Ensure-we-pass-up-any-errors-during.patch b/0005-ALSA-hda-cs35l41-Ensure-we-pass-up-any-errors-during.patch new file mode 100644 index 000000000000..5ced08481c91 --- /dev/null +++ b/0005-ALSA-hda-cs35l41-Ensure-we-pass-up-any-errors-during.patch @@ -0,0 +1,63 @@ +From 05bfc01172a34466e660465922d1cab5b460880f Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:10 +0100 +Subject: [PATCH 05/11] ALSA: hda: cs35l41: Ensure we pass up any errors during + system suspend. + +There are several steps required to put the system into system suspend. +Some of these steps may fail, so the driver should pass up the errors +if they occur. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index f42457147ce4..d4a11f7b5dbd 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -626,17 +626,22 @@ static int cs35l41_system_suspend(struct device *dev) + } + + ret = pm_runtime_force_suspend(dev); +- if (ret) ++ if (ret) { ++ dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret); + return ret; ++ } + + /* Shutdown DSP before system suspend */ +- cs35l41_ready_for_reset(cs35l41); ++ ret = cs35l41_ready_for_reset(cs35l41); ++ ++ if (ret) ++ dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret); + + /* + * Reset GPIO may be shared, so cannot reset here. + * However beyond this point, amps may be powered down. + */ +- return 0; ++ return ret; + } + + static int cs35l41_system_resume(struct device *dev) +@@ -659,9 +664,13 @@ static int cs35l41_system_resume(struct device *dev) + usleep_range(2000, 2100); + + ret = pm_runtime_force_resume(dev); ++ if (ret) { ++ dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret); ++ return ret; ++ } + + mutex_lock(&cs35l41->fw_mutex); +- if (!ret && cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { ++ if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { + cs35l41->fw_request_ongoing = true; + schedule_work(&cs35l41->fw_load_work); + } +-- +2.41.0 + diff --git a/0006-ALSA-hda-cs35l41-Move-Play-and-Pause-into-separate-f.patch b/0006-ALSA-hda-cs35l41-Move-Play-and-Pause-into-separate-f.patch new file mode 100644 index 000000000000..b79792840f63 --- /dev/null +++ b/0006-ALSA-hda-cs35l41-Move-Play-and-Pause-into-separate-f.patch @@ -0,0 +1,193 @@ +From f352ce9e5389e4746f25bfec33f4e0ee4dcbf690 Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:11 +0100 +Subject: [PATCH 06/11] ALSA: hda: cs35l41: Move Play and Pause into separate + functions + +This allows play and pause to be called from multiple places, +which is necessary for system suspend and resume. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 131 ++++++++++++++++++++++-------------- + 1 file changed, 79 insertions(+), 52 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index d4a11f7b5dbd..f77583b46b6b 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -483,63 +483,103 @@ static void cs35l41_irq_release(struct cs35l41_hda *cs35l41) + cs35l41->irq_errors = 0; + } + +-static void cs35l41_hda_playback_hook(struct device *dev, int action) ++static void cs35l41_hda_play_start(struct device *dev) + { + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct regmap *reg = cs35l41->regmap; +- int ret = 0; ++ ++ dev_dbg(dev, "Play (Start)\n"); ++ ++ if (cs35l41->playback_started) { ++ dev_dbg(dev, "Playback already started."); ++ return; ++ } ++ ++ cs35l41->playback_started = true; ++ ++ if (cs35l41->firmware_running) { ++ regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, ++ ARRAY_SIZE(cs35l41_hda_config_dsp)); ++ regmap_update_bits(reg, CS35L41_PWR_CTRL2, ++ CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, ++ 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT); ++ cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME); ++ } else { ++ regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config)); ++ } ++ regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT); ++ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) ++ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001); ++ ++} ++ ++static void cs35l41_hda_play_done(struct device *dev) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ struct regmap *reg = cs35l41->regmap; ++ ++ dev_dbg(dev, "Play (Complete)\n"); ++ ++ cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, ++ cs35l41->firmware_running); ++} ++ ++static void cs35l41_hda_pause_start(struct device *dev) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ struct regmap *reg = cs35l41->regmap; ++ ++ dev_dbg(dev, "Pause (Start)\n"); ++ ++ regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); ++ cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, ++ cs35l41->firmware_running); ++} ++ ++static void cs35l41_hda_pause_done(struct device *dev) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ struct regmap *reg = cs35l41->regmap; ++ ++ dev_dbg(dev, "Pause (Complete)\n"); ++ ++ regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); ++ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) ++ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001); ++ if (cs35l41->firmware_running) { ++ cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE); ++ regmap_update_bits(reg, CS35L41_PWR_CTRL2, ++ CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, ++ 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); ++ } ++ cs35l41_irq_release(cs35l41); ++ cs35l41->playback_started = false; ++} ++ ++static void cs35l41_hda_playback_hook(struct device *dev, int action) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: + pm_runtime_get_sync(dev); + mutex_lock(&cs35l41->fw_mutex); +- cs35l41->playback_started = true; +- if (cs35l41->firmware_running) { +- regmap_multi_reg_write(reg, cs35l41_hda_config_dsp, +- ARRAY_SIZE(cs35l41_hda_config_dsp)); +- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, +- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, +- 1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT); +- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, +- CSPL_MBOX_CMD_RESUME); +- } else { +- regmap_multi_reg_write(reg, cs35l41_hda_config, +- ARRAY_SIZE(cs35l41_hda_config)); +- } +- ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2, +- CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT); +- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) +- regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001); ++ cs35l41_hda_play_start(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_PREPARE: + mutex_lock(&cs35l41->fw_mutex); +- ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, +- cs35l41->firmware_running); ++ cs35l41_hda_play_done(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + mutex_lock(&cs35l41->fw_mutex); +- regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute)); +- ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL, +- cs35l41->firmware_running); ++ cs35l41_hda_pause_start(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLOSE: + mutex_lock(&cs35l41->fw_mutex); +- ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2, +- CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); +- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) +- regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001); +- if (cs35l41->firmware_running) { +- cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, +- CSPL_MBOX_CMD_PAUSE); +- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, +- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, +- 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); +- } +- cs35l41_irq_release(cs35l41); +- cs35l41->playback_started = false; ++ cs35l41_hda_pause_done(dev); + mutex_unlock(&cs35l41->fw_mutex); + + pm_runtime_mark_last_busy(dev); +@@ -549,9 +589,6 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) + dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); + break; + } +- +- if (ret) +- dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret); + } + + static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot, +@@ -703,18 +740,8 @@ static int cs35l41_runtime_suspend(struct device *dev) + mutex_lock(&cs35l41->fw_mutex); + + if (cs35l41->playback_started) { +- regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, +- ARRAY_SIZE(cs35l41_hda_mute)); +- cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, +- NULL, cs35l41->firmware_running); +- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, +- CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT); +- if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) +- regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001); +- regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, +- CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK, +- 0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT); +- cs35l41->playback_started = false; ++ cs35l41_hda_pause_start(dev); ++ cs35l41_hda_pause_done(dev); + } + + if (cs35l41->firmware_running) { +-- +2.41.0 + diff --git a/0007-ALSA-hda-hda_component-Add-pre-and-post-playback-hoo.patch b/0007-ALSA-hda-hda_component-Add-pre-and-post-playback-hoo.patch new file mode 100644 index 000000000000..ab7d89945d9f --- /dev/null +++ b/0007-ALSA-hda-hda_component-Add-pre-and-post-playback-hoo.patch @@ -0,0 +1,56 @@ +From c1bf8ed3a5f3d011276d975c7b1f62039bed160e Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:12 +0100 +Subject: [PATCH 07/11] ALSA: hda: hda_component: Add pre and post playback + hooks to hda_component + +These hooks can be used to add callbacks that would be run before and after +the main playback hooks. These hooks would be called for all amps, before +moving on to the next hook, i.e. pre_playback_hook would be called for +all amps, before the playback_hook is called for all amps, then finally +the post_playback_hook is called for all amps. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/hda_component.h | 2 ++ + sound/pci/hda/patch_realtek.c | 10 +++++++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h +index 534e845b9cd1..f170aec967c1 100644 +--- a/sound/pci/hda/hda_component.h ++++ b/sound/pci/hda/hda_component.h +@@ -15,5 +15,7 @@ struct hda_component { + struct device *dev; + char name[HDA_MAX_NAME_SIZE]; + struct hda_codec *codec; ++ void (*pre_playback_hook)(struct device *dev, int action); + void (*playback_hook)(struct device *dev, int action); ++ void (*post_playback_hook)(struct device *dev, int action); + }; +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 44fccfb93cff..dff92679ae72 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6716,9 +6716,17 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ + int i; + + for (i = 0; i < HDA_MAX_COMPONENTS; i++) { +- if (spec->comps[i].dev) ++ if (spec->comps[i].dev && spec->comps[i].pre_playback_hook) ++ spec->comps[i].pre_playback_hook(spec->comps[i].dev, action); ++ } ++ for (i = 0; i < HDA_MAX_COMPONENTS; i++) { ++ if (spec->comps[i].dev && spec->comps[i].playback_hook) + spec->comps[i].playback_hook(spec->comps[i].dev, action); + } ++ for (i = 0; i < HDA_MAX_COMPONENTS; i++) { ++ if (spec->comps[i].dev && spec->comps[i].post_playback_hook) ++ spec->comps[i].post_playback_hook(spec->comps[i].dev, action); ++ } + } + + struct cs35l41_dev_name { +-- +2.41.0 + diff --git a/0008-ALSA-hda-cs35l41-Use-pre-and-post-playback-hooks.patch b/0008-ALSA-hda-cs35l41-Use-pre-and-post-playback-hooks.patch new file mode 100644 index 000000000000..ac5b0290b2bc --- /dev/null +++ b/0008-ALSA-hda-cs35l41-Use-pre-and-post-playback-hooks.patch @@ -0,0 +1,122 @@ +From 4f3b42e2f126f96b1e512871d7073fb10d9a7283 Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:13 +0100 +Subject: [PATCH 08/11] ALSA: hda: cs35l41: Use pre and post playback hooks + +Use new hooks to ensure separation between play/pause actions, +as required by external boost. + +External Boost on CS35L41 requires the amp to go through a +particular sequence of steps. One of these steps involes +the setting of a GPIO. This GPIO is connected to one or +more of the amps, and it may control the boost for all of +the amps. To ensure that the GPIO is set when it is safe +to do so, and to ensure that boost is ready for the rest of +the sequence to be able to continue, we must ensure that +the each part of the sequence is executed for each amp +before moving on to the next part of the sequence. + +Some of the Play and Pause actions have moved from Open to +Prepare. This is because Open is not guaranteed to be called +again on system resume, whereas Prepare should. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 53 ++++++++++++++++++++++++++++++------- + 1 file changed, 43 insertions(+), 10 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index f77583b46b6b..a482d4752b3f 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -556,37 +556,68 @@ static void cs35l41_hda_pause_done(struct device *dev) + cs35l41->playback_started = false; + } + ++static void cs35l41_hda_pre_playback_hook(struct device *dev, int action) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ ++ switch (action) { ++ case HDA_GEN_PCM_ACT_CLEANUP: ++ mutex_lock(&cs35l41->fw_mutex); ++ cs35l41_hda_pause_start(dev); ++ mutex_unlock(&cs35l41->fw_mutex); ++ break; ++ default: ++ break; ++ } ++} + static void cs35l41_hda_playback_hook(struct device *dev, int action) + { + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: ++ /* ++ * All amps must be resumed before we can start playing back. ++ * This ensures, for external boost, that all amps are in AMP_SAFE mode. ++ * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the ++ * other actions. ++ */ + pm_runtime_get_sync(dev); +- mutex_lock(&cs35l41->fw_mutex); +- cs35l41_hda_play_start(dev); +- mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_PREPARE: + mutex_lock(&cs35l41->fw_mutex); +- cs35l41_hda_play_done(dev); ++ cs35l41_hda_play_start(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + mutex_lock(&cs35l41->fw_mutex); +- cs35l41_hda_pause_start(dev); ++ cs35l41_hda_pause_done(dev); + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLOSE: +- mutex_lock(&cs35l41->fw_mutex); +- cs35l41_hda_pause_done(dev); +- mutex_unlock(&cs35l41->fw_mutex); +- ++ /* ++ * Playback must be finished for all amps before we start runtime suspend. ++ * This ensures no amps are playing back when we start putting them to sleep. ++ */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + break; + default: +- dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action); ++ break; ++ } ++} ++ ++static void cs35l41_hda_post_playback_hook(struct device *dev, int action) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ ++ switch (action) { ++ case HDA_GEN_PCM_ACT_PREPARE: ++ mutex_lock(&cs35l41->fw_mutex); ++ cs35l41_hda_play_done(dev); ++ mutex_unlock(&cs35l41->fw_mutex); ++ break; ++ default: + break; + } + } +@@ -1037,6 +1068,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas + ret = cs35l41_create_controls(cs35l41); + + comps->playback_hook = cs35l41_hda_playback_hook; ++ comps->pre_playback_hook = cs35l41_hda_pre_playback_hook; ++ comps->post_playback_hook = cs35l41_hda_post_playback_hook; + + mutex_unlock(&cs35l41->fw_mutex); + +-- +2.41.0 + diff --git a/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch b/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch new file mode 100644 index 000000000000..02d98e408b9f --- /dev/null +++ b/0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch @@ -0,0 +1,114 @@ +From 5091ba7ad9ea6a88db464b84b4993cc9e5033a84 Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:14 +0100 +Subject: [PATCH 09/11] ALSA: hda: cs35l41: Rework System Suspend to ensure + correct call separation + +In order to correctly pause audio on suspend, amps using external boost +require parts of the pause sequence to be called for all amps before moving +on to the next steps. +For example, as part of pausing the audio, the VSPK GPIO must be disabled, +but since this GPIO is controlled by one amp, but controls the boost for +all amps, it is required to separate the calls. +During playback this is achieved by using the pre and post playback hooks, +however during system suspend, this is not possible, so to separate the +calls, we use both the .prepare and .suspend calls to pause the audio. + +Currently, for this reason, we do not restart audio on system resume. +However, we can support this by relying on the playback hook to resume +playback after system suspend. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 40 ++++++++++++++++++++++++++++++++----- + 1 file changed, 35 insertions(+), 5 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index a482d4752b3f..70aa819cfbd6 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -595,6 +595,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action) + mutex_unlock(&cs35l41->fw_mutex); + break; + case HDA_GEN_PCM_ACT_CLOSE: ++ mutex_lock(&cs35l41->fw_mutex); ++ if (!cs35l41->firmware_running && cs35l41->request_fw_load && ++ !cs35l41->fw_request_ongoing) { ++ dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n"); ++ cs35l41->fw_request_ongoing = true; ++ schedule_work(&cs35l41->fw_load_work); ++ } ++ mutex_unlock(&cs35l41->fw_mutex); ++ + /* + * Playback must be finished for all amps before we start runtime suspend. + * This ensures no amps are playing back when we start putting them to sleep. +@@ -681,6 +690,25 @@ static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41) + return ret; + } + ++static int cs35l41_system_suspend_prep(struct device *dev) ++{ ++ struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); ++ ++ dev_dbg(cs35l41->dev, "System Suspend Prepare\n"); ++ ++ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) { ++ dev_err_once(cs35l41->dev, "System Suspend not supported\n"); ++ return 0; /* don't block the whole system suspend */ ++ } ++ ++ mutex_lock(&cs35l41->fw_mutex); ++ if (cs35l41->playback_started) ++ cs35l41_hda_pause_start(dev); ++ mutex_unlock(&cs35l41->fw_mutex); ++ ++ return 0; ++} ++ + static int cs35l41_system_suspend(struct device *dev) + { + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); +@@ -693,6 +721,11 @@ static int cs35l41_system_suspend(struct device *dev) + return 0; /* don't block the whole system suspend */ + } + ++ mutex_lock(&cs35l41->fw_mutex); ++ if (cs35l41->playback_started) ++ cs35l41_hda_pause_done(dev); ++ mutex_unlock(&cs35l41->fw_mutex); ++ + ret = pm_runtime_force_suspend(dev); + if (ret) { + dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret); +@@ -738,6 +771,7 @@ static int cs35l41_system_resume(struct device *dev) + } + + mutex_lock(&cs35l41->fw_mutex); ++ + if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) { + cs35l41->fw_request_ongoing = true; + schedule_work(&cs35l41->fw_load_work); +@@ -770,11 +804,6 @@ static int cs35l41_runtime_suspend(struct device *dev) + + mutex_lock(&cs35l41->fw_mutex); + +- if (cs35l41->playback_started) { +- cs35l41_hda_pause_start(dev); +- cs35l41_hda_pause_done(dev); +- } +- + if (cs35l41->firmware_running) { + ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, + cs35l41->hw_cfg.bst_type); +@@ -1641,6 +1670,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); + const struct dev_pm_ops cs35l41_hda_pm_ops = { + RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, + cs35l41_runtime_idle) ++ .prepare = cs35l41_system_suspend_prep, + SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume) + }; + EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); +-- +2.41.0 + diff --git a/0010-ALSA-hda-cs35l41-Add-device_link-between-HDA-and-cs3.patch b/0010-ALSA-hda-cs35l41-Add-device_link-between-HDA-and-cs3.patch new file mode 100644 index 000000000000..ca5244fdbe4c --- /dev/null +++ b/0010-ALSA-hda-cs35l41-Add-device_link-between-HDA-and-cs3.patch @@ -0,0 +1,60 @@ +From 74c165859e33b62888b93891d82680350b9a615f Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:15 +0100 +Subject: [PATCH 10/11] ALSA: hda: cs35l41: Add device_link between HDA and + cs35l41_hda + +To ensure consistency between the HDA core and the CS35L41 HDA +driver, add a device_link between them. This ensures that the +HDA core will suspend first, and resume second, meaning the +amp driver will not miss any events from the playback hook from +the HDA core during system suspend and resume. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index 70aa819cfbd6..175378cdf9df 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -1063,6 +1063,7 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas + { + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; ++ unsigned int sleep_flags; + int ret = 0; + + if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS) +@@ -1102,6 +1103,11 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas + + mutex_unlock(&cs35l41->fw_mutex); + ++ sleep_flags = lock_system_sleep(); ++ if (!device_link_add(&comps->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS)) ++ dev_warn(dev, "Unable to create device link\n"); ++ unlock_system_sleep(sleep_flags); ++ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +@@ -1112,9 +1118,14 @@ static void cs35l41_hda_unbind(struct device *dev, struct device *master, void * + { + struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev); + struct hda_component *comps = master_data; ++ unsigned int sleep_flags; + +- if (comps[cs35l41->index].dev == dev) ++ if (comps[cs35l41->index].dev == dev) { + memset(&comps[cs35l41->index], 0, sizeof(*comps)); ++ sleep_flags = lock_system_sleep(); ++ device_link_remove(&comps->codec->core.dev, cs35l41->dev); ++ unlock_system_sleep(sleep_flags); ++ } + } + + static const struct component_ops cs35l41_hda_comp_ops = { +-- +2.41.0 + diff --git a/0011-ALSA-hda-cs35l41-Ensure-amp-is-only-unmuted-during-p.patch b/0011-ALSA-hda-cs35l41-Ensure-amp-is-only-unmuted-during-p.patch new file mode 100644 index 000000000000..5049e3963a51 --- /dev/null +++ b/0011-ALSA-hda-cs35l41-Ensure-amp-is-only-unmuted-during-p.patch @@ -0,0 +1,73 @@ +From 6f1a7b41a626a567fcfe915e9dbe3aea34b6c3ec Mon Sep 17 00:00:00 2001 +From: Stefan Binding <sbinding@opensource.cirrus.com> +Date: Fri, 21 Jul 2023 16:18:16 +0100 +Subject: [PATCH 11/11] ALSA: hda: cs35l41: Ensure amp is only unmuted during + playback + +Currently we only mute after playback has finished, and unmute +prior to setting global enable. To prevent any possible pops +and clicks, mute at probe, and then only unmute after global +enable is set. + +Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com> +--- + sound/pci/hda/cs35l41_hda.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c +index 175378cdf9df..98feb5ccd586 100644 +--- a/sound/pci/hda/cs35l41_hda.c ++++ b/sound/pci/hda/cs35l41_hda.c +@@ -58,8 +58,6 @@ static const struct reg_sequence cs35l41_hda_config[] = { + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON + { CS35L41_DSP1_RX5_SRC, 0x00000020 }, // DSP1RX5 SRC = ERRVOL +- { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB +- { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB + }; + + static const struct reg_sequence cs35l41_hda_config_dsp[] = { +@@ -82,6 +80,14 @@ static const struct reg_sequence cs35l41_hda_config_dsp[] = { + { CS35L41_DSP1_RX3_SRC, 0x00000018 }, // DSP1RX3 SRC = VMON + { CS35L41_DSP1_RX4_SRC, 0x00000019 }, // DSP1RX4 SRC = IMON + { CS35L41_DSP1_RX5_SRC, 0x00000029 }, // DSP1RX5 SRC = VBSTMON ++}; ++ ++static const struct reg_sequence cs35l41_hda_unmute[] = { ++ { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB ++ { CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB ++}; ++ ++static const struct reg_sequence cs35l41_hda_unmute_dsp[] = { + { CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM 0.0 dB + { CS35L41_AMP_GAIN_CTRL, 0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB + }; +@@ -522,6 +528,13 @@ static void cs35l41_hda_play_done(struct device *dev) + + cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL, + cs35l41->firmware_running); ++ if (cs35l41->firmware_running) { ++ regmap_multi_reg_write(reg, cs35l41_hda_unmute_dsp, ++ ARRAY_SIZE(cs35l41_hda_unmute_dsp)); ++ } else { ++ regmap_multi_reg_write(reg, cs35l41_hda_unmute, ++ ARRAY_SIZE(cs35l41_hda_unmute)); ++ } + } + + static void cs35l41_hda_pause_start(struct device *dev) +@@ -1616,6 +1629,11 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i + if (ret) + goto err; + ++ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute, ++ ARRAY_SIZE(cs35l41_hda_mute)); ++ if (ret) ++ goto err; ++ + INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work); + mutex_init(&cs35l41->fw_mutex); + +-- +2.41.0 + diff --git a/0102-netfilter-nf_tables-unbind_non-anonymous.patch b/0102-netfilter-nf_tables-unbind_non-anonymous.patch new file mode 100644 index 000000000000..77b52a94aba9 --- /dev/null +++ b/0102-netfilter-nf_tables-unbind_non-anonymous.patch @@ -0,0 +1,30 @@ +From 50c597f3cc8dc4de0f0b6153a0ff1bd0b2dc6f56 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso <pablo@netfilter.org> +Date: Mon, 26 Jun 2023 00:42:18 +0200 +Subject: [PATCH] netfilter: nf_tables: unbind non-anonymous set if rule + construction fails + +Otherwise a dangling reference to a rule object that is gone remains +in the set binding list. + +Fixes: 26b5a5712eb8 ("netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain") +Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> +(cherry picked from commit 3e70489721b6c870252c9082c496703677240f53) +For: https://bugs.archlinux.org/task/78908 +--- + net/netfilter/nf_tables_api.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 4c7937fd803f9f..1d64c163076a12 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5343,6 +5343,8 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set, + nft_set_trans_unbind(ctx, set); + if (nft_set_is_anonymous(set)) + nft_deactivate_next(ctx->net, set); ++ else ++ list_del_rcu(&binding->list); + + set->use--; + break; diff --git a/0201-ACPI-resource-Remove-Zen-specific-match-and-quirks.patch b/0201-ACPI-resource-Remove-Zen-specific-match-and-quirks.patch new file mode 100644 index 000000000000..3d7e40c8b28f --- /dev/null +++ b/0201-ACPI-resource-Remove-Zen-specific-match-and-quirks.patch @@ -0,0 +1,127 @@ +From a9c4a912b7dc7ff922d4b9261160c001558f9755 Mon Sep 17 00:00:00 2001 +From: Mario Limonciello <mario.limonciello@amd.com> +Date: Thu, 1 Jun 2023 17:11:51 -0500 +Subject: ACPI: resource: Remove "Zen" specific match and quirks + +commit 9946e39fe8d0 ("ACPI: resource: skip IRQ override on +AMD Zen platforms") attempted to overhaul the override logic so it +didn't apply on X86 AMD Zen systems. This was intentional so that +systems would prefer DSDT values instead of default MADT value for +IRQ 1 on Ryzen 6000 systems which typically uses ActiveLow for IRQ1. + +This turned out to be a bad assumption because several vendors +add Interrupt Source Override but don't fix the DSDT. A pile of +quirks was collecting that proved this wasn't sustaintable. + +Furthermore some vendors have used ActiveHigh for IRQ1. +To solve this problem revert the following commits: +* commit 17bb7046e7ce ("ACPI: resource: Do IRQ override on all TongFang +GMxRGxx") +* commit f3cb9b740869 ("ACPI: resource: do IRQ override on Lenovo 14ALC7") +* commit bfcdf58380b1 ("ACPI: resource: do IRQ override on LENOVO IdeaPad") +* commit 7592b79ba4a9 ("ACPI: resource: do IRQ override on XMG Core 15") +* commit 9946e39fe8d0 ("ACPI: resource: skip IRQ override on AMD Zen +platforms") + +Reported-by: evilsnoo@proton.me +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217394 +Reported-by: ruinairas1992@gmail.com +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217406 +Reported-by: nmschulte@gmail.com +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217336 +Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> +Tested-by: Werner Sembach <wse@tuxedocomputers.com> +Tested-by: Chuanhong Guo <gch981213@gmail.com> +Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> +--- + drivers/acpi/resource.c | 60 ------------------------------------------------- + 1 file changed, 60 deletions(-) + +diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c +index 0800a9d775580..1dd8d5aebf678 100644 +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -470,52 +470,6 @@ static const struct dmi_system_id asus_laptop[] = { + { } + }; + +-static const struct dmi_system_id lenovo_laptop[] = { +- { +- .ident = "LENOVO IdeaPad Flex 5 14ALC7", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "82R9"), +- }, +- }, +- { +- .ident = "LENOVO IdeaPad Flex 5 16ALC7", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), +- DMI_MATCH(DMI_PRODUCT_NAME, "82RA"), +- }, +- }, +- { } +-}; +- +-static const struct dmi_system_id tongfang_gm_rg[] = { +- { +- .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD", +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"), +- }, +- }, +- { } +-}; +- +-static const struct dmi_system_id maingear_laptop[] = { +- { +- .ident = "MAINGEAR Vector Pro 2 15", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), +- DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"), +- } +- }, +- { +- .ident = "MAINGEAR Vector Pro 2 17", +- .matches = { +- DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"), +- DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"), +- }, +- }, +- { } +-}; +- + static const struct dmi_system_id lg_laptop[] = { + { + .ident = "LG Electronics 17U70P", +@@ -539,10 +493,6 @@ struct irq_override_cmp { + static const struct irq_override_cmp override_table[] = { + { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, + { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, +- { lenovo_laptop, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, +- { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true }, +- { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, +- { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true }, + { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false }, + }; + +@@ -562,16 +512,6 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity, + return entry->override; + } + +-#ifdef CONFIG_X86 +- /* +- * IRQ override isn't needed on modern AMD Zen systems and +- * this override breaks active low IRQs on AMD Ryzen 6000 and +- * newer systems. Skip it. +- */ +- if (boot_cpu_has(X86_FEATURE_ZEN)) +- return false; +-#endif +- + return true; + } + +-- +cgit + diff --git a/0202-amd-drm-fixes-6.4-2023-06-23.patch b/0202-amd-drm-fixes-6.4-2023-06-23.patch new file mode 100644 index 000000000000..63f36917cedf --- /dev/null +++ b/0202-amd-drm-fixes-6.4-2023-06-23.patch @@ -0,0 +1,412 @@ +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c 2023-06-23 22:44:45.000000000 +0200 +@@ -133,9 +133,6 @@ static int amdgpu_cs_p1_user_fence(struc + bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj)); + p->uf_entry.priority = 0; + p->uf_entry.tv.bo = &bo->tbo; +- /* One for TTM and two for the CS job */ +- p->uf_entry.tv.num_shared = 3; +- + drm_gem_object_put(gobj); + + size = amdgpu_bo_size(bo); +@@ -882,15 +879,19 @@ static int amdgpu_cs_parser_bos(struct a + + mutex_lock(&p->bo_list->bo_list_mutex); + +- /* One for TTM and one for the CS job */ ++ /* One for TTM and one for each CS job */ + amdgpu_bo_list_for_each_entry(e, p->bo_list) +- e->tv.num_shared = 2; ++ e->tv.num_shared = 1 + p->gang_size; ++ p->uf_entry.tv.num_shared = 1 + p->gang_size; + + amdgpu_bo_list_get_list(p->bo_list, &p->validated); + + INIT_LIST_HEAD(&duplicates); + amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd); + ++ /* Two for VM updates, one for TTM and one for each CS job */ ++ p->vm_pd.tv.num_shared = 3 + p->gang_size; ++ + if (p->uf_entry.tv.bo && !ttm_to_amdgpu_bo(p->uf_entry.tv.bo)->parent) + list_add(&p->uf_entry.tv.head, &p->validated); + +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c 2023-06-23 22:44:45.000000000 +0200 +@@ -251,7 +251,8 @@ int amdgpu_jpeg_ras_late_init(struct amd + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { +- if (adev->jpeg.harvest_config & (1 << i)) ++ if (adev->jpeg.harvest_config & (1 << i) || ++ !adev->jpeg.inst[i].ras_poison_irq.funcs) + continue; + + r = amdgpu_irq_get(adev, &adev->jpeg.inst[i].ras_poison_irq, 0); +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1266,8 +1266,12 @@ void amdgpu_bo_move_notify(struct ttm_bu + void amdgpu_bo_get_memory(struct amdgpu_bo *bo, + struct amdgpu_mem_stats *stats) + { +- unsigned int domain; + uint64_t size = amdgpu_bo_size(bo); ++ unsigned int domain; ++ ++ /* Abort if the BO doesn't currently have a backing store */ ++ if (!bo->tbo.resource) ++ return; + + domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); + switch (domain) { +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1947,6 +1947,8 @@ static int psp_securedisplay_initialize( + psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); + dev_err(psp->adev->dev, "SECUREDISPLAY: query securedisplay TA failed. ret 0x%x\n", + securedisplay_cmd->securedisplay_out_message.query_ta.query_cmd_ret); ++ /* don't try again */ ++ psp->securedisplay_context.context.bin_desc.size_bytes = 0; + } + + return 0; +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c 2023-06-23 22:44:45.000000000 +0200 +@@ -423,6 +423,9 @@ void amdgpu_sw_ring_ib_mark_offset(struc + struct amdgpu_ring_mux *mux = &adev->gfx.muxer; + unsigned offset; + ++ if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) ++ return; ++ + offset = ring->wptr & ring->buf_mask; + + amdgpu_ring_mux_ib_mark_offset(mux, ring, offset, type); +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1191,7 +1191,8 @@ int amdgpu_vcn_ras_late_init(struct amdg + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { + for (i = 0; i < adev->vcn.num_vcn_inst; i++) { +- if (adev->vcn.harvest_config & (1 << i)) ++ if (adev->vcn.harvest_config & (1 << i) || ++ !adev->vcn.inst[i].ras_poison_irq.funcs) + continue; + + r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0); +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c 2023-06-23 22:44:45.000000000 +0200 +@@ -920,42 +920,51 @@ error_unlock: + return r; + } + ++static void amdgpu_vm_bo_get_memory(struct amdgpu_bo_va *bo_va, ++ struct amdgpu_mem_stats *stats) ++{ ++ struct amdgpu_vm *vm = bo_va->base.vm; ++ struct amdgpu_bo *bo = bo_va->base.bo; ++ ++ if (!bo) ++ return; ++ ++ /* ++ * For now ignore BOs which are currently locked and potentially ++ * changing their location. ++ */ ++ if (bo->tbo.base.resv != vm->root.bo->tbo.base.resv && ++ !dma_resv_trylock(bo->tbo.base.resv)) ++ return; ++ ++ amdgpu_bo_get_memory(bo, stats); ++ if (bo->tbo.base.resv != vm->root.bo->tbo.base.resv) ++ dma_resv_unlock(bo->tbo.base.resv); ++} ++ + void amdgpu_vm_get_memory(struct amdgpu_vm *vm, + struct amdgpu_mem_stats *stats) + { + struct amdgpu_bo_va *bo_va, *tmp; + + spin_lock(&vm->status_lock); +- list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } +- list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } +- list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } +- list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } +- list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } +- list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) { +- if (!bo_va->base.bo) +- continue; +- amdgpu_bo_get_memory(bo_va->base.bo, stats); +- } ++ list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); ++ ++ list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); ++ ++ list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); ++ ++ list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); ++ ++ list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); ++ ++ list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) ++ amdgpu_vm_bo_get_memory(bo_va, stats); + spin_unlock(&vm->status_lock); + } + +@@ -1674,18 +1683,30 @@ int amdgpu_vm_bo_clear_mappings(struct a + + /* Insert partial mapping before the range */ + if (!list_empty(&before->list)) { ++ struct amdgpu_bo *bo = before->bo_va->base.bo; ++ + amdgpu_vm_it_insert(before, &vm->va); + if (before->flags & AMDGPU_PTE_PRT) + amdgpu_vm_prt_get(adev); ++ ++ if (bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv && ++ !before->bo_va->base.moved) ++ amdgpu_vm_bo_moved(&before->bo_va->base); + } else { + kfree(before); + } + + /* Insert partial mapping after the range */ + if (!list_empty(&after->list)) { ++ struct amdgpu_bo *bo = after->bo_va->base.bo; ++ + amdgpu_vm_it_insert(after, &vm->va); + if (after->flags & AMDGPU_PTE_PRT) + amdgpu_vm_prt_get(adev); ++ ++ if (bo && bo->tbo.base.resv == vm->root.bo->tbo.base.resv && ++ !after->bo_va->base.moved) ++ amdgpu_vm_bo_moved(&after->bo_va->base); + } else { + kfree(after); + } +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/nbio_v2_3.c 2023-06-23 22:44:45.000000000 +0200 +@@ -345,8 +345,8 @@ static void nbio_v2_3_init_registers(str + } + + #define NAVI10_PCIE__LC_L0S_INACTIVITY_DEFAULT 0x00000000 // off by default, no gains over L1 +-#define NAVI10_PCIE__LC_L1_INACTIVITY_DEFAULT 0x00000009 // 1=1us, 9=1ms +-#define NAVI10_PCIE__LC_L1_INACTIVITY_TBT_DEFAULT 0x0000000E // 4ms ++#define NAVI10_PCIE__LC_L1_INACTIVITY_DEFAULT 0x0000000A // 1=1us, 9=1ms, 10=4ms ++#define NAVI10_PCIE__LC_L1_INACTIVITY_TBT_DEFAULT 0x0000000E // 400ms + + static void nbio_v2_3_enable_aspm(struct amdgpu_device *adev, + bool enable) +@@ -479,9 +479,12 @@ static void nbio_v2_3_program_aspm(struc + WREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP5, data); + + def = data = RREG32_PCIE(smnPCIE_LC_CNTL); +- data &= ~PCIE_LC_CNTL__LC_L0S_INACTIVITY_MASK; +- data |= 0x9 << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; +- data |= 0x1 << PCIE_LC_CNTL__LC_PMI_TO_L1_DIS__SHIFT; ++ data |= NAVI10_PCIE__LC_L0S_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L0S_INACTIVITY__SHIFT; ++ if (pci_is_thunderbolt_attached(adev->pdev)) ++ data |= NAVI10_PCIE__LC_L1_INACTIVITY_TBT_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; ++ else ++ data |= NAVI10_PCIE__LC_L1_INACTIVITY_DEFAULT << PCIE_LC_CNTL__LC_L1_INACTIVITY__SHIFT; ++ data &= ~PCIE_LC_CNTL__LC_PMI_TO_L1_DIS_MASK; + if (def != data) + WREG32_PCIE(smnPCIE_LC_CNTL, data); + +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c 2023-06-23 22:44:45.000000000 +0200 +@@ -2306,7 +2306,7 @@ const struct amd_ip_funcs sdma_v4_0_ip_f + + static const struct amdgpu_ring_funcs sdma_v4_0_ring_funcs = { + .type = AMDGPU_RING_TYPE_SDMA, +- .align_mask = 0xf, ++ .align_mask = 0xff, + .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), + .support_64bit_ptrs = true, + .secure_submission_supported = true, +@@ -2338,7 +2338,7 @@ static const struct amdgpu_ring_funcs sd + + static const struct amdgpu_ring_funcs sdma_v4_0_page_ring_funcs = { + .type = AMDGPU_RING_TYPE_SDMA, +- .align_mask = 0xf, ++ .align_mask = 0xff, + .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), + .support_64bit_ptrs = true, + .secure_submission_supported = true, +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1740,7 +1740,7 @@ const struct amd_ip_funcs sdma_v4_4_2_ip + + static const struct amdgpu_ring_funcs sdma_v4_4_2_ring_funcs = { + .type = AMDGPU_RING_TYPE_SDMA, +- .align_mask = 0xf, ++ .align_mask = 0xff, + .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), + .support_64bit_ptrs = true, + .get_rptr = sdma_v4_4_2_ring_get_rptr, +@@ -1771,7 +1771,7 @@ static const struct amdgpu_ring_funcs sd + + static const struct amdgpu_ring_funcs sdma_v4_4_2_page_ring_funcs = { + .type = AMDGPU_RING_TYPE_SDMA, +- .align_mask = 0xf, ++ .align_mask = 0xff, + .nop = SDMA_PKT_NOP_HEADER_OP(SDMA_OP_NOP), + .support_64bit_ptrs = true, + .get_rptr = sdma_v4_4_2_ring_get_rptr, +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 2023-06-23 22:44:45.000000000 +0200 +@@ -5057,11 +5057,7 @@ static inline void fill_dc_dirty_rect(st + s32 y, s32 width, s32 height, + int *i, bool ffu) + { +- if (*i > DC_MAX_DIRTY_RECTS) +- return; +- +- if (*i == DC_MAX_DIRTY_RECTS) +- goto out; ++ WARN_ON(*i >= DC_MAX_DIRTY_RECTS); + + dirty_rect->x = x; + dirty_rect->y = y; +@@ -5077,7 +5073,6 @@ static inline void fill_dc_dirty_rect(st + "[PLANE:%d] PSR SU dirty rect at (%d, %d) size (%d, %d)", + plane->base.id, x, y, width, height); + +-out: + (*i)++; + } + +@@ -5164,6 +5159,9 @@ static void fill_dc_dirty_rects(struct d + + *dirty_regions_changed = bb_changed; + ++ if ((num_clips + (bb_changed ? 2 : 0)) > DC_MAX_DIRTY_RECTS) ++ goto ffu; ++ + if (bb_changed) { + fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i], + new_plane_state->crtc_x, +@@ -5193,9 +5191,6 @@ static void fill_dc_dirty_rects(struct d + new_plane_state->crtc_h, &i, false); + } + +- if (i > DC_MAX_DIRTY_RECTS) +- goto ffu; +- + flip_addrs->dirty_rect_count = i; + return; + +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/core/dc.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/core/dc.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/core/dc.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/core/dc.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1602,6 +1602,9 @@ bool dc_validate_boot_timing(const struc + return false; + } + ++ if (dc->debug.force_odm_combine) ++ return false; ++ + /* Check for enabled DIG to identify enabled display */ + if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) + return false; +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c 2023-06-23 22:44:45.000000000 +0200 +@@ -970,10 +970,12 @@ enum dc_status resource_map_phy_clock_re + || dc_is_virtual_signal(pipe_ctx->stream->signal)) + pipe_ctx->clock_source = + dc->res_pool->dp_clock_source; +- else +- pipe_ctx->clock_source = find_matching_pll( +- &context->res_ctx, dc->res_pool, +- stream); ++ else { ++ if (stream && stream->link && stream->link->link_enc) ++ pipe_ctx->clock_source = find_matching_pll( ++ &context->res_ctx, dc->res_pool, ++ stream); ++ } + + if (pipe_ctx->clock_source == NULL) + return DC_NO_CLOCK_SOURCE_RESOURCE; +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c 2023-06-23 22:44:45.000000000 +0200 +@@ -82,8 +82,15 @@ bool dp_parse_link_loss_status( + } + + /* Check interlane align.*/ +- if (sink_status_changed || +- !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { ++ if (link_dp_get_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING && ++ (!hpd_irq_dpcd_data->bytes.lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b || ++ !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b)) { ++ sink_status_changed = true; ++ } else if (!hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { ++ sink_status_changed = true; ++ } ++ ++ if (sink_status_changed) { + + DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__); + +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/modules/power/power_helpers.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/display/modules/power/power_helpers.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/display/modules/power/power_helpers.c 2023-06-23 22:44:45.000000000 +0200 +@@ -818,6 +818,8 @@ bool is_psr_su_specific_panel(struct dc_ + ((dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x08) || + (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x07))) + isPSRSUSupported = false; ++ else if (dpcd_caps->sink_dev_id_str[1] == 0x08 && dpcd_caps->sink_dev_id_str[0] == 0x03) ++ isPSRSUSupported = false; + else if (dpcd_caps->psr_info.force_psrsu_cap == 0x1) + isPSRSUSupported = true; + } +diff -Npur linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +--- linux-9bd9be5cbaf8a8faa175ef4fba04a5623281debe/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c 2023-06-23 04:16:48.000000000 +0200 ++++ linux-134ea95255cf359a2e6d70308c15243c3fdf8eaf/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c 2023-06-23 22:44:45.000000000 +0200 +@@ -1300,6 +1300,7 @@ static int smu_v13_0_0_get_thermal_tempe + range->mem_emergency_max = (pptable->SkuTable.TemperatureLimit[TEMP_MEM] + CTF_OFFSET_MEM)* + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->software_shutdown_temp = powerplay_table->software_shutdown_temp; ++ range->software_shutdown_temp_offset = pptable->SkuTable.FanAbnormalTempLimitOffset; + + return 0; + } diff --git a/0203-Revert-drm-amd-display-edp-do-not-add-non-edid-timings.patch b/0203-Revert-drm-amd-display-edp-do-not-add-non-edid-timings.patch new file mode 100644 index 000000000000..5d67d2d5827f --- /dev/null +++ b/0203-Revert-drm-amd-display-edp-do-not-add-non-edid-timings.patch @@ -0,0 +1,19 @@ +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 a46b8b47b756..073bf00c6fdc 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -7258,13 +7258,7 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) + drm_add_modes_noedid(connector, 1920, 1080); + } else { + amdgpu_dm_connector_ddc_get_modes(connector, edid); +- /* most eDP supports only timings from its edid, +- * usually only detailed timings are available +- * from eDP edid. timings which are not from edid +- * may damage eDP +- */ +- if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) +- amdgpu_dm_connector_add_common_modes(encoder, connector); ++ amdgpu_dm_connector_add_common_modes(encoder, connector); + amdgpu_dm_connector_add_freesync_modes(connector, edid); + } + amdgpu_dm_fbc_init(connector); diff --git a/0205-ALSA-hda-realtek-add-quirks-asus-ally-cs35l41.patch b/0205-ALSA-hda-realtek-add-quirks-asus-ally-cs35l41.patch new file mode 100644 index 000000000000..4cfc250a369c --- /dev/null +++ b/0205-ALSA-hda-realtek-add-quirks-asus-ally-cs35l41.patch @@ -0,0 +1,91 @@ +From 724418b84e6248cd27599607b7e5fac365b8e3f5 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson <ruinairas1992@gmail.com> +Date: Wed, 21 Jun 2023 11:17:14 -0500 +Subject: ALSA: hda/realtek: Add quirks for ROG ALLY CS35l41 audio + +This requires a patched ACPI table or a firmware from ASUS to work because +the system does not come with the _DSD field for the CSC3551. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217550 +Signed-off-by: Matthew Anderson <ruinairas1992@gmail.com> +Tested-by: Philip Mueller <philm@manjaro.org> +Link: https://lore.kernel.org/r/20230621161714.9442-1-ruinairas1992@gmail.com +Signed-off-by: Takashi Iwai <tiwai@suse.de> +--- + sound/pci/hda/patch_realtek.c | 46 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index ce9a9cb41e4b2..2ab1065d5a1ca 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7121,6 +7121,10 @@ enum { + ALC294_FIXUP_ASUS_DUAL_SPK, + ALC285_FIXUP_THINKPAD_X1_GEN7, + ALC285_FIXUP_THINKPAD_HEADSET_JACK, ++ ALC294_FIXUP_ASUS_ALLY, ++ ALC294_FIXUP_ASUS_ALLY_PINS, ++ ALC294_FIXUP_ASUS_ALLY_VERBS, ++ ALC294_FIXUP_ASUS_ALLY_SPEAKER, + ALC294_FIXUP_ASUS_HPE, + ALC294_FIXUP_ASUS_COEF_1B, + ALC294_FIXUP_ASUS_GX502_HP, +@@ -8417,6 +8421,47 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC294_FIXUP_SPK2_TO_DAC1 + }, ++ [ALC294_FIXUP_ASUS_ALLY] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = cs35l41_fixup_i2c_two, ++ .chained = true, ++ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS ++ }, ++ [ALC294_FIXUP_ASUS_ALLY_PINS] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x19, 0x03a11050 }, ++ { 0x1a, 0x03a11c30 }, ++ { 0x21, 0x03211420 }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC294_FIXUP_ASUS_ALLY_VERBS ++ }, ++ [ALC294_FIXUP_ASUS_ALLY_VERBS] = { ++ .type = HDA_FIXUP_VERBS, ++ .v.verbs = (const struct hda_verb[]) { ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 }, ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x46 }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0x0004 }, ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x47 }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0xa47a }, ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0x0049}, ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0x201b }, ++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b }, ++ { 0x20, AC_VERB_SET_PROC_COEF, 0x4278}, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER ++ }, ++ [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_speaker2_to_dac1, ++ }, + [ALC285_FIXUP_THINKPAD_X1_GEN7] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_thinkpad_x1_gen7, +@@ -9510,6 +9555,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS), + SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), ++ SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally RC71L_RC71L", ALC294_FIXUP_ASUS_ALLY), + SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), + SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC), +-- +cgit + diff --git a/0207-AMD-HDR.patch b/0207-AMD-HDR.patch new file mode 100644 index 000000000000..4635f307058a --- /dev/null +++ b/0207-AMD-HDR.patch @@ -0,0 +1,6109 @@ +From e320343eab938d6a6d4c0e4da03c810516bf3bef Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 30 Nov 2022 14:02:15 -0500 +Subject: [PATCH 01/59] drm/connector: Drop COLORIMETRY_NO_DATA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The value is the same as DEFAULT. The HDMI_COLORIMETRY_NO_DATA +makes sense for the infopacket but it's meaningless for the +connector colorspace. or, in otherwise, just means to go with +driver default. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 619d080523ac5582bb57eecb1d6a3bdd7f614885) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/display/drm_hdmi_helper.c | 2 +- + include/drm/drm_connector.h | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c +index faf5e9efa7d33..c1e6851b26066 100644 +--- a/drivers/gpu/drm/display/drm_hdmi_helper.c ++++ b/drivers/gpu/drm/display/drm_hdmi_helper.c +@@ -103,7 +103,7 @@ EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); + #define HDMI_COLORIMETRY_DCI_P3_RGB_THEATER (C(3) | EC(7) | ACE(1)) + + static const u32 hdmi_colorimetry_val[] = { +- [DRM_MODE_COLORIMETRY_NO_DATA] = HDMI_COLORIMETRY_NO_DATA, ++ [DRM_MODE_COLORIMETRY_DEFAULT] = HDMI_COLORIMETRY_NO_DATA, + [DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = HDMI_COLORIMETRY_SMPTE_170M_YCC, + [DRM_MODE_COLORIMETRY_BT709_YCC] = HDMI_COLORIMETRY_BT709_YCC, + [DRM_MODE_COLORIMETRY_XVYCC_601] = HDMI_COLORIMETRY_XVYCC_601, +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 7b5048516185c..cfcd88c73a8d6 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -431,7 +431,6 @@ enum drm_privacy_screen_status { + /* For Default case, driver will set the colorspace */ + #define DRM_MODE_COLORIMETRY_DEFAULT 0 + /* CEA 861 Normal Colorimetry options */ +-#define DRM_MODE_COLORIMETRY_NO_DATA 0 + #define DRM_MODE_COLORIMETRY_SMPTE_170M_YCC 1 + #define DRM_MODE_COLORIMETRY_BT709_YCC 2 + /* CEA 861 Extended Colorimetry Options */ +-- +2.40.1 + + +From d98dfe4f63acfa66a646326b7b424274ae40afdc Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 30 Nov 2022 14:18:22 -0500 +Subject: [PATCH 02/59] drm/connector: Convert DRM_MODE_COLORIMETRY to enum +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows us to use strongly typed arguments. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit be90be3eee59546d092e338929d8272d4864398a) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + include/drm/display/drm_dp.h | 2 +- + include/drm/drm_connector.h | 47 ++++++++++++++++++------------------ + 2 files changed, 25 insertions(+), 24 deletions(-) + +diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h +index f8813c1e059be..2ef9a8b2c354e 100644 +--- a/include/drm/display/drm_dp.h ++++ b/include/drm/display/drm_dp.h +@@ -1632,7 +1632,7 @@ enum dp_pixelformat { + * + * This enum is used to indicate DP VSC SDP Colorimetry formats. + * It is based on DP 1.4 spec [Table 2-117: VSC SDP Payload for DB16 through +- * DB18] and a name of enum member follows DRM_MODE_COLORIMETRY definition. ++ * DB18] and a name of enum member follows &enum drm_colorimetry definition. + * + * @DP_COLORIMETRY_DEFAULT: sRGB (IEC 61966-2-1) or + * ITU-R BT.601 colorimetry format +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index cfcd88c73a8d6..657c51043a7f9 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -427,28 +427,29 @@ enum drm_privacy_screen_status { + * a colorspace property which will be created and exposed to + * userspace. + */ +- +-/* For Default case, driver will set the colorspace */ +-#define DRM_MODE_COLORIMETRY_DEFAULT 0 +-/* CEA 861 Normal Colorimetry options */ +-#define DRM_MODE_COLORIMETRY_SMPTE_170M_YCC 1 +-#define DRM_MODE_COLORIMETRY_BT709_YCC 2 +-/* CEA 861 Extended Colorimetry Options */ +-#define DRM_MODE_COLORIMETRY_XVYCC_601 3 +-#define DRM_MODE_COLORIMETRY_XVYCC_709 4 +-#define DRM_MODE_COLORIMETRY_SYCC_601 5 +-#define DRM_MODE_COLORIMETRY_OPYCC_601 6 +-#define DRM_MODE_COLORIMETRY_OPRGB 7 +-#define DRM_MODE_COLORIMETRY_BT2020_CYCC 8 +-#define DRM_MODE_COLORIMETRY_BT2020_RGB 9 +-#define DRM_MODE_COLORIMETRY_BT2020_YCC 10 +-/* Additional Colorimetry extension added as part of CTA 861.G */ +-#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 11 +-#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER 12 +-/* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ +-#define DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED 13 +-#define DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT 14 +-#define DRM_MODE_COLORIMETRY_BT601_YCC 15 ++enum drm_colorspace { ++ /* For Default case, driver will set the colorspace */ ++ DRM_MODE_COLORIMETRY_DEFAULT, ++ /* CEA 861 Normal Colorimetry options */ ++ DRM_MODE_COLORIMETRY_SMPTE_170M_YCC, ++ DRM_MODE_COLORIMETRY_BT709_YCC, ++ /* CEA 861 Extended Colorimetry Options */ ++ DRM_MODE_COLORIMETRY_XVYCC_601, ++ DRM_MODE_COLORIMETRY_XVYCC_709, ++ DRM_MODE_COLORIMETRY_SYCC_601, ++ DRM_MODE_COLORIMETRY_OPYCC_601, ++ DRM_MODE_COLORIMETRY_OPRGB, ++ DRM_MODE_COLORIMETRY_BT2020_CYCC, ++ DRM_MODE_COLORIMETRY_BT2020_RGB, ++ DRM_MODE_COLORIMETRY_BT2020_YCC, ++ /* Additional Colorimetry extension added as part of CTA 861.G */ ++ DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, ++ DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, ++ /* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ ++ DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, ++ DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, ++ DRM_MODE_COLORIMETRY_BT601_YCC, ++}; + + /** + * enum drm_bus_flags - bus_flags info for &drm_display_info +@@ -900,7 +901,7 @@ struct drm_connector_state { + * colorspace change on Sink. This is most commonly used to switch + * to wider color gamuts like BT2020. + */ +- u32 colorspace; ++ enum drm_colorspace colorspace; + + /** + * @writeback_job: Writeback job for writeback connectors +-- +2.40.1 + + +From 59312e117c9b897060184001f7736d5cb7eb15dd Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 30 Nov 2022 14:42:03 -0500 +Subject: [PATCH 03/59] drm/connector: Pull out common + create_colorspace_property code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 23badc4de4b1fa3a84689ffc09a9cf30dc927777) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/drm_connector.c | 54 ++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 48df7a5ea503f..614dd9fd4d3f7 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -2135,33 +2135,44 @@ EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); + * drm_mode_create_dp_colorspace_property() is used for DP connector. + */ + +-/** +- * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property +- * @connector: connector to create the Colorspace property on. +- * +- * Called by a driver the first time it's needed, must be attached to desired +- * HDMI connectors. +- * +- * Returns: +- * Zero on success, negative errno on failure. +- */ +-int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) ++static int drm_mode_create_colorspace_property(struct drm_connector *connector, ++ const struct drm_prop_enum_list *colorspaces, ++ int size) + { + struct drm_device *dev = connector->dev; + + if (connector->colorspace_property) + return 0; + ++ if (!colorspaces) ++ return 0; ++ + connector->colorspace_property = + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", +- hdmi_colorspaces, +- ARRAY_SIZE(hdmi_colorspaces)); ++ colorspaces, ++ size); + + if (!connector->colorspace_property) + return -ENOMEM; + + return 0; + } ++/** ++ * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property ++ * @connector: connector to create the Colorspace property on. ++ * ++ * Called by a driver the first time it's needed, must be attached to desired ++ * HDMI connectors. ++ * ++ * Returns: ++ * Zero on success, negative errno on failure. ++ */ ++int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) ++{ ++ return drm_mode_create_colorspace_property(connector, ++ hdmi_colorspaces, ++ ARRAY_SIZE(hdmi_colorspaces)); ++} + EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); + + /** +@@ -2176,20 +2187,9 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); + */ + int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) + { +- struct drm_device *dev = connector->dev; +- +- if (connector->colorspace_property) +- return 0; +- +- connector->colorspace_property = +- drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", +- dp_colorspaces, +- ARRAY_SIZE(dp_colorspaces)); +- +- if (!connector->colorspace_property) +- return -ENOMEM; +- +- return 0; ++ return drm_mode_create_colorspace_property(connector, ++ dp_colorspaces, ++ ARRAY_SIZE(dp_colorspaces)); + } + EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); + +-- +2.40.1 + + +From 769d91623bc199b054698e711ab7f31198770147 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Tue, 29 Nov 2022 15:16:31 -0500 +Subject: [PATCH 04/59] drm/connector: Allow drivers to pass list of supported + colorspaces +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Drivers might not support all colorspaces defined in +dp_colorspaces and hdmi_colorspaces. This results in +undefined behavior when userspace is setting an +unsupported colorspace. + +Allow drivers to pass the list of supported colorspaces +when creating the colorspace property. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 671b98e563d65707fb6fcf8e8d1aa04faf0565b8) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/drm_connector.c | 140 +++++++++--------- + .../gpu/drm/i915/display/intel_connector.c | 4 +- + drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- + include/drm/drm_connector.h | 8 +- + 4 files changed, 83 insertions(+), 71 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 614dd9fd4d3f7..5f272599f487f 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -1055,64 +1055,57 @@ static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { + DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, + drm_dp_subconnector_enum_list) + +-static const struct drm_prop_enum_list hdmi_colorspaces[] = { +- /* For Default case, driver will set the colorspace */ +- { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, +- /* Standard Definition Colorimetry based on CEA 861 */ +- { DRM_MODE_COLORIMETRY_SMPTE_170M_YCC, "SMPTE_170M_YCC" }, +- { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, +- /* Standard Definition Colorimetry based on IEC 61966-2-4 */ +- { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, +- /* High Definition Colorimetry based on IEC 61966-2-4 */ +- { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, +- /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ +- { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, +- /* Colorimetry based on IEC 61966-2-5 [33] */ +- { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, +- /* Colorimetry based on IEC 61966-2-5 */ +- { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, +- /* Added as part of Additional Colorimetry Extension in 861.G */ +- { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, +- { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" }, ++static const char * const colorspace_names[] = { ++ [DRM_MODE_COLORIMETRY_DEFAULT] = "Default", ++ [DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = "SMPTE_170M_YCC", ++ [DRM_MODE_COLORIMETRY_BT709_YCC] = "BT709_YCC", ++ [DRM_MODE_COLORIMETRY_XVYCC_601] = "XVYCC_601", ++ [DRM_MODE_COLORIMETRY_XVYCC_709] = "XVYCC_709", ++ [DRM_MODE_COLORIMETRY_SYCC_601] = "SYCC_601", ++ [DRM_MODE_COLORIMETRY_OPYCC_601] = "opYCC_601", ++ [DRM_MODE_COLORIMETRY_OPRGB] = "opRGB", ++ [DRM_MODE_COLORIMETRY_BT2020_CYCC] = "BT2020_CYCC", ++ [DRM_MODE_COLORIMETRY_BT2020_RGB] = "BT2020_RGB", ++ [DRM_MODE_COLORIMETRY_BT2020_YCC] = "BT2020_YCC", ++ [DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65] = "P3_RGB_D65", ++ [DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER] = "P3_RGB_Theater", ++ [DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED] = "RGB_WIDE_FIXED", ++ [DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT] = "RGB_WIDE_FLOAT", ++ [DRM_MODE_COLORIMETRY_BT601_YCC] = "BT601_YCC", + }; + ++static const u32 hdmi_colorspaces = ++ BIT(DRM_MODE_COLORIMETRY_SMPTE_170M_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_XVYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_XVYCC_709) | ++ BIT(DRM_MODE_COLORIMETRY_SYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_OPYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_OPRGB) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_CYCC) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) | ++ BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER); ++ + /* + * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry + * Format Table 2-120 + */ +-static const struct drm_prop_enum_list dp_colorspaces[] = { +- /* For Default case, driver will set the colorspace */ +- { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, +- { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" }, +- /* Colorimetry based on scRGB (IEC 61966-2-2) */ +- { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" }, +- /* Colorimetry based on IEC 61966-2-5 */ +- { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, +- /* Colorimetry based on SMPTE RP 431-2 */ +- { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, +- { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" }, +- { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, +- /* Standard Definition Colorimetry based on IEC 61966-2-4 */ +- { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, +- /* High Definition Colorimetry based on IEC 61966-2-4 */ +- { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, +- /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ +- { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, +- /* Colorimetry based on IEC 61966-2-5 [33] */ +- { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, +- /* Colorimetry based on ITU-R BT.2020 */ +- { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, +-}; ++static const u32 dp_colorspaces = ++ BIT(DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED) | ++ BIT(DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT) | ++ BIT(DRM_MODE_COLORIMETRY_OPRGB) | ++ BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) | ++ BIT(DRM_MODE_COLORIMETRY_BT601_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_XVYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_XVYCC_709) | ++ BIT(DRM_MODE_COLORIMETRY_SYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_OPYCC_601) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_CYCC) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_YCC); + + /** + * DOC: standard connector properties +@@ -2136,21 +2129,34 @@ EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); + */ + + static int drm_mode_create_colorspace_property(struct drm_connector *connector, +- const struct drm_prop_enum_list *colorspaces, +- int size) ++ u32 supported_colorspaces) + { + struct drm_device *dev = connector->dev; ++ u32 colorspaces = supported_colorspaces | BIT(DRM_MODE_COLORIMETRY_DEFAULT); ++ struct drm_prop_enum_list enum_list[DRM_MODE_COLORIMETRY_MAX]; ++ int i, len; + + if (connector->colorspace_property) + return 0; + +- if (!colorspaces) +- return 0; ++ if (WARN_ON(supported_colorspaces == 0 || ++ (supported_colorspaces & -BIT(DRM_MODE_COLORIMETRY_MAX)) != 0)) ++ return -EINVAL; ++ ++ len = 0; ++ for (i = 0; i < DRM_MODE_COLORIMETRY_MAX; i++) { ++ if ((colorspaces & BIT(i)) == 0) ++ continue; ++ ++ enum_list[len].type = i; ++ enum_list[len].name = colorspace_names[i]; ++ len++; ++ } + + connector->colorspace_property = + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", +- colorspaces, +- size); ++ enum_list, ++ len); + + if (!connector->colorspace_property) + return -ENOMEM; +@@ -2167,11 +2173,12 @@ static int drm_mode_create_colorspace_property(struct drm_connector *connector, + * Returns: + * Zero on success, negative errno on failure. + */ +-int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) ++int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector, ++ u32 supported_colorspaces) + { +- return drm_mode_create_colorspace_property(connector, +- hdmi_colorspaces, +- ARRAY_SIZE(hdmi_colorspaces)); ++ u32 colorspaces = supported_colorspaces & hdmi_colorspaces; ++ ++ return drm_mode_create_colorspace_property(connector, colorspaces); + } + EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); + +@@ -2185,11 +2192,12 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); + * Returns: + * Zero on success, negative errno on failure. + */ +-int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) ++int drm_mode_create_dp_colorspace_property(struct drm_connector *connector, ++ u32 supported_colorspaces) + { +- return drm_mode_create_colorspace_property(connector, +- dp_colorspaces, +- ARRAY_SIZE(dp_colorspaces)); ++ u32 colorspaces = supported_colorspaces & dp_colorspaces; ++ ++ return drm_mode_create_colorspace_property(connector, colorspaces); + } + EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); + +diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c +index 257afac348397..cefc7ca5bf7bc 100644 +--- a/drivers/gpu/drm/i915/display/intel_connector.c ++++ b/drivers/gpu/drm/i915/display/intel_connector.c +@@ -280,14 +280,14 @@ intel_attach_aspect_ratio_property(struct drm_connector *connector) + void + intel_attach_hdmi_colorspace_property(struct drm_connector *connector) + { +- if (!drm_mode_create_hdmi_colorspace_property(connector)) ++ if (!drm_mode_create_hdmi_colorspace_property(connector, 0xffffffff)) + drm_connector_attach_colorspace_property(connector); + } + + void + intel_attach_dp_colorspace_property(struct drm_connector *connector) + { +- if (!drm_mode_create_dp_colorspace_property(connector)) ++ if (!drm_mode_create_dp_colorspace_property(connector, 0xffffffff)) + drm_connector_attach_colorspace_property(connector); + } + +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +index 06713d8b82b5d..e9abdbb8b3c72 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -631,7 +631,7 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, + if (ret) + return ret; + +- ret = drm_mode_create_hdmi_colorspace_property(connector); ++ ret = drm_mode_create_hdmi_colorspace_property(connector, 0xffffffff); + if (ret) + return ret; + +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 657c51043a7f9..2d10ea06a7584 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -30,6 +30,7 @@ + #include <linux/notifier.h> + #include <drm/drm_mode_object.h> + #include <drm/drm_util.h> ++#include <drm/drm_property.h> + + #include <uapi/drm/drm_mode.h> + +@@ -449,6 +450,7 @@ enum drm_colorspace { + DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, + DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, + DRM_MODE_COLORIMETRY_BT601_YCC, ++ DRM_MODE_COLORIMETRY_MAX + }; + + /** +@@ -1925,8 +1927,10 @@ int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *conn + bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, + struct drm_connector_state *new_state); + int drm_mode_create_aspect_ratio_property(struct drm_device *dev); +-int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector); +-int drm_mode_create_dp_colorspace_property(struct drm_connector *connector); ++int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector, ++ u32 supported_colorspaces); ++int drm_mode_create_dp_colorspace_property(struct drm_connector *connector, ++ u32 supported_colorspaces); + int drm_mode_create_content_type_property(struct drm_device *dev); + int drm_mode_create_suggested_offset_properties(struct drm_device *dev); + +-- +2.40.1 + + +From 0109bbccb4c0e3fcb6d555b31a49ac6186f28abc Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 30 Nov 2022 16:11:30 -0500 +Subject: [PATCH 05/59] drm/connector: Print connector colorspace in state + debugfs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 7e2a454f00f1e200fa8fd89aad628d160c1eba93) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/drm_atomic.c | 1 + + drivers/gpu/drm/drm_connector.c | 15 +++++++++++++++ + include/drm/drm_connector.h | 1 + + 3 files changed, 17 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c +index b4c6ffc438da2..2c454568a607c 100644 +--- a/drivers/gpu/drm/drm_atomic.c ++++ b/drivers/gpu/drm/drm_atomic.c +@@ -1131,6 +1131,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, + drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware); + drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc); ++ drm_printf(p, "\tcolorspace=%s\n", drm_get_colorspace_name(state->colorspace)); + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + if (state->writeback_job && state->writeback_job->fb) +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 5f272599f487f..f8bf090c98144 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -1074,6 +1074,21 @@ static const char * const colorspace_names[] = { + [DRM_MODE_COLORIMETRY_BT601_YCC] = "BT601_YCC", + }; + ++/** ++ * drm_get_color_encoding_name - return a string for color encoding ++ * @encoding: color encoding to compute name of ++ * ++ * In contrast to the other drm_get_*_name functions this one here returns a ++ * const pointer and hence is threadsafe. ++ */ ++const char *drm_get_colorspace_name(enum drm_colorspace colorspace) ++{ ++ if (WARN_ON(colorspace >= ARRAY_SIZE(colorspace_names))) ++ return "unknown"; ++ ++ return colorspace_names[colorspace]; ++} ++ + static const u32 hdmi_colorspaces = + BIT(DRM_MODE_COLORIMETRY_SMPTE_170M_YCC) | + BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 2d10ea06a7584..919047091c101 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -2013,6 +2013,7 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter); + + bool drm_connector_has_possible_encoder(struct drm_connector *connector, + struct drm_encoder *encoder); ++const char *drm_get_colorspace_name(enum drm_colorspace colorspace); + + /** + * drm_for_each_connector_iter - connector_list iterator macro +-- +2.40.1 + + +From b840e36bde5711e21191fb9855e7e7ec2cab6d48 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Fri, 1 Apr 2022 13:45:29 -0400 +Subject: [PATCH 06/59] drm/amd/display: Always pass connector_state to stream + validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We need the connector_state for colorspace and scaling information +and can get it from connector->state. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit f6ab07b44373c865e286bb5e8b8e52d7d350ec66) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 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 7acd73e5004fb..5f545ef690f39 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5947,15 +5947,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + { + struct drm_display_mode *preferred_mode = NULL; + struct drm_connector *drm_connector; +- const struct drm_connector_state *con_state = +- dm_state ? &dm_state->base : NULL; ++ const struct drm_connector_state *con_state = &dm_state->base; + struct dc_stream_state *stream = NULL; + struct drm_display_mode mode; + struct drm_display_mode saved_mode; + struct drm_display_mode *freesync_mode = NULL; + bool native_mode_found = false; + bool recalculate_timing = false; +- bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; ++ bool scale = dm_state->scaling != RMX_OFF; + int mode_refresh; + int preferred_refresh = 0; + enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; +@@ -6563,7 +6562,9 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec + goto fail; + } + +- stream = create_validate_stream_for_sink(aconnector, mode, NULL, NULL); ++ stream = create_validate_stream_for_sink(aconnector, mode, ++ to_dm_connector_state(connector->state), ++ NULL); + if (stream) { + dc_stream_release(stream); + result = MODE_OK; +-- +2.40.1 + + +From 224746fb1cd4c0a5e3db947a593c510e30dd7b4c Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Fri, 25 Mar 2022 15:30:28 -0400 +Subject: [PATCH 07/59] drm/amd/display: Register Colorspace property for DP + and HDMI +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We want compositors to be able to set the output +colorspace on DP and HDMI outputs, based on the +caps reported from the receiver via EDID. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 9246196a65f4b1a06245ad0f7c0a194ab9df6dd4) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +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 5f545ef690f39..8d188145ab344 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -7211,6 +7211,12 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) + return amdgpu_dm_connector->num_modes; + } + ++static const u32 supported_colorspaces = ++ BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | ++ BIT(DRM_MODE_COLORIMETRY_OPRGB) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) | ++ BIT(DRM_MODE_COLORIMETRY_BT2020_YCC); ++ + void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector, + int connector_type, +@@ -7291,6 +7297,15 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, + adev->mode_info.abm_level_property, 0); + } + ++ if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { ++ if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces)) ++ drm_connector_attach_colorspace_property(&aconnector->base); ++ } else if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || ++ connector_type == DRM_MODE_CONNECTOR_eDP) { ++ if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces)) ++ drm_connector_attach_colorspace_property(&aconnector->base); ++ } ++ + if (connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_eDP) { +-- +2.40.1 + + +From eff7f31566489b7cf9b546844970ff58ad2ca2df Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Tue, 29 Mar 2022 11:26:23 -0400 +Subject: [PATCH 08/59] drm/amd/display: Set colorspace for HDMI infoframe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that we have the HDMI colorimetry fill the corresponding +AVI infoframe info. Also signal "mode_changed" if colorimetry +changed. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 556619b9a15bb3dec6c92528501be5b51583465e) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +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 8d188145ab344..6f7d9e0a84115 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5466,6 +5466,7 @@ static void fill_stream_properties_from_drm_display_mode( + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) { + drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, (struct drm_connector *)connector, mode_in); + timing_out->vic = avi_frame.video_code; ++ drm_hdmi_avi_infoframe_colorimetry(&avi_frame, connector_state); + drm_hdmi_vendor_infoframe_from_display_mode(&hv_frame, (struct drm_connector *)connector, mode_in); + timing_out->hdmi_vic = hv_frame.vic; + } +@@ -6658,6 +6659,14 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, + if (!crtc) + return 0; + ++ if (new_con_state->colorspace != old_con_state->colorspace) { ++ new_crtc_state = drm_atomic_get_crtc_state(state, crtc); ++ if (IS_ERR(new_crtc_state)) ++ return PTR_ERR(new_crtc_state); ++ ++ new_crtc_state->mode_changed = true; ++ } ++ + if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) { + struct dc_info_packet hdr_infopacket; + +@@ -6680,7 +6689,7 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn, + * set is permissible, however. So only force a + * modeset if we're entering or exiting HDR. + */ +- new_crtc_state->mode_changed = ++ new_crtc_state->mode_changed = new_crtc_state->mode_changed || + !old_con_state->hdr_output_metadata || + !new_con_state->hdr_output_metadata; + } +-- +2.40.1 + + +From f350177dba28757eddbe9687d06b9b90cdf85104 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Tue, 29 Mar 2022 15:30:05 -0400 +Subject: [PATCH 09/59] drm/amd/display: Send correct DP colorspace infopacket +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Look at connector->colorimetry to determine output colorspace. + +We don't want to impact current SDR behavior, so +DRM_MODE_COLORIMETRY_DEFAULT preserves current behavior. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 9c9a9db82e4f43f971fdc06ec8825bcb1a4ad391) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 38 +++++++++++-------- + 1 file changed, 22 insertions(+), 16 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 6f7d9e0a84115..a486474e63cb2 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5331,21 +5331,21 @@ get_aspect_ratio(const struct drm_display_mode *mode_in) + } + + static enum dc_color_space +-get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) ++get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, ++ const struct drm_connector_state *connector_state) + { + enum dc_color_space color_space = COLOR_SPACE_SRGB; + +- switch (dc_crtc_timing->pixel_encoding) { +- case PIXEL_ENCODING_YCBCR422: +- case PIXEL_ENCODING_YCBCR444: +- case PIXEL_ENCODING_YCBCR420: +- { ++ switch (connector_state->colorspace) { ++ case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601 ++ if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) { ++ color_space = COLOR_SPACE_SRGB; + /* + * 27030khz is the separation point between HDTV and SDTV + * according to HDMI spec, we use YCbCr709 and YCbCr601 + * respectively + */ +- if (dc_crtc_timing->pix_clk_100hz > 270300) { ++ } else if (dc_crtc_timing->pix_clk_100hz > 270300) { + if (dc_crtc_timing->flags.Y_ONLY) + color_space = + COLOR_SPACE_YCBCR709_LIMITED; +@@ -5358,15 +5358,21 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) + else + color_space = COLOR_SPACE_YCBCR601; + } +- +- } +- break; +- case PIXEL_ENCODING_RGB: +- color_space = COLOR_SPACE_SRGB; + break; +- +- default: +- WARN_ON(1); ++ case DRM_MODE_COLORIMETRY_BT709_YCC: ++ if (dc_crtc_timing->flags.Y_ONLY) ++ color_space = COLOR_SPACE_YCBCR709_LIMITED; ++ else ++ color_space = COLOR_SPACE_YCBCR709; ++ break; ++ case DRM_MODE_COLORIMETRY_OPRGB: ++ color_space = COLOR_SPACE_ADOBERGB; ++ break; ++ case DRM_MODE_COLORIMETRY_BT2020_RGB: ++ color_space = COLOR_SPACE_2020_RGB_FULLRANGE; ++ break; ++ case DRM_MODE_COLORIMETRY_BT2020_YCC: ++ color_space = COLOR_SPACE_2020_YCBCR; + break; + } + +@@ -5506,7 +5512,7 @@ static void fill_stream_properties_from_drm_display_mode( + } + } + +- stream->output_color_space = get_output_color_space(timing_out); ++ stream->output_color_space = get_output_color_space(timing_out, connector_state); + } + + static void fill_audio_info(struct audio_info *audio_info, +-- +2.40.1 + + +From a22bdccba1e118d82ce39a8085345d3d060aa350 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Mon, 14 Nov 2022 19:52:30 +0000 +Subject: [PATCH 10/59] drm/amd/display: Always set crtcinfo from + create_stream_for_sink +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Given that we always pass dm_state into here now, this won't ever +trigger anymore. + +This is needed for we will always fail mode validation with invalid +clocks or link bandwidth errors. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 069221689191b3001a171aa086ba01bb675d54c4) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 a486474e63cb2..6e7ef3bdb5c3a 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -6040,7 +6040,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, + + if (recalculate_timing) + drm_mode_set_crtcinfo(&saved_mode, 0); +- else if (!dm_state) ++ else + drm_mode_set_crtcinfo(&mode, 0); + + /* +-- +2.40.1 + + +From 7cce4d19d1b20da69331b50de1d908f5a2dc4be5 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Tue, 29 Nov 2022 14:58:10 -0500 +Subject: [PATCH 11/59] drm/amd/display: Add support for explicit BT601_YCC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We use this by default but if userspace passes this explicitly +we should respect it. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 468f3103082ec31b5923da84db1733a836f7fec9) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +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 6e7ef3bdb5c3a..4c63ed14ed610 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5359,6 +5359,12 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + color_space = COLOR_SPACE_YCBCR601; + } + break; ++ case DRM_MODE_COLORIMETRY_BT601_YCC: ++ if (dc_crtc_timing->flags.Y_ONLY) ++ color_space = COLOR_SPACE_YCBCR601_LIMITED; ++ else ++ color_space = COLOR_SPACE_YCBCR601; ++ break; + case DRM_MODE_COLORIMETRY_BT709_YCC: + if (dc_crtc_timing->flags.Y_ONLY) + color_space = COLOR_SPACE_YCBCR709_LIMITED; +-- +2.40.1 + + +From b12036a28c6d5b4f6d0798962d7a76e1c02e9d9d Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Tue, 29 Nov 2022 17:24:52 -0500 +Subject: [PATCH 12/59] drm/amd/display: Add debugfs for testing output + colorspace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to IGT test colorspace we'll want to print +the currently enabled colorspace on a stream. We add +a new debugfs to do so, using the same scheme as +current bpc reporting. + +This might also come in handy when debugging display +issues. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 4783cc7b534ebd8cd64d6d7b1c26d102f93b0576) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 57 +++++++++++++++++++ + 1 file changed, 57 insertions(+) + +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 827fcb4fb3b3b..b865570756933 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 +@@ -906,6 +906,61 @@ static int amdgpu_current_bpc_show(struct seq_file *m, void *data) + } + DEFINE_SHOW_ATTRIBUTE(amdgpu_current_bpc); + ++/* ++ * Returns the current bpc for the crtc. ++ * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/amdgpu_current_colorspace ++ */ ++static int amdgpu_current_colorspace_show(struct seq_file *m, void *data) ++{ ++ struct drm_crtc *crtc = m->private; ++ struct drm_device *dev = crtc->dev; ++ struct dm_crtc_state *dm_crtc_state = NULL; ++ int res = -ENODEV; ++ ++ mutex_lock(&dev->mode_config.mutex); ++ drm_modeset_lock(&crtc->mutex, NULL); ++ if (crtc->state == NULL) ++ goto unlock; ++ ++ dm_crtc_state = to_dm_crtc_state(crtc->state); ++ if (dm_crtc_state->stream == NULL) ++ goto unlock; ++ ++ switch (dm_crtc_state->stream->output_color_space) { ++ case COLOR_SPACE_SRGB: ++ seq_printf(m, "RGB"); ++ break; ++ case COLOR_SPACE_YCBCR601: ++ case COLOR_SPACE_YCBCR601_LIMITED: ++ seq_printf(m, "BT601_YCC"); ++ break; ++ case COLOR_SPACE_YCBCR709: ++ case COLOR_SPACE_YCBCR709_LIMITED: ++ seq_printf(m, "BT709_YCC"); ++ break; ++ case COLOR_SPACE_ADOBERGB: ++ seq_printf(m, "opRGB"); ++ break; ++ case COLOR_SPACE_2020_RGB_FULLRANGE: ++ seq_printf(m, "BT2020_RGB"); ++ break; ++ case COLOR_SPACE_2020_YCBCR: ++ seq_printf(m, "BT2020_YCC"); ++ break; ++ default: ++ goto unlock; ++ } ++ res = 0; ++ ++unlock: ++ drm_modeset_unlock(&crtc->mutex); ++ mutex_unlock(&dev->mode_config.mutex); ++ ++ return res; ++} ++DEFINE_SHOW_ATTRIBUTE(amdgpu_current_colorspace); ++ ++ + /* + * Example usage: + * Disable dsc passthrough, i.e.,: have dsc decoding at converver, not external RX +@@ -3246,6 +3301,8 @@ void crtc_debugfs_init(struct drm_crtc *crtc) + #endif + debugfs_create_file("amdgpu_current_bpc", 0644, crtc->debugfs_entry, + crtc, &amdgpu_current_bpc_fops); ++ debugfs_create_file("amdgpu_current_colorspace", 0644, crtc->debugfs_entry, ++ crtc, &amdgpu_current_colorspace_fops); + } + + /* +-- +2.40.1 + + +From ffb5d236189cfdf92f7bdd47c70140791c332860 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 30 Nov 2022 14:17:14 -0500 +Subject: [PATCH 13/59] drm/amd/display: Add default case for + output_color_space switch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Cc: Pekka Paalanen <ppaalanen@gmail.com> +Cc: Sebastian Wick <sebastian.wick@redhat.com> +Cc: Vitaly.Prosyak@amd.com +Cc: Uma Shankar <uma.shankar@intel.com> +Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> +Cc: Joshua Ashton <joshua@froggi.es> +Cc: dri-devel@lists.freedesktop.org +Cc: amd-gfx@lists.freedesktop.org +(cherry picked from commit 1c98f57342c976b12775155746d56801b1231463) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 43 ++++++++++--------- + 1 file changed, 22 insertions(+), 21 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 4c63ed14ed610..353bc03f30cb7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5337,7 +5337,29 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + enum dc_color_space color_space = COLOR_SPACE_SRGB; + + switch (connector_state->colorspace) { ++ case DRM_MODE_COLORIMETRY_BT601_YCC: ++ if (dc_crtc_timing->flags.Y_ONLY) ++ color_space = COLOR_SPACE_YCBCR601_LIMITED; ++ else ++ color_space = COLOR_SPACE_YCBCR601; ++ break; ++ case DRM_MODE_COLORIMETRY_BT709_YCC: ++ if (dc_crtc_timing->flags.Y_ONLY) ++ color_space = COLOR_SPACE_YCBCR709_LIMITED; ++ else ++ color_space = COLOR_SPACE_YCBCR709; ++ break; ++ case DRM_MODE_COLORIMETRY_OPRGB: ++ color_space = COLOR_SPACE_ADOBERGB; ++ break; ++ case DRM_MODE_COLORIMETRY_BT2020_RGB: ++ color_space = COLOR_SPACE_2020_RGB_FULLRANGE; ++ break; ++ case DRM_MODE_COLORIMETRY_BT2020_YCC: ++ color_space = COLOR_SPACE_2020_YCBCR; ++ break; + case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601 ++ default: + if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) { + color_space = COLOR_SPACE_SRGB; + /* +@@ -5359,27 +5381,6 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + color_space = COLOR_SPACE_YCBCR601; + } + break; +- case DRM_MODE_COLORIMETRY_BT601_YCC: +- if (dc_crtc_timing->flags.Y_ONLY) +- color_space = COLOR_SPACE_YCBCR601_LIMITED; +- else +- color_space = COLOR_SPACE_YCBCR601; +- break; +- case DRM_MODE_COLORIMETRY_BT709_YCC: +- if (dc_crtc_timing->flags.Y_ONLY) +- color_space = COLOR_SPACE_YCBCR709_LIMITED; +- else +- color_space = COLOR_SPACE_YCBCR709; +- break; +- case DRM_MODE_COLORIMETRY_OPRGB: +- color_space = COLOR_SPACE_ADOBERGB; +- break; +- case DRM_MODE_COLORIMETRY_BT2020_RGB: +- color_space = COLOR_SPACE_2020_RGB_FULLRANGE; +- break; +- case DRM_MODE_COLORIMETRY_BT2020_YCC: +- color_space = COLOR_SPACE_2020_YCBCR; +- break; + } + + return color_space; +-- +2.40.1 + + +From 0e442c9a946e78ca5078c00a5ce5b5686622b5dd Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 10 Jan 2023 19:17:08 +0000 +Subject: [PATCH 14/59] drm/amd/display: Fallback to 2020_YCBCR if the pixel + encoding is not RGB + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +(cherry picked from commit 4d5fe77e2cd4444756790466c573b54b108445fe) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +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 353bc03f30cb7..9b9b0b7706522 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5353,7 +5353,10 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + color_space = COLOR_SPACE_ADOBERGB; + break; + case DRM_MODE_COLORIMETRY_BT2020_RGB: +- color_space = COLOR_SPACE_2020_RGB_FULLRANGE; ++ if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) ++ color_space = COLOR_SPACE_2020_RGB_FULLRANGE; ++ else ++ color_space = COLOR_SPACE_2020_YCBCR; + break; + case DRM_MODE_COLORIMETRY_BT2020_YCC: + color_space = COLOR_SPACE_2020_YCBCR; +-- +2.40.1 + + +From 2bd640d40bcc2b2445d6e4d5791199d26bf0b909 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 10 Jan 2023 19:14:06 +0000 +Subject: [PATCH 15/59] drm/amd/display: Refactor avi_info_frame colorimetry + determination + +Replace the messy two if-else chains here that were on the same value with a switch on the enum. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +(cherry picked from commit 88558ba9c35a3e2d0e2df7b90692ffbcea1fc9dd) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + .../gpu/drm/amd/display/dc/core/dc_resource.c | 28 +++++++++++-------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index fe1551393b264..4b80091b6021a 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -3034,23 +3034,29 @@ static void set_avi_info_frame( + hdmi_info.bits.S0_S1 = scan_type; + + /* C0, C1 : Colorimetry */ +- if (color_space == COLOR_SPACE_YCBCR709 || +- color_space == COLOR_SPACE_YCBCR709_LIMITED) ++ switch (color_space) { ++ case COLOR_SPACE_YCBCR709: ++ case COLOR_SPACE_YCBCR709_LIMITED: + hdmi_info.bits.C0_C1 = COLORIMETRY_ITU709; +- else if (color_space == COLOR_SPACE_YCBCR601 || +- color_space == COLOR_SPACE_YCBCR601_LIMITED) ++ break; ++ case COLOR_SPACE_YCBCR601: ++ case COLOR_SPACE_YCBCR601_LIMITED: + hdmi_info.bits.C0_C1 = COLORIMETRY_ITU601; +- else { +- hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; +- } +- if (color_space == COLOR_SPACE_2020_RGB_FULLRANGE || +- color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE || +- color_space == COLOR_SPACE_2020_YCBCR) { ++ break; ++ case COLOR_SPACE_2020_RGB_FULLRANGE: ++ case COLOR_SPACE_2020_RGB_LIMITEDRANGE: ++ case COLOR_SPACE_2020_YCBCR: + hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; + hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; +- } else if (color_space == COLOR_SPACE_ADOBERGB) { ++ break; ++ case COLOR_SPACE_ADOBERGB: + hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; + hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; ++ break; ++ case COLOR_SPACE_SRGB: ++ default: ++ hdmi_info.bits.C0_C1 = COLORIMETRY_NO_DATA; ++ break; + } + + if (pixel_encoding && color_space == COLOR_SPACE_2020_YCBCR && +-- +2.40.1 + + +From abd25d352b9c9f9b8f1ed7e6824f3369bef10e8d Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 10 Jan 2023 19:26:07 +0000 +Subject: [PATCH 16/59] drm/amd/display: Use COLORIMETRYEX_BT2020YCC for + COLOR_SPACE_2020_YCBCR for avi info frame + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +(cherry picked from commit 622ce9770fdf2ffbff6110b6e61f01a08cd8c35c) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 4b80091b6021a..de8bc5c0d28ca 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -3045,10 +3045,13 @@ static void set_avi_info_frame( + break; + case COLOR_SPACE_2020_RGB_FULLRANGE: + case COLOR_SPACE_2020_RGB_LIMITEDRANGE: +- case COLOR_SPACE_2020_YCBCR: + hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020RGBYCBCR; + hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; + break; ++ case COLOR_SPACE_2020_YCBCR: ++ hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_BT2020YCC; ++ hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; ++ break; + case COLOR_SPACE_ADOBERGB: + hdmi_info.bits.EC0_EC2 = COLORIMETRYEX_ADOBERGB; + hdmi_info.bits.C0_C1 = COLORIMETRY_EXTENDED; +-- +2.40.1 + + +From 45fffdcdc68a22e073966d7c864842c292a13f20 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Mon, 16 Jan 2023 04:20:17 +0000 +Subject: [PATCH 17/59] drm/amd/display: Hook up content_type property + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +(cherry picked from commit dc91bc9addbe058894a78ae72a13b20d76636b0c) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 21 ++++++ + .../gpu/drm/amd/display/dc/core/dc_resource.c | 69 ++++++------------- + drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 + + 3 files changed, 43 insertions(+), 48 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 9b9b0b7706522..6deec192ae04e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5389,6 +5389,24 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + return color_space; + } + ++static enum display_content_type ++get_output_content_type(const struct drm_connector_state *connector_state) ++{ ++ switch (connector_state->content_type) { ++ default: ++ case DRM_MODE_CONTENT_TYPE_NO_DATA: ++ return DISPLAY_CONTENT_TYPE_NO_DATA; ++ case DRM_MODE_CONTENT_TYPE_GRAPHICS: ++ return DISPLAY_CONTENT_TYPE_GRAPHICS; ++ case DRM_MODE_CONTENT_TYPE_PHOTO: ++ return DISPLAY_CONTENT_TYPE_PHOTO; ++ case DRM_MODE_CONTENT_TYPE_CINEMA: ++ return DISPLAY_CONTENT_TYPE_CINEMA; ++ case DRM_MODE_CONTENT_TYPE_GAME: ++ return DISPLAY_CONTENT_TYPE_GAME; ++ } ++} ++ + static bool adjust_colour_depth_from_display_info( + struct dc_crtc_timing *timing_out, + const struct drm_display_info *info) +@@ -5523,6 +5541,7 @@ static void fill_stream_properties_from_drm_display_mode( + } + + stream->output_color_space = get_output_color_space(timing_out, connector_state); ++ stream->content_type = get_output_content_type(connector_state); + } + + static void fill_audio_info(struct audio_info *audio_info, +@@ -7322,6 +7341,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, + adev->mode_info.abm_level_property, 0); + } + ++ drm_connector_attach_content_type_property(&aconnector->base); ++ + if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { + if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces)) + drm_connector_attach_colorspace_property(&aconnector->base); +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index de8bc5c0d28ca..29757f39707cc 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -2967,14 +2967,9 @@ static void set_avi_info_frame( + uint32_t pixel_encoding = 0; + enum scanning_type scan_type = SCANNING_TYPE_NODATA; + enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA; +- bool itc = false; +- uint8_t itc_value = 0; +- uint8_t cn0_cn1 = 0; +- unsigned int cn0_cn1_value = 0; + uint8_t *check_sum = NULL; + uint8_t byte_index = 0; + union hdmi_info_packet hdmi_info; +- union display_content_support support = {0}; + unsigned int vic = pipe_ctx->stream->timing.vic; + unsigned int rid = pipe_ctx->stream->timing.rid; + unsigned int fr_ind = pipe_ctx->stream->timing.fr_index; +@@ -3087,49 +3082,27 @@ static void set_avi_info_frame( + /* Active Format Aspect ratio - same as Picture Aspect Ratio. */ + hdmi_info.bits.R0_R3 = ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE; + +- /* TODO: un-hardcode cn0_cn1 and itc */ +- +- cn0_cn1 = 0; +- cn0_cn1_value = 0; +- +- itc = true; +- itc_value = 1; +- +- support = stream->content_support; +- +- if (itc) { +- if (!support.bits.valid_content_type) { +- cn0_cn1_value = 0; +- } else { +- if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GRAPHICS) { +- if (support.bits.graphics_content == 1) { +- cn0_cn1_value = 0; +- } +- } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_PHOTO) { +- if (support.bits.photo_content == 1) { +- cn0_cn1_value = 1; +- } else { +- cn0_cn1_value = 0; +- itc_value = 0; +- } +- } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_CINEMA) { +- if (support.bits.cinema_content == 1) { +- cn0_cn1_value = 2; +- } else { +- cn0_cn1_value = 0; +- itc_value = 0; +- } +- } else if (cn0_cn1 == DISPLAY_CONTENT_TYPE_GAME) { +- if (support.bits.game_content == 1) { +- cn0_cn1_value = 3; +- } else { +- cn0_cn1_value = 0; +- itc_value = 0; +- } +- } +- } +- hdmi_info.bits.CN0_CN1 = cn0_cn1_value; +- hdmi_info.bits.ITC = itc_value; ++ switch (stream->content_type) { ++ case DISPLAY_CONTENT_TYPE_NO_DATA: ++ hdmi_info.bits.CN0_CN1 = 0; ++ hdmi_info.bits.ITC = 0; ++ break; ++ case DISPLAY_CONTENT_TYPE_GRAPHICS: ++ hdmi_info.bits.CN0_CN1 = 0; ++ hdmi_info.bits.ITC = 1; ++ break; ++ case DISPLAY_CONTENT_TYPE_PHOTO: ++ hdmi_info.bits.CN0_CN1 = 1; ++ hdmi_info.bits.ITC = 1; ++ break; ++ case DISPLAY_CONTENT_TYPE_CINEMA: ++ hdmi_info.bits.CN0_CN1 = 2; ++ hdmi_info.bits.ITC = 1; ++ break; ++ case DISPLAY_CONTENT_TYPE_GAME: ++ hdmi_info.bits.CN0_CN1 = 3; ++ hdmi_info.bits.ITC = 1; ++ break; + } + + if (stream->qs_bit == 1) { +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 25284006019c3..82dcef4dbe782 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -206,6 +206,7 @@ struct dc_stream_state { + struct dc_csc_transform csc_color_matrix; + + enum dc_color_space output_color_space; ++ enum display_content_type content_type; + enum dc_dither_option dither_option; + + enum view_3d_format view_format; +-- +2.40.1 + + +From daedb3f12312fe6e3a1c6147fa15148477f163a9 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 17 Jan 2023 06:03:02 +0000 +Subject: [PATCH 18/59] drm/amd/display: Remove unused display_content_support + +This was never filled in and thus never truly used. + +Checking the EDID for content_type support is not required for sending the avi infoframe packet. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +(cherry picked from commit a3b57c86fae88c74c9ff8b48d44b8d7a1e3824cb) +Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> +--- + drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 - + drivers/gpu/drm/amd/display/dc/dc_types.h | 14 -------------- + 2 files changed, 15 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h +index 82dcef4dbe782..9f2c6fa501d16 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h +@@ -182,7 +182,6 @@ struct dc_stream_state { + */ + struct link_encoder *link_enc; + struct dc_panel_patch sink_patches; +- union display_content_support content_support; + struct dc_crtc_timing timing; + struct dc_crtc_timing_adjust adjust; + struct dc_info_packet vrr_infopacket; +diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h +index 45ab48fe5d004..fd92e09eb6932 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h +@@ -170,18 +170,6 @@ struct dc_edid { + + #define AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 20 + +-union display_content_support { +- unsigned int raw; +- struct { +- unsigned int valid_content_type :1; +- unsigned int game_content :1; +- unsigned int cinema_content :1; +- unsigned int photo_content :1; +- unsigned int graphics_content :1; +- unsigned int reserved :27; +- } bits; +-}; +- + struct dc_panel_patch { + unsigned int dppowerup_delay; + unsigned int extra_t12_ms; +@@ -214,8 +202,6 @@ struct dc_edid_caps { + uint32_t audio_latency; + uint32_t video_latency; + +- union display_content_support content_support; +- + uint8_t qs_bit; + uint8_t qy_bit; + +-- +2.40.1 + + +From ea7f73e73a0c102b5c51dc0ed2c5fbd18616b689 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Fri, 21 Apr 2023 22:39:34 -0100 +Subject: [PATCH 19/59] drm/drm_mode_object: increase max objects to + accommodate new color props + +DRM_OBJECT_MAX_PROPERTY limits the number of properties to be attached +and we are increasing that value all time we add a new property (generic +or driver-specific). + +In this series, we are adding 13 new KMS driver-specific properties for +AMD color manage: +- CRTC Gamma enumerated Transfer Function +- Plane: Degamma LUT+size+TF, HDR multiplier, shaper LUT+size+TF, 3D + LUT+size, blend LUT+size+TF (12) + +Therefore, just increase DRM_OBJECT_MAX_PROPERTY to a number (64) that +accomodates these new properties and gives some room for others, +avoiding change this number everytime we add a new KMS property. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + include/drm/drm_mode_object.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h +index 912f1e4156853..08d7a7f0188fe 100644 +--- a/include/drm/drm_mode_object.h ++++ b/include/drm/drm_mode_object.h +@@ -60,7 +60,7 @@ struct drm_mode_object { + void (*free_cb)(struct kref *kref); + }; + +-#define DRM_OBJECT_MAX_PROPERTY 24 ++#define DRM_OBJECT_MAX_PROPERTY 64 + /** + * struct drm_object_properties - property tracking for &drm_mode_object + */ +-- +2.40.1 + + +From 57f0e8749ce5a87138d83e4022ea5e95d82d0370 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Fri, 12 May 2023 15:15:26 -0100 +Subject: [PATCH 20/59] drm/drm_property: make replace_property_blob_from_id a + DRM helper + +Place it in drm_property where drm_property_replace_blob and +drm_property_lookup_blob live. Then we can use the DRM helper for +driver-specific KMS properties too. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/arm/malidp_crtc.c | 2 +- + drivers/gpu/drm/drm_atomic_uapi.c | 43 ++++----------------------- + drivers/gpu/drm/drm_property.c | 49 +++++++++++++++++++++++++++++++ + include/drm/drm_property.h | 6 ++++ + 4 files changed, 61 insertions(+), 39 deletions(-) + +diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c +index dc01c43f61930..d72c22dcf6855 100644 +--- a/drivers/gpu/drm/arm/malidp_crtc.c ++++ b/drivers/gpu/drm/arm/malidp_crtc.c +@@ -221,7 +221,7 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, + + /* + * The size of the ctm is checked in +- * drm_atomic_replace_property_blob_from_id. ++ * drm_property_replace_blob_from_id. + */ + ctm = (struct drm_color_ctm *)state->ctm->data; + for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { +diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c +index d867e7f9f2cd5..a6a9ee5086ddb 100644 +--- a/drivers/gpu/drm/drm_atomic_uapi.c ++++ b/drivers/gpu/drm/drm_atomic_uapi.c +@@ -362,39 +362,6 @@ static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, + return fence_ptr; + } + +-static int +-drm_atomic_replace_property_blob_from_id(struct drm_device *dev, +- struct drm_property_blob **blob, +- uint64_t blob_id, +- ssize_t expected_size, +- ssize_t expected_elem_size, +- bool *replaced) +-{ +- struct drm_property_blob *new_blob = NULL; +- +- if (blob_id != 0) { +- new_blob = drm_property_lookup_blob(dev, blob_id); +- if (new_blob == NULL) +- return -EINVAL; +- +- if (expected_size > 0 && +- new_blob->length != expected_size) { +- drm_property_blob_put(new_blob); +- return -EINVAL; +- } +- if (expected_elem_size > 0 && +- new_blob->length % expected_elem_size != 0) { +- drm_property_blob_put(new_blob); +- return -EINVAL; +- } +- } +- +- *replaced |= drm_property_replace_blob(blob, new_blob); +- drm_property_blob_put(new_blob); +- +- return 0; +-} +- + static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct drm_property *property, + uint64_t val) +@@ -415,7 +382,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + } else if (property == config->prop_vrr_enabled) { + state->vrr_enabled = val; + } else if (property == config->degamma_lut_property) { +- ret = drm_atomic_replace_property_blob_from_id(dev, ++ ret = drm_property_replace_blob_from_id(dev, + &state->degamma_lut, + val, + -1, sizeof(struct drm_color_lut), +@@ -423,7 +390,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + state->color_mgmt_changed |= replaced; + return ret; + } else if (property == config->ctm_property) { +- ret = drm_atomic_replace_property_blob_from_id(dev, ++ ret = drm_property_replace_blob_from_id(dev, + &state->ctm, + val, + sizeof(struct drm_color_ctm), -1, +@@ -431,7 +398,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + state->color_mgmt_changed |= replaced; + return ret; + } else if (property == config->gamma_lut_property) { +- ret = drm_atomic_replace_property_blob_from_id(dev, ++ ret = drm_property_replace_blob_from_id(dev, + &state->gamma_lut, + val, + -1, sizeof(struct drm_color_lut), +@@ -563,7 +530,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, + } else if (property == plane->color_range_property) { + state->color_range = val; + } else if (property == config->prop_fb_damage_clips) { +- ret = drm_atomic_replace_property_blob_from_id(dev, ++ ret = drm_property_replace_blob_from_id(dev, + &state->fb_damage_clips, + val, + -1, +@@ -729,7 +696,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, + if (state->link_status != DRM_LINK_STATUS_GOOD) + state->link_status = val; + } else if (property == config->hdr_output_metadata_property) { +- ret = drm_atomic_replace_property_blob_from_id(dev, ++ ret = drm_property_replace_blob_from_id(dev, + &state->hdr_output_metadata, + val, + sizeof(struct hdr_output_metadata), -1, +diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c +index dfec479830e49..f72ef6493340a 100644 +--- a/drivers/gpu/drm/drm_property.c ++++ b/drivers/gpu/drm/drm_property.c +@@ -751,6 +751,55 @@ bool drm_property_replace_blob(struct drm_property_blob **blob, + } + EXPORT_SYMBOL(drm_property_replace_blob); + ++/** ++ * drm_property_replace_blob_from_id - replace a blob property taking a reference ++ * @dev: DRM device ++ * @blob: a pointer to the member blob to be replaced ++ * @blob_id: the id of the new blob to replace with ++ * @expected_size: expected size of the blob property ++ * @expected_elem_size: expected size of an element in the blob property ++ * @replaced: if the blob was in fact replaced ++ * ++ * Look up the new blob from id, take its reference, check expected sizes of ++ * the blob and its element and replace the old blob by the new one. Advertise ++ * if the replacement operation was successful. ++ * ++ * Return: true if the blob was in fact replaced. -EINVAL if the new blob was ++ * not found or sizes don't match. ++ */ ++int drm_property_replace_blob_from_id(struct drm_device *dev, ++ struct drm_property_blob **blob, ++ uint64_t blob_id, ++ ssize_t expected_size, ++ ssize_t expected_elem_size, ++ bool *replaced) ++{ ++ struct drm_property_blob *new_blob = NULL; ++ ++ if (blob_id != 0) { ++ new_blob = drm_property_lookup_blob(dev, blob_id); ++ if (new_blob == NULL) ++ return -EINVAL; ++ ++ if (expected_size > 0 && ++ new_blob->length != expected_size) { ++ drm_property_blob_put(new_blob); ++ return -EINVAL; ++ } ++ if (expected_elem_size > 0 && ++ new_blob->length % expected_elem_size != 0) { ++ drm_property_blob_put(new_blob); ++ return -EINVAL; ++ } ++ } ++ ++ *replaced |= drm_property_replace_blob(blob, new_blob); ++ drm_property_blob_put(new_blob); ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_property_replace_blob_from_id); ++ + int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) + { +diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h +index 65bc9710a4702..082f29156b3e3 100644 +--- a/include/drm/drm_property.h ++++ b/include/drm/drm_property.h +@@ -279,6 +279,12 @@ struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, + const void *data); + struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, + uint32_t id); ++int drm_property_replace_blob_from_id(struct drm_device *dev, ++ struct drm_property_blob **blob, ++ uint64_t blob_id, ++ ssize_t expected_size, ++ ssize_t expected_elem_size, ++ bool *replaced); + int drm_property_replace_global_blob(struct drm_device *dev, + struct drm_property_blob **replace, + size_t length, +-- +2.40.1 + + +From c28dbee4f2aec811aa1fbfd2339cc1a886272d00 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Tue, 21 Mar 2023 15:30:20 -0100 +Subject: [PATCH 21/59] drm/drm_plane: track color mgmt changes per plane + +We will add color mgmt properties to DRM planes in the next patches and +we want to track when one of this properties change to define atomic +commit behaviors. Using a similar approach from CRTC color props, we set +a color_mgmt_changed boolean whenever a plane color prop changes. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/drm_atomic.c | 1 + + drivers/gpu/drm/drm_atomic_state_helper.c | 1 + + include/drm/drm_plane.h | 7 +++++++ + 3 files changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c +index 2c454568a607c..2925371d230da 100644 +--- a/drivers/gpu/drm/drm_atomic.c ++++ b/drivers/gpu/drm/drm_atomic.c +@@ -724,6 +724,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, + drm_get_color_encoding_name(state->color_encoding)); + drm_printf(p, "\tcolor-range=%s\n", + drm_get_color_range_name(state->color_range)); ++ drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); + + if (plane->funcs->atomic_print_state) + plane->funcs->atomic_print_state(p, state); +diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c +index 784e63d70a421..25bb0859fda74 100644 +--- a/drivers/gpu/drm/drm_atomic_state_helper.c ++++ b/drivers/gpu/drm/drm_atomic_state_helper.c +@@ -338,6 +338,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, + state->fence = NULL; + state->commit = NULL; + state->fb_damage_clips = NULL; ++ state->color_mgmt_changed = false; + } + EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); + +diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h +index 51291983ea445..52c3287da0daa 100644 +--- a/include/drm/drm_plane.h ++++ b/include/drm/drm_plane.h +@@ -237,6 +237,13 @@ struct drm_plane_state { + + /** @state: backpointer to global drm_atomic_state */ + struct drm_atomic_state *state; ++ ++ /** ++ * @color_mgmt_changed: Color management properties have changed. Used ++ * by the atomic helpers and drivers to steer the atomic commit control ++ * flow. ++ */ ++ bool color_mgmt_changed : 1; + }; + + static inline struct drm_rect +-- +2.40.1 + + +From 92c38e005f574eac3d0461d400606f1c4649a785 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Wed, 29 Mar 2023 11:30:31 -0400 +Subject: [PATCH 22/59] drm/amd/display: fix segment distribution for linear + LUTs + +The region and segment calculation was incapable of dealing +with regions of more than 16 segments. We first fix this. + +Now that we can support regions up to 256 elements we can +define a better segment distribution for near-linear LUTs +for our maximum of 256 HW-supported points. + +With these changes an "identity" LUT looks visually +indistinguishable from bypass and allows us to use +our 3DLUT. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/dc/dcn10/dcn10_cm_common.c | 95 +++++++++++++++---- + 1 file changed, 76 insertions(+), 19 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index 7a00fe525dfba..f27413e942801 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -346,20 +346,37 @@ bool cm_helper_translate_curve_to_hw_format( + * segment is from 2^-10 to 2^1 + * There are less than 256 points, for optimization + */ +- seg_distr[0] = 3; +- seg_distr[1] = 4; +- seg_distr[2] = 4; +- seg_distr[3] = 4; +- seg_distr[4] = 4; +- seg_distr[5] = 4; +- seg_distr[6] = 4; +- seg_distr[7] = 4; +- seg_distr[8] = 4; +- seg_distr[9] = 4; +- seg_distr[10] = 1; +- +- region_start = -10; +- region_end = 1; ++ if (output_tf->tf == TRANSFER_FUNCTION_LINEAR) { ++ seg_distr[0] = 0; /* 2 */ ++ seg_distr[1] = 1; /* 4 */ ++ seg_distr[2] = 2; /* 4 */ ++ seg_distr[3] = 3; /* 8 */ ++ seg_distr[4] = 4; /* 16 */ ++ seg_distr[5] = 5; /* 32 */ ++ seg_distr[6] = 6; /* 64 */ ++ seg_distr[7] = 7; /* 128 */ ++ ++ region_start = -8; ++ region_end = 1; ++ } else { ++ seg_distr[0] = 3; /* 8 */ ++ seg_distr[1] = 4; /* 16 */ ++ seg_distr[2] = 4; ++ seg_distr[3] = 4; ++ seg_distr[4] = 4; ++ seg_distr[5] = 4; ++ seg_distr[6] = 4; ++ seg_distr[7] = 4; ++ seg_distr[8] = 4; ++ seg_distr[9] = 4; ++ seg_distr[10] = 1; /* 2 */ ++ /* total = 8*16 + 8 + 64 + 2 = */ ++ ++ region_start = -10; ++ region_end = 1; ++ } ++ ++ + } + + for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) +@@ -372,16 +389,56 @@ bool cm_helper_translate_curve_to_hw_format( + + j = 0; + for (k = 0; k < (region_end - region_start); k++) { +- increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); ++ /* ++ * We're using an ugly-ish hack here. Our HW allows for ++ * 256 segments per region but SW_SEGMENTS is 16. ++ * SW_SEGMENTS has some undocumented relationship to ++ * the number of points in the tf_pts struct, which ++ * is 512, unlike what's suggested TRANSFER_FUNC_POINTS. ++ * ++ * In order to work past this dilemma we'll scale our ++ * increment by (1 << 4) and then do the inverse (1 >> 4) ++ * when accessing the elements in tf_pts. ++ * ++ * TODO: find a better way using SW_SEGMENTS and ++ * TRANSFER_FUNC_POINTS definitions ++ */ ++ increment = (NUMBER_SW_SEGMENTS << 4) / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; +- for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; ++ for (i = (start_index << 4); i < (start_index << 4) + (NUMBER_SW_SEGMENTS << 4); + i += increment) { ++ struct fixed31_32 in_plus_one, in; ++ struct fixed31_32 value, red_value, green_value, blue_value; ++ uint32_t t = i & 0xf; ++ + if (j == hw_points - 1) + break; +- rgb_resulted[j].red = output_tf->tf_pts.red[i]; +- rgb_resulted[j].green = output_tf->tf_pts.green[i]; +- rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; ++ ++ in_plus_one = output_tf->tf_pts.red[(i >> 4) + 1]; ++ in = output_tf->tf_pts.red[i >> 4]; ++ value = dc_fixpt_sub(in_plus_one, in); ++ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4); ++ value = dc_fixpt_add(in, value); ++ red_value = value; ++ ++ in_plus_one = output_tf->tf_pts.green[(i >> 4) + 1]; ++ in = output_tf->tf_pts.green[i >> 4]; ++ value = dc_fixpt_sub(in_plus_one, in); ++ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4); ++ value = dc_fixpt_add(in, value); ++ green_value = value; ++ ++ in_plus_one = output_tf->tf_pts.blue[(i >> 4) + 1]; ++ in = output_tf->tf_pts.blue[i >> 4]; ++ value = dc_fixpt_sub(in_plus_one, in); ++ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4); ++ value = dc_fixpt_add(in, value); ++ blue_value = value; ++ ++ rgb_resulted[j].red = red_value; ++ rgb_resulted[j].green = green_value; ++ rgb_resulted[j].blue = blue_value; + j++; + } + } +-- +2.40.1 + + +From daa6f9f1521c43a419cd4bf30eaed63408c9d497 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Thu, 6 Apr 2023 18:06:27 -0400 +Subject: [PATCH 23/59] drm/amd/display: fix the delta clamping for shaper LUT + +The shaper LUT requires a 10-bit value of the delta between +segments. We were using dc_fixpt_clamp_u0d10() to do that +but it doesn't do what we want it to do. It will preserve +10-bit precision after the decimal point, but that's not +quite what we want. We want 14-bit precision and discard +the 4 most-significant bytes. + +To do that we'll do dc_fixpt_clamp_u0d14() & 0x3ff instead. + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index f27413e942801..efa6cee649d0a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -539,10 +539,18 @@ bool cm_helper_translate_curve_to_hw_format( + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); + ++ + if (fixpoint == true) { +- rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red); +- rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green); +- rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue); ++ uint32_t red_clamp = dc_fixpt_clamp_u0d14(rgb->delta_red); ++ uint32_t green_clamp = dc_fixpt_clamp_u0d14(rgb->delta_green); ++ uint32_t blue_clamp = dc_fixpt_clamp_u0d14(rgb->delta_blue); ++ ++ if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10) ++ DC_LOG_WARNING("Losing delta precision while programming shaper LUT."); ++ ++ rgb->delta_red_reg = red_clamp & 0x3ff; ++ rgb->delta_green_reg = green_clamp & 0x3ff; ++ rgb->delta_blue_reg = blue_clamp & 0x3ff; + rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red); + rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green); + rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue); +-- +2.40.1 + + +From ecd0e951362b05025bb49ba9fdf9ec8ef58da1a4 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 22 May 2023 14:21:23 -0100 +Subject: [PATCH 24/59] drm/amd/display: add CRTC driver-specific property for + gamma TF + +Hook up driver-specific atomic operations for managing AMD color +properties and create AMD driver-specific color management properties +and attach them according to HW capabilities defined by `struct +dc_color_caps`. Add enumerated transfer function property to DRM CRTC +gamma to convert to wire encoding with or without a user gamma LUT. +Enumerated TFs are not supported yet by the DRM color pipeline, +therefore, create a DRM enum list with the predefined TFs supported by +the AMD display driver. + +Co-developed-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 36 ++++++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 8 +++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 22 ++++++ + .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 72 ++++++++++++++++++- + 4 files changed, 137 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index d60fe7eb5579a..73a1ce45ad4ce 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1248,6 +1248,38 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, + return &amdgpu_fb->base; + } + ++static const struct drm_prop_enum_list drm_transfer_function_enum_list[] = { ++ { DRM_TRANSFER_FUNCTION_DEFAULT, "Default" }, ++ { DRM_TRANSFER_FUNCTION_SRGB, "sRGB" }, ++ { DRM_TRANSFER_FUNCTION_BT709, "BT.709" }, ++ { DRM_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" }, ++ { DRM_TRANSFER_FUNCTION_LINEAR, "Linear" }, ++ { DRM_TRANSFER_FUNCTION_UNITY, "Unity" }, ++ { DRM_TRANSFER_FUNCTION_HLG, "HLG (Hybrid Log Gamma)" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, ++}; ++ ++#ifdef AMD_PRIVATE_COLOR ++static int ++amdgpu_display_create_color_properties(struct amdgpu_device *adev) ++{ ++ struct drm_property *prop; ++ ++ prop = drm_property_create_enum(adev_to_drm(adev), ++ DRM_MODE_PROP_ENUM, ++ "AMD_REGAMMA_TF", ++ drm_transfer_function_enum_list, ++ ARRAY_SIZE(drm_transfer_function_enum_list)); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.regamma_tf_property = prop; ++ ++ return 0; ++} ++#endif ++ + const struct drm_mode_config_funcs amdgpu_mode_funcs = { + .fb_create = amdgpu_display_user_framebuffer_create, + }; +@@ -1324,6 +1356,10 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) + return -ENOMEM; + } + ++#ifdef AMD_PRIVATE_COLOR ++ if (amdgpu_display_create_color_properties(adev)) ++ return -ENOMEM; ++#endif + return 0; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 32fe05c810c6f..156067c53c21a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -343,6 +343,14 @@ struct amdgpu_mode_info { + int disp_priority; + const struct amdgpu_display_funcs *funcs; + const enum drm_plane_type *plane_type; ++ ++ /* Driver-private color mgmt props */ ++ ++ /* @regamma_tf_property: Transfer function for CRTC regamma ++ * (post-blending). Possible values are defined by `enum ++ * drm_transfer_function`. ++ */ ++ struct drm_property *regamma_tf_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 2e2413fd73a4f..ad5ee28b83dcd 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -699,6 +699,20 @@ static inline void amdgpu_dm_set_mst_status(uint8_t *status, + + extern const struct amdgpu_ip_block_version dm_ip_block; + ++enum drm_transfer_function { ++ DRM_TRANSFER_FUNCTION_DEFAULT, ++ DRM_TRANSFER_FUNCTION_SRGB, ++ DRM_TRANSFER_FUNCTION_BT709, ++ DRM_TRANSFER_FUNCTION_PQ, ++ DRM_TRANSFER_FUNCTION_LINEAR, ++ DRM_TRANSFER_FUNCTION_UNITY, ++ DRM_TRANSFER_FUNCTION_HLG, ++ DRM_TRANSFER_FUNCTION_GAMMA22, ++ DRM_TRANSFER_FUNCTION_GAMMA24, ++ DRM_TRANSFER_FUNCTION_GAMMA26, ++ DRM_TRANSFER_FUNCTION_MAX, ++}; ++ + struct dm_plane_state { + struct drm_plane_state base; + struct dc_plane_state *dc_state; +@@ -726,6 +740,14 @@ struct dm_crtc_state { + struct dc_info_packet vrr_infopacket; + + int abm_level; ++ ++ /** ++ * @regamma_tf: ++ * ++ * Pre-defined transfer function for converting internal FB -> wire ++ * encoding. ++ */ ++ enum drm_transfer_function regamma_tf; + }; + + #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base) +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +index 440fc0869a34b..4a725aeef3e84 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -219,7 +219,6 @@ static void dm_crtc_destroy_state(struct drm_crtc *crtc, + if (cur->stream) + dc_stream_release(cur->stream); + +- + __drm_atomic_helper_crtc_destroy_state(state); + + +@@ -253,6 +252,7 @@ static struct drm_crtc_state *dm_crtc_duplicate_state(struct drm_crtc *crtc) + state->freesync_config = cur->freesync_config; + state->cm_has_degamma = cur->cm_has_degamma; + state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; ++ state->regamma_tf = cur->regamma_tf; + state->crc_skip_count = cur->crc_skip_count; + state->mpo_requested = cur->mpo_requested; + /* TODO Duplicate dc_stream after objects are stream object is flattened */ +@@ -289,6 +289,69 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc) + } + #endif + ++#ifdef AMD_PRIVATE_COLOR ++/** ++ * drm_crtc_additional_color_mgmt - enable additional color properties ++ * @crtc: DRM CRTC ++ * ++ * This function lets the driver enable the 3D LUT color correction property ++ * on a CRTC. This includes shaper LUT, 3D LUT and regamma TF. The shaper ++ * LUT and 3D LUT property is only attached if its size is not 0. ++ */ ++static void ++dm_crtc_additional_color_mgmt(struct drm_crtc *crtc) ++{ ++ struct amdgpu_device *adev = drm_to_adev(crtc->dev); ++ ++ if(adev->dm.dc->caps.color.mpc.ogam_ram) ++ drm_object_attach_property(&crtc->base, ++ adev->mode_info.regamma_tf_property, ++ DRM_TRANSFER_FUNCTION_DEFAULT); ++} ++ ++static int ++amdgpu_dm_atomic_crtc_set_property(struct drm_crtc *crtc, ++ struct drm_crtc_state *state, ++ struct drm_property *property, ++ uint64_t val) ++{ ++ struct amdgpu_device *adev = drm_to_adev(crtc->dev); ++ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state); ++ ++ if (property == adev->mode_info.regamma_tf_property) { ++ if (acrtc_state->regamma_tf != val) { ++ acrtc_state->regamma_tf = val; ++ acrtc_state->base.color_mgmt_changed |= 1; ++ } ++ } else { ++ drm_dbg_atomic(crtc->dev, ++ "[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n", ++ crtc->base.id, crtc->name, ++ property->base.id, property->name); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++amdgpu_dm_atomic_crtc_get_property(struct drm_crtc *crtc, ++ const struct drm_crtc_state *state, ++ struct drm_property *property, ++ uint64_t *val) ++{ ++ struct amdgpu_device *adev = drm_to_adev(crtc->dev); ++ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state); ++ ++ if (property == adev->mode_info.regamma_tf_property) ++ *val = acrtc_state->regamma_tf; ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++#endif ++ + /* Implemented only the options currently available for the driver */ + static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + .reset = dm_crtc_reset_state, +@@ -307,6 +370,10 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + #if defined(CONFIG_DEBUG_FS) + .late_register = amdgpu_dm_crtc_late_register, + #endif ++#ifdef AMD_PRIVATE_COLOR ++ .atomic_set_property = amdgpu_dm_atomic_crtc_set_property, ++ .atomic_get_property = amdgpu_dm_atomic_crtc_get_property, ++#endif + }; + + static void dm_crtc_helper_disable(struct drm_crtc *crtc) +@@ -470,6 +537,9 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, + + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); + ++#ifdef AMD_PRIVATE_COLOR ++ dm_crtc_additional_color_mgmt(&acrtc->base); ++#endif + return 0; + + fail: +-- +2.40.1 + + +From 74f4e9d658f61f4aef5ecd79dbfcfb9cd8262353 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Tue, 16 May 2023 14:55:28 -0100 +Subject: [PATCH 25/59] drm/amd/display: add plane driver-specific properties + for degamma LUT + +Create and attach driver-private properties for plane color management. +First add plane degamma LUT properties that means user-blob and its +size. We will add more plane color properties in the next commits. In +addition, we keep these driver-private plane properties limited by +defining AMD_PRIVATE_COLOR. + +Co-developed-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 14 ++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 8 ++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 +++ + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 77 +++++++++++++++++++ + 4 files changed, 108 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 73a1ce45ad4ce..eb13ac46da7b2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1276,6 +1276,20 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.regamma_tf_property = prop; + ++ prop = drm_property_create(adev_to_drm(adev), ++ DRM_MODE_PROP_BLOB, ++ "AMD_PLANE_DEGAMMA_LUT", 0); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_degamma_lut_property = prop; ++ ++ prop = drm_property_create_range(adev_to_drm(adev), ++ DRM_MODE_PROP_IMMUTABLE, ++ "AMD_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_degamma_lut_size_property = prop; ++ + return 0; + } + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 156067c53c21a..f420799e38593 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -351,6 +351,14 @@ struct amdgpu_mode_info { + * drm_transfer_function`. + */ + struct drm_property *regamma_tf_property; ++ /* @plane_degamma_lut_property: Plane property to set a degamma LUT to ++ * convert color space before blending. ++ */ ++ struct drm_property *plane_degamma_lut_property; ++ /* @plane_degamma_lut_size_property: Plane property to define the max ++ * size of degamma LUT as supported by the driver (read-only). ++ */ ++ struct drm_property *plane_degamma_lut_size_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index ad5ee28b83dcd..22e1266547676 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -716,6 +716,15 @@ enum drm_transfer_function { + struct dm_plane_state { + struct drm_plane_state base; + struct dc_plane_state *dc_state; ++ ++ /* Plane color mgmt */ ++ /** ++ * @degamma_lut: ++ * ++ * LUT for converting plane pixel data before going into plane merger. ++ * The blob (if not NULL) is an array of &struct drm_color_lut. ++ */ ++ struct drm_property_blob *degamma_lut; + }; + + struct dm_crtc_state { +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 3226689737479..e9cedc4068f13 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1338,6 +1338,9 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + dc_plane_state_retain(dm_plane_state->dc_state); + } + ++ if (dm_plane_state->degamma_lut) ++ drm_property_blob_get(dm_plane_state->degamma_lut); ++ + return &dm_plane_state->base; + } + +@@ -1405,12 +1408,79 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, + { + struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); + ++ if (dm_plane_state->degamma_lut) ++ drm_property_blob_put(dm_plane_state->degamma_lut); ++ + if (dm_plane_state->dc_state) + dc_plane_state_release(dm_plane_state->dc_state); + + drm_atomic_helper_plane_destroy_state(plane, state); + } + ++#ifdef AMD_PRIVATE_COLOR ++static void ++dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, ++ struct drm_plane *plane) ++{ ++ if (dm->dc->caps.color.dpp.dgam_ram || dm->dc->caps.color.dpp.gamma_corr ) { ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_degamma_lut_property, 0); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_degamma_lut_size_property, ++ MAX_COLOR_LUT_ENTRIES); ++ } ++} ++ ++static int ++dm_atomic_plane_set_property(struct drm_plane *plane, ++ struct drm_plane_state *state, ++ struct drm_property *property, ++ uint64_t val) ++{ ++ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); ++ struct amdgpu_device *adev = drm_to_adev(plane->dev); ++ bool replaced = false; ++ int ret; ++ ++ if (property == adev->mode_info.plane_degamma_lut_property) { ++ ret = drm_property_replace_blob_from_id(plane->dev, ++ &dm_plane_state->degamma_lut, ++ val, ++ -1, sizeof(struct drm_color_lut), ++ &replaced); ++ dm_plane_state->base.color_mgmt_changed |= replaced; ++ return ret; ++ } else { ++ drm_dbg_atomic(plane->dev, ++ "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", ++ plane->base.id, plane->name, ++ property->base.id, property->name); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++dm_atomic_plane_get_property(struct drm_plane *plane, ++ const struct drm_plane_state *state, ++ struct drm_property *property, ++ uint64_t *val) ++{ ++ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); ++ struct amdgpu_device *adev = drm_to_adev(plane->dev); ++ ++ if (property == adev->mode_info.plane_degamma_lut_property) { ++ *val = (dm_plane_state->degamma_lut) ? ++ dm_plane_state->degamma_lut->base.id : 0; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++#endif ++ + static const struct drm_plane_funcs dm_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, +@@ -1419,6 +1489,10 @@ static const struct drm_plane_funcs dm_plane_funcs = { + .atomic_duplicate_state = dm_drm_plane_duplicate_state, + .atomic_destroy_state = dm_drm_plane_destroy_state, + .format_mod_supported = dm_plane_format_mod_supported, ++#ifdef AMD_PRIVATE_COLOR ++ .atomic_set_property = dm_atomic_plane_set_property, ++ .atomic_get_property = dm_atomic_plane_get_property, ++#endif + }; + + int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, +@@ -1489,6 +1563,9 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, + + drm_plane_helper_add(plane, &dm_plane_helper_funcs); + ++#ifdef AMD_PRIVATE_COLOR ++ dm_atomic_plane_attach_color_mgmt_properties(dm, plane); ++#endif + /* Create (reset) the plane state */ + if (plane->funcs->reset) + plane->funcs->reset(plane); +-- +2.40.1 + + +From c80fcb0d0c947c741a5f93c9d5a774b6a45097c1 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 20 Apr 2023 15:07:34 -0100 +Subject: [PATCH 26/59] drm/amd/display: add plane degamma TF driver-specific + property + +Allow userspace to tell the kernel driver the input space and, +therefore, uses correct predefined transfer function (TF) to delinearize +content with or without LUT. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 9 ++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 5 +++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 ++++ + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 32 +++++++++++++++++-- + 4 files changed, 51 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index eb13ac46da7b2..7b63812b27e28 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1290,6 +1290,15 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_size_property = prop; + ++ prop = drm_property_create_enum(adev_to_drm(adev), ++ DRM_MODE_PROP_ENUM, ++ "AMD_PLANE_DEGAMMA_TF", ++ drm_transfer_function_enum_list, ++ ARRAY_SIZE(drm_transfer_function_enum_list)); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_degamma_tf_property = prop; ++ + return 0; + } + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index f420799e38593..58cc91ec3100d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -359,6 +359,11 @@ struct amdgpu_mode_info { + * size of degamma LUT as supported by the driver (read-only). + */ + struct drm_property *plane_degamma_lut_size_property; ++ /** ++ * @plane_degamma_tf_property: Predefined transfer function to ++ * linearize content with or without LUT. ++ */ ++ struct drm_property *plane_degamma_tf_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 22e1266547676..b8e432cc80781 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -725,6 +725,13 @@ struct dm_plane_state { + * The blob (if not NULL) is an array of &struct drm_color_lut. + */ + struct drm_property_blob *degamma_lut; ++ /** ++ * @degamma_tf: ++ * ++ * Predefined transfer function to tell DC driver the input space to ++ * linearize. ++ */ ++ enum drm_transfer_function degamma_tf; + }; + + struct dm_crtc_state { +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index e9cedc4068f13..6b71777a525ce 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1317,8 +1317,11 @@ static void dm_drm_plane_reset(struct drm_plane *plane) + amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL); + WARN_ON(amdgpu_state == NULL); + +- if (amdgpu_state) +- __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); ++ if (!amdgpu_state) ++ return; ++ ++ __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); ++ amdgpu_state->degamma_tf = DRM_TRANSFER_FUNCTION_DEFAULT; + } + + static struct drm_plane_state * +@@ -1341,6 +1344,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + if (dm_plane_state->degamma_lut) + drm_property_blob_get(dm_plane_state->degamma_lut); + ++ dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; ++ + return &dm_plane_state->base; + } + +@@ -1417,6 +1422,19 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, + drm_atomic_helper_plane_destroy_state(plane, state); + } + ++static const struct drm_prop_enum_list drm_transfer_function_enum_list[] = { ++ { DRM_TRANSFER_FUNCTION_DEFAULT, "Default" }, ++ { DRM_TRANSFER_FUNCTION_SRGB, "sRGB" }, ++ { DRM_TRANSFER_FUNCTION_BT709, "BT.709" }, ++ { DRM_TRANSFER_FUNCTION_PQ, "PQ (Perceptual Quantizer)" }, ++ { DRM_TRANSFER_FUNCTION_LINEAR, "Linear" }, ++ { DRM_TRANSFER_FUNCTION_UNITY, "Unity" }, ++ { DRM_TRANSFER_FUNCTION_HLG, "HLG (Hybrid Log Gamma)" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA22, "Gamma 2.2" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA24, "Gamma 2.4" }, ++ { DRM_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, ++}; ++ + #ifdef AMD_PRIVATE_COLOR + static void + dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, +@@ -1428,6 +1446,9 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_degamma_lut_size_property, + MAX_COLOR_LUT_ENTRIES); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_degamma_tf_property, ++ DRM_TRANSFER_FUNCTION_DEFAULT); + } + } + +@@ -1450,6 +1471,11 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; ++ } else if (property == adev->mode_info.plane_degamma_tf_property) { ++ if (dm_plane_state->degamma_tf != val) { ++ dm_plane_state->degamma_tf = val; ++ dm_plane_state->base.color_mgmt_changed = 1; ++ } + } else { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", +@@ -1473,6 +1499,8 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + if (property == adev->mode_info.plane_degamma_lut_property) { + *val = (dm_plane_state->degamma_lut) ? + dm_plane_state->degamma_lut->base.id : 0; ++ } else if (property == adev->mode_info.plane_degamma_tf_property) { ++ *val = dm_plane_state->degamma_tf; + } else { + return -EINVAL; + } +-- +2.40.1 + + +From ce5029c84e4232375be266d960c101581047476a Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 20 Apr 2023 15:33:22 -0100 +Subject: [PATCH 27/59] drm/amd/display: add plane HDR multiplier + driver-specific property + +Multiplier to 'gain' the plane. When PQ is decoded using the fixed func +transfer function to the internal FP16 fb, 1.0 -> 80 nits (on AMD at +least) When sRGB is decoded, 1.0 -> 1.0. Therefore, 1.0 multiplier = 80 +nits for SDR content. So if you want, 203 nits for SDR content, pass in +(203.0 / 80.0). + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 6 ++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 4 ++++ + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 ++++++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 13 +++++++++++++ + 4 files changed, 35 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 7b63812b27e28..3002128980077 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1299,6 +1299,12 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_degamma_tf_property = prop; + ++ prop = drm_property_create_range(adev_to_drm(adev), ++ 0, "AMD_PLANE_HDR_MULT", 0, U64_MAX); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_hdr_mult_property = prop; ++ + return 0; + } + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 58cc91ec3100d..899708f1e7d85 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -364,6 +364,10 @@ struct amdgpu_mode_info { + * linearize content with or without LUT. + */ + struct drm_property *plane_degamma_tf_property; ++ /** ++ * @plane_hdr_mult_property: ++ */ ++ struct drm_property *plane_hdr_mult_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index b8e432cc80781..dadbef561606d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -51,6 +51,7 @@ + + #define AMDGPU_DMUB_NOTIFICATION_MAX 5 + ++#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) + /* + #include "include/amdgpu_dal_power_if.h" + #include "amdgpu_dm_irq.h" +@@ -732,6 +733,17 @@ struct dm_plane_state { + * linearize. + */ + enum drm_transfer_function degamma_tf; ++ /** ++ * @hdr_mult: ++ * ++ * Multiplier to 'gain' the plane. When PQ is decoded using the fixed ++ * func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on ++ * AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously. ++ * Therefore, 1.0 multiplier = 80 nits for SDR content. So if you ++ * want, 203 nits for SDR content, pass in (203.0 / 80.0). Format is ++ * S31.32 sign-magnitude. ++ */ ++ __u64 hdr_mult; + }; + + struct dm_crtc_state { +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 6b71777a525ce..bbbf25dd2515b 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1322,6 +1322,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) + + __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); + amdgpu_state->degamma_tf = DRM_TRANSFER_FUNCTION_DEFAULT; ++ amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; + } + + static struct drm_plane_state * +@@ -1345,6 +1346,7 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + drm_property_blob_get(dm_plane_state->degamma_lut); + + dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; ++ dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; + + return &dm_plane_state->base; + } +@@ -1450,6 +1452,10 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + dm->adev->mode_info.plane_degamma_tf_property, + DRM_TRANSFER_FUNCTION_DEFAULT); + } ++ /* HDR MULT is always available */ ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_hdr_mult_property, ++ AMDGPU_HDR_MULT_DEFAULT); + } + + static int +@@ -1476,6 +1482,11 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + dm_plane_state->degamma_tf = val; + dm_plane_state->base.color_mgmt_changed = 1; + } ++ } else if (property == adev->mode_info.plane_hdr_mult_property) { ++ if (dm_plane_state->hdr_mult != val) { ++ dm_plane_state->hdr_mult = val; ++ dm_plane_state->base.color_mgmt_changed = 1; ++ } + } else { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", +@@ -1501,6 +1512,8 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + dm_plane_state->degamma_lut->base.id : 0; + } else if (property == adev->mode_info.plane_degamma_tf_property) { + *val = dm_plane_state->degamma_tf; ++ } else if (property == adev->mode_info.plane_hdr_mult_property) { ++ *val = dm_plane_state->hdr_mult; + } else { + return -EINVAL; + } +-- +2.40.1 + + +From c14719939780ba3ba812011a4e2d5c56218a633e Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Thu, 20 Apr 2023 16:03:11 -0100 +Subject: [PATCH 28/59] drm/amd/display: add plane 3D LUT driver-specific + properties + +Add 3D LUT property for plane gamma correction using a 3D lookup table. +Since a 3D LUT has a limited number of entries in each dimension we want +to use them in an optimal fashion. This means using the 3D LUT in a +colorspace that is optimized for human vision, such as sRGB, PQ, or +another non-linear space. Therefore, userpace may need one 1D LUT +(shaper) before it to delinearize content and another 1D LUT after 3D +LUT (blend) to linearize content again for blending. The next patches +add these 1D LUTs to the plane color mgmt pipeline. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 14 +++++++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 10 ++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 9 ++++++++ + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 23 +++++++++++++++++++ + 4 files changed, 56 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 3002128980077..3b4b01ee9f07f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1305,6 +1305,20 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_hdr_mult_property = prop; + ++ prop = drm_property_create(adev_to_drm(adev), ++ DRM_MODE_PROP_BLOB, ++ "AMD_PLANE_LUT3D", 0); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_lut3d_property = prop; ++ ++ prop = drm_property_create_range(adev_to_drm(adev), ++ DRM_MODE_PROP_IMMUTABLE, ++ "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_lut3d_size_property = prop; ++ + return 0; + } + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 899708f1e7d85..cde06717360a0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -368,6 +368,16 @@ struct amdgpu_mode_info { + * @plane_hdr_mult_property: + */ + struct drm_property *plane_hdr_mult_property; ++ /** ++ * @plane_lut3d_property: Plane property for gamma correction using a ++ * 3D LUT (pre-blending). ++ */ ++ struct drm_property *plane_lut3d_property; ++ /** ++ * @plane_degamma_lut_size_property: Plane property to define the max ++ * size of 3D LUT as supported by the driver (read-only). ++ */ ++ struct drm_property *plane_lut3d_size_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index dadbef561606d..7e4978c2f2538 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -744,6 +744,11 @@ struct dm_plane_state { + * S31.32 sign-magnitude. + */ + __u64 hdr_mult; ++ /** ++ * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of ++ * &struct drm_color_lut. ++ */ ++ struct drm_property_blob *lut3d; + }; + + struct dm_crtc_state { +@@ -837,6 +842,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, + + void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); + ++/* 3D LUT max size is 17x17x17 */ ++#define MAX_COLOR_3DLUT_ENTRIES 4913 ++#define MAX_COLOR_3DLUT_BITDEPTH 12 ++/* 1D LUT size */ + #define MAX_COLOR_LUT_ENTRIES 4096 + /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ + #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index bbbf25dd2515b..5fc3855448d04 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1344,6 +1344,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + + if (dm_plane_state->degamma_lut) + drm_property_blob_get(dm_plane_state->degamma_lut); ++ if (dm_plane_state->lut3d) ++ drm_property_blob_get(dm_plane_state->lut3d); + + dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; + dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; +@@ -1417,6 +1419,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, + + if (dm_plane_state->degamma_lut) + drm_property_blob_put(dm_plane_state->degamma_lut); ++ if (dm_plane_state->lut3d) ++ drm_property_blob_put(dm_plane_state->lut3d); + + if (dm_plane_state->dc_state) + dc_plane_state_release(dm_plane_state->dc_state); +@@ -1456,6 +1460,14 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_hdr_mult_property, + AMDGPU_HDR_MULT_DEFAULT); ++ ++ if (dm->dc->caps.color.dpp.hw_3d_lut) { ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_lut3d_property, 0); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_lut3d_size_property, ++ MAX_COLOR_3DLUT_ENTRIES); ++ } + } + + static int +@@ -1487,6 +1499,14 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + dm_plane_state->hdr_mult = val; + dm_plane_state->base.color_mgmt_changed = 1; + } ++ } else if (property == adev->mode_info.plane_lut3d_property) { ++ ret = drm_property_replace_blob_from_id(plane->dev, ++ &dm_plane_state->lut3d, ++ val, -1, ++ sizeof(struct drm_color_lut), ++ &replaced); ++ dm_plane_state->base.color_mgmt_changed |= replaced; ++ return ret; + } else { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", +@@ -1514,6 +1534,9 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + *val = dm_plane_state->degamma_tf; + } else if (property == adev->mode_info.plane_hdr_mult_property) { + *val = dm_plane_state->hdr_mult; ++ } else if (property == adev->mode_info.plane_lut3d_property) { ++ *val = (dm_plane_state->lut3d) ? ++ dm_plane_state->lut3d->base.id : 0; + } else { + return -EINVAL; + } +-- +2.40.1 + + +From 433312a60d8b1c2a4df7e66d56b7e90cdeeea15f Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Thu, 20 Apr 2023 16:30:39 -0100 +Subject: [PATCH 29/59] drm/amd/display: add plane shaper LUT driver-specific + properties + +On AMD HW, 3D LUT always assumes a preceding shaper 1D LUT used for +delinearizing and/or normalizing the color space before applying a 3D +LUT. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 14 +++++++++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 10 ++++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5 +++++ + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 20 +++++++++++++++++++ + 4 files changed, 49 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 3b4b01ee9f07f..891cf16ebfa06 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1305,6 +1305,20 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_hdr_mult_property = prop; + ++ prop = drm_property_create(adev_to_drm(adev), ++ DRM_MODE_PROP_BLOB, ++ "AMD_PLANE_SHAPER_LUT", 0); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_shaper_lut_property = prop; ++ ++ prop = drm_property_create_range(adev_to_drm(adev), ++ DRM_MODE_PROP_IMMUTABLE, ++ "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_shaper_lut_size_property = prop; ++ + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_LUT3D", 0); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index cde06717360a0..52dfffafe23f9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -368,6 +368,16 @@ struct amdgpu_mode_info { + * @plane_hdr_mult_property: + */ + struct drm_property *plane_hdr_mult_property; ++ /** ++ * @shaper_lut_property: Plane property to set pre-blending shaper LUT ++ * that converts color content before 3D LUT. ++ */ ++ struct drm_property *plane_shaper_lut_property; ++ /** ++ * @shaper_lut_size_property: Plane property for the size of ++ * pre-blending shaper LUT as supported by the driver (read-only). ++ */ ++ struct drm_property *plane_shaper_lut_size_property; + /** + * @plane_lut3d_property: Plane property for gamma correction using a + * 3D LUT (pre-blending). +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 7e4978c2f2538..fa0bb6a5c5984 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -744,6 +744,11 @@ struct dm_plane_state { + * S31.32 sign-magnitude. + */ + __u64 hdr_mult; ++ /** ++ * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an ++ * array of &struct drm_color_lut. ++ */ ++ struct drm_property_blob *shaper_lut; + /** + * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of + * &struct drm_color_lut. +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 5fc3855448d04..abc5b9a353a03 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1344,6 +1344,8 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + + if (dm_plane_state->degamma_lut) + drm_property_blob_get(dm_plane_state->degamma_lut); ++ if (dm_plane_state->shaper_lut) ++ drm_property_blob_get(dm_plane_state->shaper_lut); + if (dm_plane_state->lut3d) + drm_property_blob_get(dm_plane_state->lut3d); + +@@ -1421,6 +1423,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, + drm_property_blob_put(dm_plane_state->degamma_lut); + if (dm_plane_state->lut3d) + drm_property_blob_put(dm_plane_state->lut3d); ++ if (dm_plane_state->shaper_lut) ++ drm_property_blob_put(dm_plane_state->shaper_lut); + + if (dm_plane_state->dc_state) + dc_plane_state_release(dm_plane_state->dc_state); +@@ -1462,6 +1466,11 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + AMDGPU_HDR_MULT_DEFAULT); + + if (dm->dc->caps.color.dpp.hw_3d_lut) { ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_shaper_lut_property, 0); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_shaper_lut_size_property, ++ MAX_COLOR_LUT_ENTRIES); + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_lut3d_property, 0); + drm_object_attach_property(&plane->base, +@@ -1499,6 +1508,14 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + dm_plane_state->hdr_mult = val; + dm_plane_state->base.color_mgmt_changed = 1; + } ++ } else if (property == adev->mode_info.plane_shaper_lut_property) { ++ ret = drm_property_replace_blob_from_id(plane->dev, ++ &dm_plane_state->shaper_lut, ++ val, -1, ++ sizeof(struct drm_color_lut), ++ &replaced); ++ dm_plane_state->base.color_mgmt_changed |= replaced; ++ return ret; + } else if (property == adev->mode_info.plane_lut3d_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->lut3d, +@@ -1534,6 +1551,9 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + *val = dm_plane_state->degamma_tf; + } else if (property == adev->mode_info.plane_hdr_mult_property) { + *val = dm_plane_state->hdr_mult; ++ } else if (property == adev->mode_info.plane_shaper_lut_property) { ++ *val = (dm_plane_state->shaper_lut) ? ++ dm_plane_state->shaper_lut->base.id : 0; + } else if (property == adev->mode_info.plane_lut3d_property) { + *val = (dm_plane_state->lut3d) ? + dm_plane_state->lut3d->base.id : 0; +-- +2.40.1 + + +From 3cb40107c641ef07f63ecceb40683309aee5c743 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Thu, 20 Apr 2023 16:36:46 -0100 +Subject: [PATCH 30/59] drm/amd/display: add plane shaper TF driver-private + property + +Add property to set predefined transfer function to enable delinearizing +content with or without shaper LUT. Drivers should advertize this +property acoording to HW caps. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 9 +++++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 6 ++++++ + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 ++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 12 ++++++++++++ + 4 files changed, 33 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 891cf16ebfa06..b267873cdddde 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1319,6 +1319,15 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_size_property = prop; + ++ prop = drm_property_create_enum(adev_to_drm(adev), ++ DRM_MODE_PROP_ENUM, ++ "AMD_PLANE_SHAPER_TF", ++ drm_transfer_function_enum_list, ++ ARRAY_SIZE(drm_transfer_function_enum_list)); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_shaper_tf_property = prop; ++ + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_LUT3D", 0); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 52dfffafe23f9..1154babd2b671 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -378,6 +378,12 @@ struct amdgpu_mode_info { + * pre-blending shaper LUT as supported by the driver (read-only). + */ + struct drm_property *plane_shaper_lut_size_property; ++ /** ++ * @plane_shaper_tf_property: Plane property to set a predefined ++ * transfer function for pre-blending shaper (before applying 3D LUT) ++ * with or without LUT. ++ */ ++ struct drm_property *plane_shaper_tf_property; + /** + * @plane_lut3d_property: Plane property for gamma correction using a + * 3D LUT (pre-blending). +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index fa0bb6a5c5984..663ffc7d648e6 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -749,6 +749,12 @@ struct dm_plane_state { + * array of &struct drm_color_lut. + */ + struct drm_property_blob *shaper_lut; ++ /** ++ * @shaper_tf: ++ * ++ * Predefined transfer function to delinearize color space. ++ */ ++ enum drm_transfer_function shaper_tf; + /** + * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of + * &struct drm_color_lut. +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index abc5b9a353a03..61e47bdecde4e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1323,6 +1323,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) + __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); + amdgpu_state->degamma_tf = DRM_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; ++ amdgpu_state->shaper_tf = DRM_TRANSFER_FUNCTION_DEFAULT; + } + + static struct drm_plane_state * +@@ -1351,6 +1352,7 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + + dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; + dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; ++ dm_plane_state->shaper_tf = old_dm_plane_state->shaper_tf; + + return &dm_plane_state->base; + } +@@ -1471,6 +1473,9 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_shaper_lut_size_property, + MAX_COLOR_LUT_ENTRIES); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_shaper_tf_property, ++ DRM_TRANSFER_FUNCTION_DEFAULT); + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_lut3d_property, 0); + drm_object_attach_property(&plane->base, +@@ -1516,6 +1521,11 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; ++ } else if (property == adev->mode_info.plane_shaper_tf_property) { ++ if (dm_plane_state->shaper_tf != val) { ++ dm_plane_state->shaper_tf = val; ++ dm_plane_state->base.color_mgmt_changed = 1; ++ } + } else if (property == adev->mode_info.plane_lut3d_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->lut3d, +@@ -1554,6 +1564,8 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + } else if (property == adev->mode_info.plane_shaper_lut_property) { + *val = (dm_plane_state->shaper_lut) ? + dm_plane_state->shaper_lut->base.id : 0; ++ } else if (property == adev->mode_info.plane_shaper_tf_property) { ++ *val = dm_plane_state->shaper_tf; + } else if (property == adev->mode_info.plane_lut3d_property) { + *val = (dm_plane_state->lut3d) ? + dm_plane_state->lut3d->base.id : 0; +-- +2.40.1 + + +From 1eb847da50db7a06c32eb6116a645f9f840e587a Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 20 Apr 2023 16:54:38 -0100 +Subject: [PATCH 31/59] drm/amd/display: add plane blend LUT and TF + driver-specific properties + +Blend 1D LUT or a predefined transfer function can be set to linearize +content before blending, so that it's positioned just before blending +planes in the AMD color mgmt pipeline, and after 3D LUT (non-linear +space). Shaper and Blend LUTs are 1D LUTs that sandwich 3D LUT. Drivers +should advertize blend properties according to HW caps. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 23 ++++++++++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 18 ++++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 +++++++ + .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 36 +++++++++++++++++++ + 4 files changed, 89 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index b267873cdddde..708866da78633 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1342,6 +1342,29 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + return -ENOMEM; + adev->mode_info.plane_lut3d_size_property = prop; + ++ prop = drm_property_create(adev_to_drm(adev), ++ DRM_MODE_PROP_BLOB, ++ "AMD_PLANE_BLEND_LUT", 0); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_blend_lut_property = prop; ++ ++ prop = drm_property_create_range(adev_to_drm(adev), ++ DRM_MODE_PROP_IMMUTABLE, ++ "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_blend_lut_size_property = prop; ++ ++ prop = drm_property_create_enum(adev_to_drm(adev), ++ DRM_MODE_PROP_ENUM, ++ "AMD_PLANE_BLEND_TF", ++ drm_transfer_function_enum_list, ++ ARRAY_SIZE(drm_transfer_function_enum_list)); ++ if (!prop) ++ return -ENOMEM; ++ adev->mode_info.plane_blend_tf_property = prop; ++ + return 0; + } + #endif +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +index 1154babd2b671..34291cd134a1b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +@@ -394,6 +394,24 @@ struct amdgpu_mode_info { + * size of 3D LUT as supported by the driver (read-only). + */ + struct drm_property *plane_lut3d_size_property; ++ /** ++ * @plane_blend_lut_property: Plane property for output gamma before ++ * blending. Userspace set a blend LUT to convert colors after 3D LUT ++ * conversion. It works as a post-3D LUT 1D LUT, with shaper LUT, they ++ * are sandwiching 3D LUT with two 1D LUT. ++ */ ++ struct drm_property *plane_blend_lut_property; ++ /** ++ * @plane_blend_lut_size_property: Plane property to define the max ++ * size of blend LUT as supported by the driver (read-only). ++ */ ++ struct drm_property *plane_blend_lut_size_property; ++ /** ++ * @plane_blend_tf_property: Plane property to set a predefined ++ * transfer function for pre-blending blend (before applying 3D LUT) ++ * with or without LUT. ++ */ ++ struct drm_property *plane_blend_tf_property; + }; + + #define AMDGPU_MAX_BL_LEVEL 0xFF +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index 663ffc7d648e6..ac430a23d3e14 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -760,6 +760,18 @@ struct dm_plane_state { + * &struct drm_color_lut. + */ + struct drm_property_blob *lut3d; ++ /** ++ * @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an ++ * array of &struct drm_color_lut. ++ */ ++ struct drm_property_blob *blend_lut; ++ /** ++ * @blend_tf: ++ * ++ * Pre-defined transfer function for converting plane pixel data before ++ * applying blend LUT. ++ */ ++ enum drm_transfer_function blend_tf; + }; + + struct dm_crtc_state { +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 61e47bdecde4e..ea13b49fa0215 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1324,6 +1324,7 @@ static void dm_drm_plane_reset(struct drm_plane *plane) + amdgpu_state->degamma_tf = DRM_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; + amdgpu_state->shaper_tf = DRM_TRANSFER_FUNCTION_DEFAULT; ++ amdgpu_state->blend_tf = DRM_TRANSFER_FUNCTION_DEFAULT; + } + + static struct drm_plane_state * +@@ -1349,10 +1350,13 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane) + drm_property_blob_get(dm_plane_state->shaper_lut); + if (dm_plane_state->lut3d) + drm_property_blob_get(dm_plane_state->lut3d); ++ if (dm_plane_state->blend_lut) ++ drm_property_blob_get(dm_plane_state->blend_lut); + + dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; + dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; + dm_plane_state->shaper_tf = old_dm_plane_state->shaper_tf; ++ dm_plane_state->blend_tf = old_dm_plane_state->blend_tf; + + return &dm_plane_state->base; + } +@@ -1427,6 +1431,8 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane, + drm_property_blob_put(dm_plane_state->lut3d); + if (dm_plane_state->shaper_lut) + drm_property_blob_put(dm_plane_state->shaper_lut); ++ if (dm_plane_state->blend_lut) ++ drm_property_blob_put(dm_plane_state->blend_lut); + + if (dm_plane_state->dc_state) + dc_plane_state_release(dm_plane_state->dc_state); +@@ -1482,6 +1488,17 @@ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + dm->adev->mode_info.plane_lut3d_size_property, + MAX_COLOR_3DLUT_ENTRIES); + } ++ ++ if (dm->dc->caps.color.dpp.ogam_ram) { ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_blend_lut_property, 0); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_blend_lut_size_property, ++ MAX_COLOR_LUT_ENTRIES); ++ drm_object_attach_property(&plane->base, ++ dm->adev->mode_info.plane_blend_tf_property, ++ DRM_TRANSFER_FUNCTION_DEFAULT); ++ } + } + + static int +@@ -1534,6 +1551,19 @@ dm_atomic_plane_set_property(struct drm_plane *plane, + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; ++ } else if (property == adev->mode_info.plane_blend_lut_property) { ++ ret = drm_property_replace_blob_from_id(plane->dev, ++ &dm_plane_state->blend_lut, ++ val, -1, ++ sizeof(struct drm_color_lut), ++ &replaced); ++ dm_plane_state->base.color_mgmt_changed |= replaced; ++ return ret; ++ } else if (property == adev->mode_info.plane_blend_tf_property) { ++ if (dm_plane_state->blend_tf != val) { ++ dm_plane_state->blend_tf = val; ++ dm_plane_state->base.color_mgmt_changed = 1; ++ } + } else { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", +@@ -1569,6 +1599,12 @@ dm_atomic_plane_get_property(struct drm_plane *plane, + } else if (property == adev->mode_info.plane_lut3d_property) { + *val = (dm_plane_state->lut3d) ? + dm_plane_state->lut3d->base.id : 0; ++ } else if (property == adev->mode_info.plane_blend_lut_property) { ++ *val = (dm_plane_state->blend_lut) ? ++ dm_plane_state->blend_lut->base.id : 0; ++ } else if (property == adev->mode_info.plane_blend_tf_property) { ++ *val = dm_plane_state->blend_tf; ++ + } else { + return -EINVAL; + } +-- +2.40.1 + + +From b6b0b5ba464cc962394016a25a63729b684ff0da Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 22 Aug 2022 19:07:56 -0100 +Subject: [PATCH 32/59] drm/amd/display: add comments to describe DM crtc color + mgmt behavior + +Describe some expected behavior of the AMD DM color mgmt programming. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index a4cb23d059bd6..fe779d10834e7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -440,12 +440,23 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) + stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + ++ /* Note: although we pass has_rom as parameter here, we never ++ * actually use ROM because the color module only takes the ROM ++ * path if transfer_func->type == PREDEFINED. ++ * ++ * See more in mod_color_calculate_regamma_params() ++ */ + r = __set_legacy_tf(stream->out_transfer_func, regamma_lut, + regamma_size, has_rom); + if (r) + return r; + } else if (has_regamma) { +- /* If atomic regamma, CRTC RGM goes into RGM LUT. */ ++ /* CRTC RGM goes into RGM LUT. ++ * ++ * Note: there is no implicit sRGB regamma here. We are using ++ * degamma calculation from color module to calculate the curve ++ * from a linear base. ++ */ + stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + +-- +2.40.1 + + +From 48f91e65a89f55c4aafffb287f54c3531050d04d Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Thu, 9 Mar 2023 13:28:18 -0100 +Subject: [PATCH 33/59] drm/amd/display: encapsulate atomic regamma operation + +We will wire up MPC 3D LUT to DM CRTC color pipeline in the next patch, +but so far, only for atomic interface. By checking +set_output_transfer_func in DC drivers with MPC 3D LUT support, we can +verify that regamma is only programmed when 3D LUT programming fails. As +a groundwork to introduce 3D LUT programming and better understand each +step, detach atomic regamma programming from the crtc colocr updating +code. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 53 ++++++++++++------- + 1 file changed, 34 insertions(+), 19 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index fe779d10834e7..fe03f1ec326e7 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -303,6 +303,36 @@ static int __set_output_tf(struct dc_transfer_func *func, + return res ? 0 : -ENOMEM; + } + ++static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, ++ const struct drm_color_lut *regamma_lut, ++ uint32_t regamma_size, bool has_rom) ++{ ++ struct dc_transfer_func *out_tf = stream->out_transfer_func; ++ int ret = 0; ++ ++ if (regamma_size) { ++ /* CRTC RGM goes into RGM LUT. ++ * ++ * Note: there is no implicit sRGB regamma here. We are using ++ * degamma calculation from color module to calculate the curve ++ * from a linear base. ++ */ ++ out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; ++ out_tf->tf = TRANSFER_FUNCTION_LINEAR; ++ ++ ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); ++ } else { ++ /* ++ * No CRTC RGM means we can just put the block into bypass ++ * since we don't have any plane level adjustments using it. ++ */ ++ out_tf->type = TF_TYPE_BYPASS; ++ out_tf->tf = TRANSFER_FUNCTION_LINEAR; ++ } ++ ++ return ret; ++} ++ + /** + * __set_input_tf - calculates the input transfer function based on expected + * input space. +@@ -450,27 +480,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) + regamma_size, has_rom); + if (r) + return r; +- } else if (has_regamma) { +- /* CRTC RGM goes into RGM LUT. +- * +- * Note: there is no implicit sRGB regamma here. We are using +- * degamma calculation from color module to calculate the curve +- * from a linear base. +- */ +- stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; +- stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; +- +- r = __set_output_tf(stream->out_transfer_func, regamma_lut, +- regamma_size, has_rom); ++ } else { ++ regamma_size = has_regamma ? regamma_size : 0; ++ r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, ++ regamma_size, has_rom); + if (r) + return r; +- } else { +- /* +- * No CRTC RGM means we can just put the block into bypass +- * since we don't have any plane level adjustments using it. +- */ +- stream->out_transfer_func->type = TF_TYPE_BYPASS; +- stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + } + + /* +-- +2.40.1 + + +From 0a9956269468523d7b641df97782242c26530c7d Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Wed, 31 Aug 2022 23:39:29 -0100 +Subject: [PATCH 34/59] drm/amd/display: update lut3d and shaper lut to stream + +It follows the same path of out_transfer_func for stream updates, since +shaper LUT and 3D LUT is programmed in funcs.set_output_transfer_func() +and this function is called in the atomic commit_tail when +update_flags.bits.out_tf is set. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 7cde67b7f0c33..da1689de5d68a 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -2606,7 +2606,7 @@ static enum surface_update_type check_update_surfaces_for_stream( + stream_update->integer_scaling_update) + su_flags->bits.scaling = 1; + +- if (stream_update->out_transfer_func) ++ if (stream_update->out_transfer_func || stream_update->lut3d_func) + su_flags->bits.out_tf = 1; + + if (stream_update->abm_level) +@@ -2955,6 +2955,14 @@ static void copy_stream_update_to_stream(struct dc *dc, + sizeof(struct dc_transfer_func_distributed_points)); + } + ++ if (update->func_shaper && ++ stream->func_shaper != update->func_shaper) ++ stream->func_shaper = update->func_shaper; ++ ++ if (update->lut3d_func && ++ stream->lut3d_func != update->lut3d_func) ++ stream->lut3d_func = update->lut3d_func; ++ + if (update->hdr_static_metadata) + stream->hdr_static_metadata = *update->hdr_static_metadata; + +-- +2.40.1 + + +From c44420194f73444b8cab5e33faadc5b5e2b1f770 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 20 Dec 2022 16:29:13 -0100 +Subject: [PATCH 35/59] drm/amd/display: copy 3D LUT settings from crtc state + to stream_update + +When commiting planes, we copy color mgmt resources to the stream state. +Do the same for shaper and 3D LUTs. + +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Joshua Ashton <joshua@froggi.es> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++ + 1 file changed, 4 insertions(+) + +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 6deec192ae04e..7936fcb05afcc 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -8260,6 +8260,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + &acrtc_state->stream->csc_color_matrix; + bundle->stream_update.out_transfer_func = + acrtc_state->stream->out_transfer_func; ++ bundle->stream_update.lut3d_func = ++ (struct dc_3dlut *) acrtc_state->stream->lut3d_func; ++ bundle->stream_update.func_shaper = ++ (struct dc_transfer_func *) acrtc_state->stream->func_shaper; + } + + acrtc_state->stream->abm_level = acrtc_state->abm_level; +-- +2.40.1 + + +From f886b44c68e1af7033ab8974eb73ab3d794b033f Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Wed, 15 Mar 2023 12:43:16 -0100 +Subject: [PATCH 36/59] drm/amd/display: allow BYPASS 3D LUT but keep shaper + LUT settings + +HW allows us to program shaper LUT without 3D LUT settings and it is +also good for testing shaper LUT behavior, therefore, DC driver should +allow acquiring both 3D and shaper LUT, but programing shaper LUT +without 3D LUT (not initialized). + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +index 32121db2851e6..fd2428871c8a9 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +@@ -113,7 +113,6 @@ static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, + } + + if (stream->lut3d_func && +- stream->lut3d_func->state.bits.initialized == 1 && + stream->lut3d_func->state.bits.rmu_idx_valid == 1) { + if (stream->lut3d_func->state.bits.rmu_mux_num == 0) + mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux; +@@ -131,8 +130,12 @@ static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, + if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num) + BREAK_TO_DEBUGGER(); + +- result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, +- stream->lut3d_func->state.bits.rmu_mux_num); ++ if (stream->lut3d_func->state.bits.initialized == 1) ++ result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, ++ stream->lut3d_func->state.bits.rmu_mux_num); ++ else ++ result = mpc->funcs->program_3dlut(mpc, NULL, ++ stream->lut3d_func->state.bits.rmu_mux_num); + result = mpc->funcs->program_shaper(mpc, shaper_lut, + stream->lut3d_func->state.bits.rmu_mux_num); + } else { +-- +2.40.1 + + +From 8fd6a7323d448430a14d8e61c12069dbebcc32e6 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 5 Dec 2022 15:01:48 -0100 +Subject: [PATCH 37/59] drm/amd/display: handle MPC 3D LUT resources for a + given context + +In the original dc_acquire_release_mpc_3dlut(), only current ctx is +considered, which doesn't fit the steps for atomic checking new ctx. +Therefore, create a function to handle 3D LUT resource for a given +context, so that we can check resources availability in atomic_check +time and handle failures properly. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 39 ++++++++++++++++++++++++ + drivers/gpu/drm/amd/display/dc/dc.h | 8 +++++ + 2 files changed, 47 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index da1689de5d68a..615d7c41f49bf 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -2123,6 +2123,45 @@ bool dc_acquire_release_mpc_3dlut( + return ret; + } + ++bool ++dc_acquire_release_mpc_3dlut_for_ctx(struct dc *dc, ++ bool acquire, ++ struct dc_state *state, ++ struct dc_stream_state *stream, ++ struct dc_3dlut **lut, ++ struct dc_transfer_func **shaper) ++{ ++ int pipe_idx; ++ bool ret = false; ++ bool found_pipe_idx = false; ++ const struct resource_pool *pool = dc->res_pool; ++ struct resource_context *res_ctx = &state->res_ctx; ++ int mpcc_id = 0; ++ ++ if (pool && res_ctx) { ++ if (acquire) { ++ /*find pipe idx for the given stream*/ ++ for (pipe_idx = 0; pipe_idx < pool->pipe_count; pipe_idx++) { ++ if (res_ctx->pipe_ctx[pipe_idx].stream == stream) { ++ found_pipe_idx = true; ++ mpcc_id = res_ctx->pipe_ctx[pipe_idx].plane_res.hubp->inst; ++ break; ++ } ++ } ++ } else ++ found_pipe_idx = true;/*for release pipe_idx is not required*/ ++ ++ if (found_pipe_idx) { ++ if (acquire && pool->funcs->acquire_post_bldn_3dlut) ++ ret = pool->funcs->acquire_post_bldn_3dlut(res_ctx, pool, mpcc_id, lut, shaper); ++ else if (!acquire && pool->funcs->release_post_bldn_3dlut) ++ ret = pool->funcs->release_post_bldn_3dlut(res_ctx, pool, lut, shaper); ++ } ++ } ++ return ret; ++} ++ ++ + static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context) + { + int i; +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 30f0ba05a6e6c..549ef605bb2b8 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -1348,6 +1348,14 @@ bool dc_acquire_release_mpc_3dlut( + struct dc_3dlut **lut, + struct dc_transfer_func **shaper); + ++bool ++dc_acquire_release_mpc_3dlut_for_ctx(struct dc *dc, ++ bool acquire, ++ struct dc_state *state, ++ struct dc_stream_state *stream, ++ struct dc_3dlut **lut, ++ struct dc_transfer_func **shaper); ++ + void dc_resource_state_copy_construct( + const struct dc_state *src_ctx, + struct dc_state *dst_ctx); +-- +2.40.1 + + +From b0b4bcea109bc5fcba96c9e7447bfe0247ab3c6b Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Tue, 14 Mar 2023 15:08:34 -0100 +Subject: [PATCH 38/59] drm/amd/display: dynamically acquire 3DLUT resources + for color changes + +dc_acquire_release_mpc_3dlut_for_ctx initializes the bits required to +program 3DLUT in DC MPC hw block, applied in set_output_transfer_func(). +Since acquire/release can fail, we should check resources availability +during atomic check considering the new context created. We dynamically +acquire 3D LUT resources when we actually use them, so we don't limit +ourselves with the stream count. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 55 ++++++++++++++++++- + .../amd/display/dc/dcn301/dcn301_resource.c | 26 ++++++++- + 4 files changed, 87 insertions(+), 4 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 7936fcb05afcc..97baaa674137b 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -9452,7 +9452,12 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, + */ + if (dm_new_crtc_state->base.color_mgmt_changed || + drm_atomic_crtc_needs_modeset(new_crtc_state)) { +- ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state); ++ if (!dm_state) { ++ ret = dm_atomic_get_state(state, &dm_state); ++ if (ret) ++ goto fail; ++ } ++ ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state, dm_state->context); + if (ret) + goto fail; + } +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index ac430a23d3e14..e5f9db5a43f47 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -875,7 +875,8 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); + + void amdgpu_dm_init_color_mod(void); + int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); +-int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); ++int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, ++ struct dc_state *ctx); + int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct dc_plane_state *dc_plane_state); + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index fe03f1ec326e7..161807e198869 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -364,6 +364,49 @@ static int __set_input_tf(struct dc_transfer_func *func, + return res ? 0 : -ENOMEM; + } + ++/* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC ++ * interface ++ * @dc: Display Core control structure ++ * @ctx: new DC state information ++ * @stream: DC stream state to set shaper LUT and 3D LUT ++ * @drm_shaper_lut: DRM CRTC (user) shaper LUT ++ * @drm_shaper_size: size of shaper LUT ++ * @drm_lut3d: DRM CRTC (user) 3D LUT ++ * @drm_lut3d_size: size of 3D LUT ++ * ++ * Returns: ++ * 0 on success. ++ */ ++static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc, ++ struct dc_state *ctx, ++ struct dc_stream_state *stream, ++ const struct drm_color_lut *drm_shaper_lut, ++ uint32_t drm_shaper_size, ++ const struct drm_color_lut *drm_lut3d, ++ uint32_t drm_lut3d_size) ++{ ++ struct dc_3dlut *lut3d_func; ++ struct dc_transfer_func *func_shaper; ++ bool acquire = drm_shaper_size || drm_lut3d_size; ++ ++ lut3d_func = (struct dc_3dlut *)stream->lut3d_func; ++ func_shaper = (struct dc_transfer_func *)stream->func_shaper; ++ ++ ASSERT((lut3d_func && func_shaper) || (!lut3d_func && !func_shaper)); ++ if ((acquire && !lut3d_func && !func_shaper) || ++ (!acquire && lut3d_func && func_shaper)) ++ { ++ if (!dc_acquire_release_mpc_3dlut_for_ctx(dc, acquire, ctx, stream, ++ &lut3d_func, &func_shaper)) ++ return DC_ERROR_UNEXPECTED; ++ } ++ ++ stream->func_shaper = func_shaper; ++ stream->lut3d_func = lut3d_func; ++ ++ return 0; ++} ++ + /** + * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes + * @crtc_state: the DRM CRTC state +@@ -403,6 +446,7 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state) + /** + * amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream. + * @crtc: amdgpu_dm crtc state ++ * @ctx: new DC state information + * + * With no plane level color management properties we're free to use any + * of the HW blocks as long as the CRTC CTM always comes before the +@@ -422,7 +466,8 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state) + * Returns: + * 0 on success. Error code if setup fails. + */ +-int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) ++int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, ++ struct dc_state *ctx) + { + struct dc_stream_state *stream = crtc->stream; + struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev); +@@ -481,6 +526,14 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) + if (r) + return r; + } else { ++ r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream, ++ NULL, 0, NULL, 0); ++ if (r) ++ return r; ++ /* Note: OGAM is disabled if 3D LUT is successfully programmed. ++ * See params and set_output_gamma in ++ * dcn30_set_output_transfer_func() ++ */ + regamma_size = has_regamma ? regamma_size : 0; + r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, + regamma_size, has_rom); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +index 5ac2a272c380f..a6d6fcaaca1c2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +@@ -1258,6 +1258,30 @@ static struct display_stream_compressor *dcn301_dsc_create( + return &dsc->base; + } + ++static enum dc_status ++dcn301_remove_stream_from_ctx(struct dc *dc, ++ struct dc_state *new_ctx, ++ struct dc_stream_state *dc_stream) ++{ ++ struct dc_3dlut *lut3d_func; ++ struct dc_transfer_func *func_shaper; ++ ++ lut3d_func = (struct dc_3dlut *)dc_stream->lut3d_func; ++ func_shaper = (struct dc_transfer_func *)dc_stream->func_shaper; ++ ++ ASSERT((lut3d_func && func_shaper) || (!lut3d_func && !func_shaper)); ++ if (lut3d_func && func_shaper) ++ { ++ if (!dc_acquire_release_mpc_3dlut_for_ctx(dc, false, new_ctx, dc_stream, ++ &lut3d_func, &func_shaper)) ++ return DC_ERROR_UNEXPECTED; ++ } ++ ++ dc_stream->lut3d_func = lut3d_func; ++ dc_stream->func_shaper = func_shaper; ++ ++ return dcn20_remove_stream_from_ctx(dc, new_ctx, dc_stream); ++} + + static void dcn301_destroy_resource_pool(struct resource_pool **pool) + { +@@ -1406,7 +1430,7 @@ static struct resource_funcs dcn301_res_pool_funcs = { + .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, +- .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, ++ .remove_stream_from_ctx = dcn301_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, +-- +2.40.1 + + +From 25d40859e077e977bd1a1661dc5cc1ec5c80028c Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 22 Aug 2022 22:02:09 -0100 +Subject: [PATCH 39/59] drm/amd/display: add CRTC 3D LUT support + +Wire up DC 3D LUT to DM CRTC color management (post-blending). On AMD +display HW, we have to set a shaper LUT to delinearize or normalize the +color space before applying a 3D LUT (since we have a reduced number of +LUT entries). Therefore, we map DC shaper LUT to DM CRTC color mgmt in +the next patch. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 + + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 17 ++ + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 158 +++++++++++++++++- + 3 files changed, 180 insertions(+), 1 deletion(-) + +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 97baaa674137b..513cf9c557f2e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -10018,6 +10018,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + goto fail; + } + ++ ret = amdgpu_dm_verify_lut3d_size(adev, new_crtc_state); ++ if (ret) { ++ drm_dbg_driver(dev, "amdgpu_dm_verify_lut_sizes() failed\n"); ++ goto fail; ++ } ++ + if (!new_crtc_state->enable) + continue; + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index e5f9db5a43f47..eebe12c353ad8 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -797,6 +797,21 @@ struct dm_crtc_state { + + int abm_level; + ++ /* AMD driver-private CRTC color management ++ * ++ * DRM provides CRTC degamma/ctm/gamma color mgmt features, but AMD HW ++ * has a larger set of post-blending color calibration. Here, DC MPC ++ * color caps are wired up to DM CRTC state: ++ */ ++ /** ++ * @lut3d: ++ * ++ * Post-blending 3D Lookup table for converting pixel data. When ++ * supported by HW (DCN 3+), it is positioned just before post-blending ++ * regamma and always assumes a preceding shaper LUT. The blob (if not ++ * NULL) is an array of &struct drm_color_lut. ++ */ ++ struct drm_property_blob *lut3d; + /** + * @regamma_tf: + * +@@ -868,6 +883,8 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); + /* 3D LUT max size is 17x17x17 */ + #define MAX_COLOR_3DLUT_ENTRIES 4913 + #define MAX_COLOR_3DLUT_BITDEPTH 12 ++int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, ++ const struct drm_crtc_state *crtc_state); + /* 1D LUT size */ + #define MAX_COLOR_LUT_ENTRIES 4096 + /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 161807e198869..cef8d0d7f37b5 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -364,6 +364,96 @@ static int __set_input_tf(struct dc_transfer_func *func, + return res ? 0 : -ENOMEM; + } + ++static void __to_dc_lut3d_color(struct dc_rgb *rgb, ++ const struct drm_color_lut lut, ++ int bit_precision) ++{ ++ rgb->red = drm_color_lut_extract(lut.red, bit_precision); ++ rgb->green = drm_color_lut_extract(lut.green, bit_precision); ++ rgb->blue = drm_color_lut_extract(lut.blue, bit_precision); ++} ++ ++static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut, ++ uint32_t lut3d_size, ++ struct tetrahedral_params *params, ++ bool use_tetrahedral_9, ++ int bit_depth) ++{ ++ struct dc_rgb *lut0; ++ struct dc_rgb *lut1; ++ struct dc_rgb *lut2; ++ struct dc_rgb *lut3; ++ int lut_i, i; ++ ++ ++ if (use_tetrahedral_9) { ++ lut0 = params->tetrahedral_9.lut0; ++ lut1 = params->tetrahedral_9.lut1; ++ lut2 = params->tetrahedral_9.lut2; ++ lut3 = params->tetrahedral_9.lut3; ++ } else { ++ lut0 = params->tetrahedral_17.lut0; ++ lut1 = params->tetrahedral_17.lut1; ++ lut2 = params->tetrahedral_17.lut2; ++ lut3 = params->tetrahedral_17.lut3; ++ } ++ ++ for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) { ++ /* We should consider the 3dlut RGB values are distributed ++ * along four arrays lut0-3 where the first sizes 1229 and the ++ * other 1228. The bit depth supported for 3dlut channel is ++ * 12-bit, but DC also supports 10-bit. ++ * ++ * TODO: improve color pipeline API to enable the userspace set ++ * bit depth and 3D LUT size/stride, as specified by VA-API. ++ */ ++ __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth); ++ __to_dc_lut3d_color(&lut1[lut_i], lut[i + 1], bit_depth); ++ __to_dc_lut3d_color(&lut2[lut_i], lut[i + 2], bit_depth); ++ __to_dc_lut3d_color(&lut3[lut_i], lut[i + 3], bit_depth); ++ } ++ /* lut0 has 1229 points (lut_size/4 + 1) */ ++ __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth); ++} ++ ++/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream ++ * @drm_lut3d: DRM CRTC (user) 3D LUT ++ * @drm_lut3d_size: size of 3D LUT ++ * @lut3d: DC 3D LUT ++ * ++ * Map DRM CRTC 3D LUT to DC 3D LUT and all necessary bits to program it ++ * on DCN MPC accordingly. ++ */ ++static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut, ++ uint32_t drm_lut3d_size, ++ struct dc_3dlut *lut) ++{ ++ if (!drm_lut3d_size) { ++ lut->state.bits.initialized = 0; ++ } else { ++ /* Stride and bit depth are not programmable by API yet. ++ * Therefore, only supports 17x17x17 3D LUT (12-bit). ++ */ ++ lut->lut_3d.use_tetrahedral_9 = false; ++ lut->lut_3d.use_12bits = true; ++ lut->state.bits.initialized = 1; ++ __drm_3dlut_to_dc_3dlut(drm_lut, drm_lut3d_size, &lut->lut_3d, ++ lut->lut_3d.use_tetrahedral_9, ++ MAX_COLOR_3DLUT_BITDEPTH); ++ } ++} ++ ++static int amdgpu_dm_atomic_shaper_lut(struct dc_transfer_func *func_shaper) ++{ ++ /* We don't get DRM shaper LUT yet. We assume the input color space is already ++ * delinearized, so we don't need a shaper LUT and we can just BYPASS ++ */ ++ func_shaper->type = TF_TYPE_BYPASS; ++ func_shaper->tf = TRANSFER_FUNCTION_LINEAR; ++ ++ return 0; ++} ++ + /* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC + * interface + * @dc: Display Core control structure +@@ -404,6 +494,57 @@ static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc, + stream->func_shaper = func_shaper; + stream->lut3d_func = lut3d_func; + ++ if (!acquire) ++ return 0; ++ ++ amdgpu_dm_atomic_lut3d(drm_lut3d, drm_lut3d_size, lut3d_func); ++ ++ return amdgpu_dm_atomic_shaper_lut(func_shaper); ++} ++ ++/** ++ * amdgpu_dm_lut3d_size - get expected size according to hw color caps ++ * @adev: amdgpu device ++ * @lut_size: default size ++ * ++ * Return: ++ * lut_size if DC 3D LUT is supported, zero otherwise. ++ */ ++static uint32_t amdgpu_dm_get_lut3d_size(struct amdgpu_device *adev, ++ uint32_t lut_size) ++{ ++ return adev->dm.dc->caps.color.mpc.num_3dluts ? lut_size : 0; ++} ++ ++/** ++ * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if DRM 3D ++ * LUT matches the hw supported size ++ * @adev: amdgpu device ++ * @crtc_state: the DRM CRTC state ++ * ++ * Verifies if post-blending (MPC) 3D LUT is supported by the HW (DCN 3.0 or ++ * newer) and if the DRM 3D LUT matches the supported size. ++ * ++ * Returns: ++ * 0 on success. -EINVAL if lut size are invalid. ++ */ ++int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, ++ const struct drm_crtc_state *crtc_state) ++{ ++ const struct drm_color_lut *lut3d = NULL; ++ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc_state); ++ uint32_t exp_size, size; ++ ++ exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES); ++ ++ lut3d = __extract_blob_lut(acrtc_state->lut3d, &size); ++ ++ if (lut3d && size != exp_size) { ++ drm_dbg(&adev->ddev, "Invalid 3D LUT size. Should be %u but got %u.\n", ++ exp_size, size); ++ return -EINVAL; ++ } ++ + return 0; + } + +@@ -478,6 +619,14 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + bool has_regamma, has_degamma; + bool is_legacy; + int r; ++ const struct drm_color_lut *lut3d; ++ uint32_t lut3d_size; ++ ++ r = amdgpu_dm_verify_lut3d_size(adev, &crtc->base); ++ if (r) ++ return r; ++ ++ lut3d = __extract_blob_lut(crtc->lut3d, &lut3d_size); + + r = amdgpu_dm_verify_lut_sizes(&crtc->base); + if (r) +@@ -526,10 +675,17 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + if (r) + return r; + } else { ++ /* We are not exposing CRTC 3D LUT properties yet, so DC 3D LUT ++ * programming is expected to be set to bypass mode, since ++ * there is no user-blob. ++ */ ++ lut3d_size = lut3d != NULL ? lut3d_size : 0; + r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream, +- NULL, 0, NULL, 0); ++ NULL, 0, ++ lut3d, lut3d_size); + if (r) + return r; ++ + /* Note: OGAM is disabled if 3D LUT is successfully programmed. + * See params and set_output_gamma in + * dcn30_set_output_transfer_func() +-- +2.40.1 + + +From e846b1078ce3980fd36c7eeda5a87c4e1cf66c68 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 22 Aug 2022 22:08:18 -0100 +Subject: [PATCH 40/59] drm/amd/display: add CRTC shaper LUT support + +Map DC shaper LUT to DM CRTC color management. Shaper LUT can be used to +delinearize and/or normalize the color space for computational +efficiency and achiving specific visual styles. Blending usually occurs +in linear space and if a CRTC degamma 1D LUT is set to linearize the +color space, a custom shaper 1D LUT can be used just before applying 3D +LUT. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 +++ + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 54 ++++++++++++++----- + 2 files changed, 47 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index eebe12c353ad8..ea76c29578483 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -803,6 +803,13 @@ struct dm_crtc_state { + * has a larger set of post-blending color calibration. Here, DC MPC + * color caps are wired up to DM CRTC state: + */ ++ /** ++ * @shaper_lut: ++ * ++ * Post-blending 1D Lookup table used to de-linearize pixel data for 3D ++ * LUT. The blob (if not NULL) is an array of &struct drm_color_lut. ++ */ ++ struct drm_property_blob *shaper_lut; + /** + * @lut3d: + * +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index cef8d0d7f37b5..934636d7b8d3f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -443,15 +443,26 @@ static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut, + } + } + +-static int amdgpu_dm_atomic_shaper_lut(struct dc_transfer_func *func_shaper) ++static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, ++ uint32_t shaper_size, ++ struct dc_transfer_func *func_shaper) + { +- /* We don't get DRM shaper LUT yet. We assume the input color space is already +- * delinearized, so we don't need a shaper LUT and we can just BYPASS +- */ +- func_shaper->type = TF_TYPE_BYPASS; +- func_shaper->tf = TRANSFER_FUNCTION_LINEAR; ++ int ret = 0; + +- return 0; ++ if (shaper_size) { ++ /* If DRM shaper LUT is set, we assume a linear color space ++ * (linearized by DRM degamma 1D LUT or not) ++ */ ++ func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS; ++ func_shaper->tf = TRANSFER_FUNCTION_LINEAR; ++ ++ ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, false); ++ } else { ++ func_shaper->type = TF_TYPE_BYPASS; ++ func_shaper->tf = TRANSFER_FUNCTION_LINEAR; ++ } ++ ++ return ret; + } + + /* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC +@@ -499,7 +510,8 @@ static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc, + + amdgpu_dm_atomic_lut3d(drm_lut3d, drm_lut3d_size, lut3d_func); + +- return amdgpu_dm_atomic_shaper_lut(func_shaper); ++ return amdgpu_dm_atomic_shaper_lut(drm_shaper_lut, ++ drm_shaper_size, func_shaper); + } + + /** +@@ -531,12 +543,22 @@ static uint32_t amdgpu_dm_get_lut3d_size(struct amdgpu_device *adev, + int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, + const struct drm_crtc_state *crtc_state) + { +- const struct drm_color_lut *lut3d = NULL; + struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc_state); ++ const struct drm_color_lut *shaper = NULL, *lut3d = NULL; + uint32_t exp_size, size; + +- exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES); ++ /* shaper LUT is only available if 3D LUT color caps*/ ++ exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_LUT_ENTRIES); ++ shaper = __extract_blob_lut(acrtc_state->shaper_lut, &size); ++ ++ if (shaper && size != exp_size) { ++ drm_dbg(&adev->ddev, ++ "Invalid Shaper LUT size. Should be %u but got %u.\n", ++ exp_size, size); ++ return -EINVAL; ++ } + ++ exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES); + lut3d = __extract_blob_lut(acrtc_state->lut3d, &size); + + if (lut3d && size != exp_size) { +@@ -618,15 +640,16 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + uint32_t degamma_size, regamma_size; + bool has_regamma, has_degamma; + bool is_legacy; ++ const struct drm_color_lut *shaper_lut, *lut3d; ++ uint32_t shaper_size, lut3d_size; + int r; +- const struct drm_color_lut *lut3d; +- uint32_t lut3d_size; + + r = amdgpu_dm_verify_lut3d_size(adev, &crtc->base); + if (r) + return r; + + lut3d = __extract_blob_lut(crtc->lut3d, &lut3d_size); ++ shaper_lut = __extract_blob_lut(crtc->shaper_lut, &shaper_size); + + r = amdgpu_dm_verify_lut_sizes(&crtc->base); + if (r) +@@ -680,11 +703,14 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + * there is no user-blob. + */ + lut3d_size = lut3d != NULL ? lut3d_size : 0; ++ shaper_size = shaper_lut != NULL ? shaper_size : 0; + r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream, +- NULL, 0, ++ shaper_lut, shaper_size, + lut3d, lut3d_size); +- if (r) ++ if (r) { ++ drm_dbg(&adev->ddev, "Failed on shaper/3D LUTs setup\n"); + return r; ++ } + + /* Note: OGAM is disabled if 3D LUT is successfully programmed. + * See params and set_output_gamma in +-- +2.40.1 + + +From feecbdff070930ca09d3de7a08ee6b908b800720 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Wed, 12 Apr 2023 22:17:56 -0100 +Subject: [PATCH 41/59] drm/amd/display: add CRTC regamma TF support + +Add predefined transfer function programming. There is no out gamma ROM, +but we can use AMD color modules to program LUT parameters from a +predefined TF and an empty regamma LUT (or bump up LUT parameters with +predefined TF setup). + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 58 ++++++++++++++----- + 1 file changed, 42 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 934636d7b8d3f..146363363ef07 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -268,16 +268,18 @@ static int __set_output_tf(struct dc_transfer_func *func, + struct calculate_buffer cal_buffer = {0}; + bool res; + +- ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); +- + cal_buffer.buffer_index = -1; + +- gamma = dc_create_gamma(); +- if (!gamma) +- return -ENOMEM; ++ if (lut_size) { ++ ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); + +- gamma->num_entries = lut_size; +- __drm_lut_to_dc_gamma(lut, gamma, false); ++ gamma = dc_create_gamma(); ++ if (!gamma) ++ return -ENOMEM; ++ ++ gamma->num_entries = lut_size; ++ __drm_lut_to_dc_gamma(lut, gamma, false); ++ } + + if (func->tf == TRANSFER_FUNCTION_LINEAR) { + /* +@@ -285,32 +287,36 @@ static int __set_output_tf(struct dc_transfer_func *func, + * on top of a linear input. But degamma params can be used + * instead to simulate this. + */ +- gamma->type = GAMMA_CUSTOM; ++ if (gamma) ++ gamma->type = GAMMA_CUSTOM; + res = mod_color_calculate_degamma_params(NULL, func, +- gamma, true); ++ gamma, gamma != NULL); + } else { + /* + * Assume sRGB. The actual mapping will depend on whether the + * input was legacy or not. + */ +- gamma->type = GAMMA_CS_TFM_1D; +- res = mod_color_calculate_regamma_params(func, gamma, false, ++ if (gamma) ++ gamma->type = GAMMA_CS_TFM_1D; ++ res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL, + has_rom, NULL, &cal_buffer); + } + +- dc_gamma_release(&gamma); ++ if (gamma) ++ dc_gamma_release(&gamma); + + return res ? 0 : -ENOMEM; + } + + static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + const struct drm_color_lut *regamma_lut, +- uint32_t regamma_size, bool has_rom) ++ uint32_t regamma_size, bool has_rom, ++ enum dc_transfer_func_predefined tf) + { + struct dc_transfer_func *out_tf = stream->out_transfer_func; + int ret = 0; + +- if (regamma_size) { ++ if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* CRTC RGM goes into RGM LUT. + * + * Note: there is no implicit sRGB regamma here. We are using +@@ -318,7 +324,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + * from a linear base. + */ + out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; +- out_tf->tf = TRANSFER_FUNCTION_LINEAR; ++ out_tf->tf = tf; + + ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); + } else { +@@ -364,6 +370,24 @@ static int __set_input_tf(struct dc_transfer_func *func, + return res ? 0 : -ENOMEM; + } + ++static enum dc_transfer_func_predefined drm_tf_to_dc_tf(enum drm_transfer_function drm_tf) ++{ ++ switch (drm_tf) ++ { ++ default: ++ case DRM_TRANSFER_FUNCTION_DEFAULT: return TRANSFER_FUNCTION_LINEAR; ++ case DRM_TRANSFER_FUNCTION_SRGB: return TRANSFER_FUNCTION_SRGB; ++ case DRM_TRANSFER_FUNCTION_BT709: return TRANSFER_FUNCTION_BT709; ++ case DRM_TRANSFER_FUNCTION_PQ: return TRANSFER_FUNCTION_PQ; ++ case DRM_TRANSFER_FUNCTION_LINEAR: return TRANSFER_FUNCTION_LINEAR; ++ case DRM_TRANSFER_FUNCTION_UNITY: return TRANSFER_FUNCTION_UNITY; ++ case DRM_TRANSFER_FUNCTION_HLG: return TRANSFER_FUNCTION_HLG; ++ case DRM_TRANSFER_FUNCTION_GAMMA22: return TRANSFER_FUNCTION_GAMMA22; ++ case DRM_TRANSFER_FUNCTION_GAMMA24: return TRANSFER_FUNCTION_GAMMA24; ++ case DRM_TRANSFER_FUNCTION_GAMMA26: return TRANSFER_FUNCTION_GAMMA26; ++ } ++} ++ + static void __to_dc_lut3d_color(struct dc_rgb *rgb, + const struct drm_color_lut lut, + int bit_precision) +@@ -639,6 +663,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + const struct drm_color_lut *degamma_lut, *regamma_lut; + uint32_t degamma_size, regamma_size; + bool has_regamma, has_degamma; ++ enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR; + bool is_legacy; + const struct drm_color_lut *shaper_lut, *lut3d; + uint32_t shaper_size, lut3d_size; +@@ -650,6 +675,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + + lut3d = __extract_blob_lut(crtc->lut3d, &lut3d_size); + shaper_lut = __extract_blob_lut(crtc->shaper_lut, &shaper_size); ++ tf = drm_tf_to_dc_tf(crtc->regamma_tf); + + r = amdgpu_dm_verify_lut_sizes(&crtc->base); + if (r) +@@ -718,7 +744,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + */ + regamma_size = has_regamma ? regamma_size : 0; + r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, +- regamma_size, has_rom); ++ regamma_size, has_rom, tf); + if (r) + return r; + } +-- +2.40.1 + + +From 9162f97abaee9f28c92cb1d14969c6072c9290d6 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 16 Mar 2023 14:14:39 +0000 +Subject: [PATCH 42/59] drm/amd/display: set sdr_ref_white_level to 80 for + out_transfer_func + +Otherwise this is just initialized to 0. This needs to actually have a +value so that compute_curve can work for PQ EOTF. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 146363363ef07..7cf35ac3fad38 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -72,6 +72,7 @@ + */ + + #define MAX_DRM_LUT_VALUE 0xFFFF ++#define SDR_WHITE_LEVEL_INIT_VALUE 80 + + /** + * amdgpu_dm_init_color_mod - Initialize the color module. +@@ -325,6 +326,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + */ + out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + out_tf->tf = tf; ++ out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + + ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); + } else { +-- +2.40.1 + + +From 05e9422ea6732679681826c9a0030f9400647148 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Wed, 12 Apr 2023 22:01:43 -0100 +Subject: [PATCH 43/59] drm/amd/display: add CRTC shaper TF support + +Inspired by regamma TF, follow similar steps to add TF + 1D LUT for +shaper func. Reuse regamma_tf property, since the driver doesn't support +shaper and out gamma at the same time. Only set shaper TF if setting +shaper LUT or 3D LUT. We could rename regamma_tf - if necessary to avoid +misunderstandings - or add a specific property for shaper TF when. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 7cf35ac3fad38..5650b85cc28ec 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -470,19 +470,22 @@ static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut, + } + + static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, ++ bool has_rom, ++ enum dc_transfer_func_predefined tf, + uint32_t shaper_size, + struct dc_transfer_func *func_shaper) + { + int ret = 0; + +- if (shaper_size) { ++ if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* If DRM shaper LUT is set, we assume a linear color space + * (linearized by DRM degamma 1D LUT or not) + */ + func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS; +- func_shaper->tf = TRANSFER_FUNCTION_LINEAR; ++ func_shaper->tf = tf; ++ func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + +- ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, false); ++ ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom); + } else { + func_shaper->type = TF_TYPE_BYPASS; + func_shaper->tf = TRANSFER_FUNCTION_LINEAR; +@@ -509,6 +512,8 @@ static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc, + struct dc_stream_state *stream, + const struct drm_color_lut *drm_shaper_lut, + uint32_t drm_shaper_size, ++ bool has_rom, ++ enum dc_transfer_func_predefined tf, + const struct drm_color_lut *drm_lut3d, + uint32_t drm_lut3d_size) + { +@@ -536,7 +541,7 @@ static int amdgpu_dm_atomic_shaper_lut3d(struct dc *dc, + + amdgpu_dm_atomic_lut3d(drm_lut3d, drm_lut3d_size, lut3d_func); + +- return amdgpu_dm_atomic_shaper_lut(drm_shaper_lut, ++ return amdgpu_dm_atomic_shaper_lut(drm_shaper_lut, has_rom, tf, + drm_shaper_size, func_shaper); + } + +@@ -734,6 +739,7 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + shaper_size = shaper_lut != NULL ? shaper_size : 0; + r = amdgpu_dm_atomic_shaper_lut3d(adev->dm.dc, ctx, stream, + shaper_lut, shaper_size, ++ has_rom, tf, + lut3d, lut3d_size); + if (r) { + drm_dbg(&adev->ddev, "Failed on shaper/3D LUTs setup\n"); +-- +2.40.1 + + +From 02b87d4ea9cdb6c55bdb2b66e57b6abb3ce03b7a Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Fri, 14 Apr 2023 22:19:49 -0100 +Subject: [PATCH 44/59] drm/amd/display: mark plane as needing reset if plane + color mgmt changes + +We took a similar path for CRTC color mgmt changes, since we remap CRTC +degamma to plane/DPP block. Here we can use the status of +`plane->color_mgmt_changed` to detect when a plane color property +changed and recreate the plane accordingly. + +Co-developed-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++ + 1 file changed, 3 insertions(+) + +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 513cf9c557f2e..0f3a10bcddc04 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -9513,6 +9513,9 @@ static bool should_reset_plane(struct drm_atomic_state *state, + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) + return true; + ++ if (new_plane_state->color_mgmt_changed) ++ return true; ++ + /* + * If there are any new primary or overlay planes being added or + * removed then the z-order can potentially change. To ensure +-- +2.40.1 + + +From d95ad19cbf7713eaac40f04676be1d2b5b6456e6 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Fri, 14 Apr 2023 16:06:42 -0100 +Subject: [PATCH 45/59] drm/amd/display: decouple steps for mapping CRTC + degamma to DC plane + +The next patch adds pre-blending degamma to AMD color mgmt pipeline, but +pre-blending degamma caps (DPP) is currently in use to provide DRM CRTC +atomic degamma or implict degamma on legacy gamma. Detach degamma usage +regarging CRTC color properties to manage plane and CRTC color +correction combinations. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 59 +++++++++++++------ + 1 file changed, 41 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 5650b85cc28ec..246f12532c48f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -790,20 +790,9 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + return 0; + } + +-/** +- * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. +- * @crtc: amdgpu_dm crtc state +- * @dc_plane_state: target DC surface +- * +- * Update the underlying dc_stream_state's input transfer function (ITF) in +- * preparation for hardware commit. The transfer function used depends on +- * the preparation done on the stream for color management. +- * +- * Returns: +- * 0 on success. -ENOMEM if mem allocation fails. +- */ +-int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, +- struct dc_plane_state *dc_plane_state) ++static int ++map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, ++ struct dc_plane_state *dc_plane_state) + { + const struct drm_color_lut *degamma_lut; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; +@@ -826,8 +815,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + °amma_size); + ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); + +- dc_plane_state->in_transfer_func->type = +- TF_TYPE_DISTRIBUTED_POINTS; ++ dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + + /* + * This case isn't fully correct, but also fairly +@@ -863,7 +851,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + degamma_lut, degamma_size); + if (r) + return r; +- } else if (crtc->cm_is_degamma_srgb) { ++ } else { + /* + * For legacy gamma support we need the regamma input + * in linear space. Assume that the input is sRGB. +@@ -873,8 +861,43 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + + if (tf != TRANSFER_FUNCTION_SRGB && + !mod_color_calculate_degamma_params(NULL, +- dc_plane_state->in_transfer_func, NULL, false)) ++ dc_plane_state->in_transfer_func, ++ NULL, false)) + return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/** ++ * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. ++ * @crtc: amdgpu_dm crtc state ++ * @dc_plane_state: target DC surface ++ * ++ * Update the underlying dc_stream_state's input transfer function (ITF) in ++ * preparation for hardware commit. The transfer function used depends on ++ * the preparation done on the stream for color management. ++ * ++ * Returns: ++ * 0 on success. -ENOMEM if mem allocation fails. ++ */ ++int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, ++ struct dc_plane_state *dc_plane_state) ++{ ++ bool has_crtc_cm_degamma; ++ int ret; ++ ++ has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); ++ if (has_crtc_cm_degamma){ ++ /* AMD HW doesn't have post-blending degamma caps. When DRM ++ * CRTC atomic degamma is set, we maps it to DPP degamma block ++ * (pre-blending) or, on legacy gamma, we use DPP degamma to ++ * linearize (implicit degamma) from sRGB/BT709 according to ++ * the input space. ++ */ ++ ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state); ++ if (ret) ++ return ret; + } else { + /* ...Otherwise we can just bypass the DGM block. */ + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; +-- +2.40.1 + + +From f33acbd896a1d9379c1eba8d9eec2a4da973d5f6 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Wed, 12 Apr 2023 10:04:27 -0100 +Subject: [PATCH 46/59] drm/amd/display: add support for plane degamma TF and + LUT properties + +Set DC plane with user degamma LUT or predefined TF from driver-specific +plane color properties. If plane and CRTC degamma are set in the same +time, plane degamma has priority. That means, we only set CRTC degamma +if we don't have plane degamma LUT or TF to configure. We return -EINVAL +if we don't have plane degamma settings, so we can continue and check +CRTC degamma. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 70 +++++++++++++++++-- + 3 files changed, 69 insertions(+), 6 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 0f3a10bcddc04..c7f98503a750e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -5045,7 +5045,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, + * Always set input transfer function, since plane state is refreshed + * every time. + */ +- ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state); ++ ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, ++ plane_state, ++ dc_plane_state); + if (ret) + return ret; + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index ea76c29578483..bf4a1d6be99e6 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -902,6 +902,7 @@ int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); + int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + struct dc_state *ctx); + int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, ++ struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state); + + void amdgpu_dm_update_connector_after_detect( +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 246f12532c48f..89178b7f636f1 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -869,9 +869,58 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + return 0; + } + ++static int ++__set_dm_plane_degamma(struct drm_plane_state *plane_state, ++ struct dc_plane_state *dc_plane_state) ++{ ++ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); ++ const struct drm_color_lut *degamma_lut; ++ enum drm_transfer_function drm_tf = DRM_TRANSFER_FUNCTION_DEFAULT; ++ uint32_t degamma_size; ++ bool has_degamma_lut; ++ int ret; ++ ++ degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut, ++ °amma_size); ++ ++ has_degamma_lut = degamma_lut && ++ !__is_lut_linear(degamma_lut, degamma_size); ++ ++ drm_tf = dm_plane_state->degamma_tf; ++ ++ /* If we don't have plane degamma LUT nor TF to set on DC, we have ++ * nothing to do here, return. ++ */ ++ if (!has_degamma_lut && drm_tf == DRM_TRANSFER_FUNCTION_DEFAULT) ++ return -EINVAL; ++ ++ dc_plane_state->in_transfer_func->tf = drm_tf_to_dc_tf(drm_tf); ++ ++ if (has_degamma_lut) { ++ ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); ++ ++ dc_plane_state->in_transfer_func->type = ++ TF_TYPE_DISTRIBUTED_POINTS; ++ ++ ret = __set_input_tf(dc_plane_state->in_transfer_func, ++ degamma_lut, degamma_size); ++ if (ret) ++ return ret; ++ } else { ++ dc_plane_state->in_transfer_func->type = ++ TF_TYPE_PREDEFINED; ++ ++ if (!mod_color_calculate_degamma_params(NULL, ++ dc_plane_state->in_transfer_func, NULL, false)) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ + /** + * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. + * @crtc: amdgpu_dm crtc state ++ * @plane_state: DRM plane state + * @dc_plane_state: target DC surface + * + * Update the underlying dc_stream_state's input transfer function (ITF) in +@@ -882,13 +931,28 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + * 0 on success. -ENOMEM if mem allocation fails. + */ + int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, ++ struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) + { + bool has_crtc_cm_degamma; + int ret; + ++ /* Initially, we can just bypass the DGM block. */ ++ dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; ++ dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; ++ ++ /* After, we start to update values according to color props */ + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); +- if (has_crtc_cm_degamma){ ++ ++ ret = __set_dm_plane_degamma(plane_state, dc_plane_state); ++ if (ret != -EINVAL) ++ return ret; ++ ++ /* If we are here, it means we don't have plane degamma settings, check ++ * if we have CRTC degamma waiting for mapping to pre-blending degamma ++ * block ++ */ ++ if (has_crtc_cm_degamma) { + /* AMD HW doesn't have post-blending degamma caps. When DRM + * CRTC atomic degamma is set, we maps it to DPP degamma block + * (pre-blending) or, on legacy gamma, we use DPP degamma to +@@ -898,10 +962,6 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state); + if (ret) + return ret; +- } else { +- /* ...Otherwise we can just bypass the DGM block. */ +- dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; +- dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + } + + return 0; +-- +2.40.1 + + +From ac4146a88212a242e8fea0b01bf14333ccd41033 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Fri, 14 Apr 2023 16:50:34 -0100 +Subject: [PATCH 47/59] drm/amd/display: reject atomic commit if setting both + plane and CRTC degamma + +DC only has pre-blending degamma caps (plane/DPP) that is currently in +use for CRTC/post-blending degamma, so that we don't have HW caps to +perform plane and CRTC degamma at the same time. Reject atomic updates +when serspace sets both plane and CRTC degamma properties. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 89178b7f636f1..8452519cabe8b 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -945,9 +945,20 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + + ret = __set_dm_plane_degamma(plane_state, dc_plane_state); +- if (ret != -EINVAL) ++ if (ret == -ENOMEM) + return ret; + ++ /* We only have one degamma block available (pre-blending) for the ++ * whole color correction pipeline, so that we can't actually perform ++ * plane and CRTC degamma at the same time. Explicitly reject atomic ++ * updates when userspace sets both plane and CRTC degamma properties. ++ */ ++ if (has_crtc_cm_degamma && ret != -EINVAL){ ++ drm_dbg_kms(crtc->base.crtc->dev, ++ "doesn't support plane and CRTC degamma at the same time\n"); ++ return -EINVAL; ++ } ++ + /* If we are here, it means we don't have plane degamma settings, check + * if we have CRTC degamma waiting for mapping to pre-blending degamma + * block +-- +2.40.1 + + +From f5943c06d541016a2f8e3c7764eca33ca1e6f9f7 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 16 Mar 2023 12:00:59 +0000 +Subject: [PATCH 48/59] drm/amd/display: add dc_fixpt_from_s3132 helper + +Detach value translation from CTM to reuse it for programming HDR +multiplier property. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 8 +------- + drivers/gpu/drm/amd/display/include/fixed31_32.h | 12 ++++++++++++ + 2 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 8452519cabe8b..629ba10fbee93 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -183,7 +183,6 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut, + static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, + struct fixed31_32 *matrix) + { +- int64_t val; + int i; + + /* +@@ -202,12 +201,7 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, + } + + /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ +- val = ctm->matrix[i - (i / 4)]; +- /* If negative, convert to 2's complement. */ +- if (val & (1ULL << 63)) +- val = -(val & ~(1ULL << 63)); +- +- matrix[i].value = val; ++ matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i - (i / 4)]); + } + } + +diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h +index ece97ae0e826c..f4cc7f97329fc 100644 +--- a/drivers/gpu/drm/amd/display/include/fixed31_32.h ++++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h +@@ -69,6 +69,18 @@ static const struct fixed31_32 dc_fixpt_epsilon = { 1LL }; + static const struct fixed31_32 dc_fixpt_half = { 0x80000000LL }; + static const struct fixed31_32 dc_fixpt_one = { 0x100000000LL }; + ++static inline struct fixed31_32 dc_fixpt_from_s3132(__u64 x) ++{ ++ struct fixed31_32 val; ++ ++ /* If negative, convert to 2's complement. */ ++ if (x & (1ULL << 63)) ++ x = -(x & ~(1ULL << 63)); ++ ++ val.value = x; ++ return val; ++} ++ + /* + * @brief + * Initialization routines +-- +2.40.1 + + +From 00da10be582bf8bc9295653aefb7c9ae5055ef8a Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Wed, 12 Apr 2023 21:42:51 -0100 +Subject: [PATCH 49/59] drm/adm/display: add HDR multiplier support + +With `dc_fixpt_from_s3132()` translation, we can just use it to set +hdr_mult. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 3 +++ + 2 files changed, 4 insertions(+) + +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 c7f98503a750e..4530ce1d06ef8 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -8061,6 +8061,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction; + bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; + bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; ++ bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; + } + + amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 629ba10fbee93..57d6aab762954 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -928,6 +928,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) + { ++ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + bool has_crtc_cm_degamma; + int ret; + +@@ -938,6 +939,8 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + /* After, we start to update values according to color props */ + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + ++ dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult); ++ + ret = __set_dm_plane_degamma(plane_state, dc_plane_state); + if (ret == -ENOMEM) + return ret; +-- +2.40.1 + + +From f7ff5f0bf1c46bcde2b0af3f0c203803c1178ced Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Mon, 22 May 2023 15:31:31 -0100 +Subject: [PATCH 50/59] drm/amd/display: program DPP shaper and 3D LUT if + updated + +If shaper and 3D LUT data updates, lut_3d bit in update_flag is updated +and we need to call set_input_transfer_func to program DPP shaper and 3D +LUTs. Small cleanup of code style in the related if-condition. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +index 5403e9399a465..b39880d26c6df 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +@@ -1755,8 +1755,9 @@ static void dcn20_program_pipe( + hws->funcs.set_hdr_multiplier(pipe_ctx); + + if (pipe_ctx->update_flags.bits.enable || +- pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || +- pipe_ctx->plane_state->update_flags.bits.gamma_change) ++ pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || ++ pipe_ctx->plane_state->update_flags.bits.gamma_change || ++ pipe_ctx->plane_state->update_flags.bits.lut_3d) + hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish +-- +2.40.1 + + +From 5bf24f48ca55fb1470d752b5cb9b758b520441fb Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Wed, 22 Mar 2023 18:37:12 -0100 +Subject: [PATCH 51/59] drm/amd/display: add plane shaper/3D LUT and shaper TF + support + +We already have the steps to program post-blending shaper/3D LUT on AMD +display driver, but unlike MPC 3D LUT, we don't need to acquire/release +DPP 3D LUT. We can reuse programming steps to map plane properties to +DC plane for pre-blending (plane) shaper/3D LUT setup. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 ++ + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 35 ++++++++++++++++--- + 2 files changed, 33 insertions(+), 4 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 4530ce1d06ef8..9a9c3cbf77693 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -8062,6 +8062,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; + bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; + bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; ++ bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; ++ bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func; + } + + amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 57d6aab762954..b075c9f6e7179 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -911,6 +911,35 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, + return 0; + } + ++static int ++amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, ++ struct dc_plane_state *dc_plane_state) ++{ ++ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); ++ enum drm_transfer_function shaper_tf = DRM_TRANSFER_FUNCTION_DEFAULT; ++ const struct drm_color_lut *shaper_lut, *lut3d; ++ uint32_t lut3d_size, shaper_size; ++ ++ /* We have nothing to do here, return */ ++ if (!plane_state->color_mgmt_changed) ++ return 0; ++ ++ dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult); ++ ++ shaper_tf = dm_plane_state->shaper_tf; ++ shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, &shaper_size); ++ lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size); ++ lut3d_size = lut3d != NULL ? lut3d_size : 0; ++ shaper_size = shaper_lut != NULL ? shaper_size : 0; ++ ++ amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, dc_plane_state->lut3d_func); ++ ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false, ++ drm_tf_to_dc_tf(shaper_tf), ++ shaper_size, dc_plane_state->in_shaper_func); ++ ++ return ret; ++} ++ + /** + * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. + * @crtc: amdgpu_dm crtc state +@@ -928,7 +957,6 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) + { +- struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + bool has_crtc_cm_degamma; + int ret; + +@@ -939,8 +967,6 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + /* After, we start to update values according to color props */ + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + +- dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult); +- + ret = __set_dm_plane_degamma(plane_state, dc_plane_state); + if (ret == -ENOMEM) + return ret; +@@ -972,5 +998,6 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + return ret; + } + +- return 0; ++ return amdgpu_dm_plane_set_color_properties(plane_state, ++ dc_plane_state); + } +-- +2.40.1 + + +From ec19bcb7f9c99ed36c64497c54952aa72769e1c1 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Sun, 2 Apr 2023 22:46:46 +0100 +Subject: [PATCH 52/59] drm/amd/display: handle empty LUTs in __set_input_tf + +Unlike degamma, blend gamma doesn't support hardcoded curve +(predefined/ROM), but we can use AMD color module to fill blend gamma +parameters when we have non-linear plane gamma TF without plane gamma +LUT. The regular degamma path doesn't hit this. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 20 +++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index b075c9f6e7179..a441c02380f24 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -351,17 +351,21 @@ static int __set_input_tf(struct dc_transfer_func *func, + struct dc_gamma *gamma = NULL; + bool res; + +- gamma = dc_create_gamma(); +- if (!gamma) +- return -ENOMEM; ++ if (lut_size) { ++ gamma = dc_create_gamma(); ++ if (!gamma) ++ return -ENOMEM; + +- gamma->type = GAMMA_CUSTOM; +- gamma->num_entries = lut_size; ++ gamma->type = GAMMA_CUSTOM; ++ gamma->num_entries = lut_size; + +- __drm_lut_to_dc_gamma(lut, gamma, false); ++ __drm_lut_to_dc_gamma(lut, gamma, false); ++ } + +- res = mod_color_calculate_degamma_params(NULL, func, gamma, true); +- dc_gamma_release(&gamma); ++ res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != NULL); ++ ++ if (gamma) ++ dc_gamma_release(&gamma); + + return res ? 0 : -ENOMEM; + } +-- +2.40.1 + + +From b3145cac534368103353e04099c484924bee630b Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Wed, 12 Apr 2023 21:53:32 -0100 +Subject: [PATCH 53/59] drm/amd/display: add DRM plane blend LUT and TF support + +Map DRM plane blend properties to DPP blend gamma. Plane blend is a +post-3D LUT curve that linearizes color space for blending. It may be +defined by a user-blob LUT and/or predefined transfer function. As +hardcoded curve (ROM) is not supported on blend gamma, we use AMD color +module to fill parameters when setting non-linear TF with empty LUT. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 58 ++++++++++++++++++- + 2 files changed, 56 insertions(+), 3 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 9a9c3cbf77693..cecf3dba945c5 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -8064,6 +8064,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; + bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; + bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func; ++ bundle->surface_updates[planes_count].blend_tf = dc_plane->blend_tf; + } + + amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index a441c02380f24..4a2b66568451f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -492,6 +492,34 @@ static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, + return ret; + } + ++static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, ++ bool has_rom, ++ enum dc_transfer_func_predefined tf, ++ uint32_t blend_size, ++ struct dc_transfer_func *func_blend) ++{ ++ int ret = 0; ++ ++ if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) { ++ /* DRM plane gamma LUT or TF means we are linearizing color ++ * space before blending (similar to degamma programming). As ++ * we don't have hardcoded curve support, or we use AMD color ++ * module to fill the parameters that will be translated to HW ++ * points. ++ */ ++ func_blend->type = TF_TYPE_DISTRIBUTED_POINTS; ++ func_blend->tf = tf; ++ func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; ++ ++ ret = __set_input_tf(func_blend, blend_lut, blend_size); ++ } else { ++ func_blend->type = TF_TYPE_BYPASS; ++ func_blend->tf = TRANSFER_FUNCTION_LINEAR; ++ } ++ ++ return ret; ++} ++ + /* amdgpu_dm_atomic_shaper_lut3d - set DRM CRTC shaper LUT and 3D LUT to DC + * interface + * @dc: Display Core control structure +@@ -921,8 +949,10 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, + { + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + enum drm_transfer_function shaper_tf = DRM_TRANSFER_FUNCTION_DEFAULT; +- const struct drm_color_lut *shaper_lut, *lut3d; +- uint32_t lut3d_size, shaper_size; ++ enum drm_transfer_function blend_tf = DRM_TRANSFER_FUNCTION_DEFAULT; ++ const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut; ++ uint32_t lut3d_size, shaper_size, blend_size; ++ int ret; + + /* We have nothing to do here, return */ + if (!plane_state->color_mgmt_changed) +@@ -940,8 +970,30 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, + ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false, + drm_tf_to_dc_tf(shaper_tf), + shaper_size, dc_plane_state->in_shaper_func); ++ if (ret) { ++ drm_dbg_kms(plane_state->plane->dev, ++ "setting plane %d shaper/3d lut failed.\n", ++ plane_state->plane->index); + +- return ret; ++ return ret; ++ } ++ ++ blend_tf = dm_plane_state->blend_tf; ++ blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, &blend_size); ++ blend_size = blend_lut != NULL ? blend_size : 0; ++ ++ ret = amdgpu_dm_atomic_blend_lut(blend_lut, false, ++ drm_tf_to_dc_tf(blend_tf), ++ blend_size, dc_plane_state->blend_tf); ++ if (ret) { ++ drm_dbg_kms(plane_state->plane->dev, ++ "setting plane %d gamma lut failed.\n", ++ plane_state->plane->index); ++ ++ return ret; ++ } ++ ++ return 0; + } + + /** +-- +2.40.1 + + +From 8eb5e95733656b2a7b4ef8c3b7f6fc5cc2b5822c Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Fri, 21 Apr 2023 01:05:39 +0100 +Subject: [PATCH 54/59] drm/amd/display: allow newer DC hardware to use degamma + ROM for PQ/HLG + +Need to funnel the color caps through to these functions so it can check +that the hardware is capable. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 35 ++++++++++++------- + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +index 4a2b66568451f..714f07bb9c9ca 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +@@ -338,6 +338,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + /** + * __set_input_tf - calculates the input transfer function based on expected + * input space. ++ * @caps: dc color capabilities + * @func: transfer function + * @lut: lookup table that defines the color space + * @lut_size: size of respective lut. +@@ -345,7 +346,7 @@ static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + * Returns: + * 0 in case of success. -ENOMEM if fails. + */ +-static int __set_input_tf(struct dc_transfer_func *func, ++static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func, + const struct drm_color_lut *lut, uint32_t lut_size) + { + struct dc_gamma *gamma = NULL; +@@ -362,7 +363,7 @@ static int __set_input_tf(struct dc_transfer_func *func, + __drm_lut_to_dc_gamma(lut, gamma, false); + } + +- res = mod_color_calculate_degamma_params(NULL, func, gamma, gamma != NULL); ++ res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL); + + if (gamma) + dc_gamma_release(&gamma); +@@ -511,7 +512,7 @@ static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, + func_blend->tf = tf; + func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + +- ret = __set_input_tf(func_blend, blend_lut, blend_size); ++ ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size); + } else { + func_blend->type = TF_TYPE_BYPASS; + func_blend->tf = TRANSFER_FUNCTION_LINEAR; +@@ -818,7 +819,8 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc, + + static int + map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, +- struct dc_plane_state *dc_plane_state) ++ struct dc_plane_state *dc_plane_state, ++ struct dc_color_caps *caps) + { + const struct drm_color_lut *degamma_lut; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; +@@ -873,7 +875,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + dc_plane_state->in_transfer_func->tf = + TRANSFER_FUNCTION_LINEAR; + +- r = __set_input_tf(dc_plane_state->in_transfer_func, ++ r = __set_input_tf(caps, dc_plane_state->in_transfer_func, + degamma_lut, degamma_size); + if (r) + return r; +@@ -886,7 +888,7 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + dc_plane_state->in_transfer_func->tf = tf; + + if (tf != TRANSFER_FUNCTION_SRGB && +- !mod_color_calculate_degamma_params(NULL, ++ !mod_color_calculate_degamma_params(caps, + dc_plane_state->in_transfer_func, + NULL, false)) + return -ENOMEM; +@@ -897,7 +899,8 @@ map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + + static int + __set_dm_plane_degamma(struct drm_plane_state *plane_state, +- struct dc_plane_state *dc_plane_state) ++ struct dc_plane_state *dc_plane_state, ++ struct dc_color_caps *color_caps) + { + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + const struct drm_color_lut *degamma_lut; +@@ -906,6 +909,9 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, + bool has_degamma_lut; + int ret; + ++ if (dc_plane_state->ctx && dc_plane_state->ctx->dc) ++ color_caps = &dc_plane_state->ctx->dc->caps.color; ++ + degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut, + °amma_size); + +@@ -928,7 +934,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, + dc_plane_state->in_transfer_func->type = + TF_TYPE_DISTRIBUTED_POINTS; + +- ret = __set_input_tf(dc_plane_state->in_transfer_func, ++ ret = __set_input_tf(color_caps, dc_plane_state->in_transfer_func, + degamma_lut, degamma_size); + if (ret) + return ret; +@@ -945,7 +951,8 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, + + static int + amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, +- struct dc_plane_state *dc_plane_state) ++ struct dc_plane_state *dc_plane_state, ++ struct dc_color_caps *color_caps) + { + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + enum drm_transfer_function shaper_tf = DRM_TRANSFER_FUNCTION_DEFAULT; +@@ -1013,9 +1020,13 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) + { ++ struct dc_color_caps *color_caps = NULL; + bool has_crtc_cm_degamma; + int ret; + ++ if (dc_plane_state->ctx && dc_plane_state->ctx->dc) ++ color_caps = &dc_plane_state->ctx->dc->caps.color; ++ + /* Initially, we can just bypass the DGM block. */ + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; +@@ -1023,7 +1034,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + /* After, we start to update values according to color props */ + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + +- ret = __set_dm_plane_degamma(plane_state, dc_plane_state); ++ ret = __set_dm_plane_degamma(plane_state, dc_plane_state, color_caps); + if (ret == -ENOMEM) + return ret; + +@@ -1049,11 +1060,11 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + * linearize (implicit degamma) from sRGB/BT709 according to + * the input space. + */ +- ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state); ++ ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state, color_caps); + if (ret) + return ret; + } + + return amdgpu_dm_plane_set_color_properties(plane_state, +- dc_plane_state); ++ dc_plane_state, color_caps); + } +-- +2.40.1 + + +From c547b55f0c40d52be6d885865ae3a8c9b707e25b Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Thu, 20 Apr 2023 20:39:00 -0100 +Subject: [PATCH 55/59] HACK: Prefix new color mgmt properties with VALVE1_ + +Plane color mgmt properties, predefined transfer functions and CRTC +shaper/3D LUT aren't upstream properties yet, add a prefix to indicate +they are downstream props. + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 26 ++++++++++----------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 708866da78633..8b3933a77e7b5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1269,7 +1269,7 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + + prop = drm_property_create_enum(adev_to_drm(adev), + DRM_MODE_PROP_ENUM, +- "AMD_REGAMMA_TF", ++ "VALVE1_CRTC_REGAMMA_TF", + drm_transfer_function_enum_list, + ARRAY_SIZE(drm_transfer_function_enum_list)); + if (!prop) +@@ -1278,21 +1278,21 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, +- "AMD_PLANE_DEGAMMA_LUT", 0); ++ "VALVE1_PLANE_DEGAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, +- "AMD_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX); ++ "VALVE1_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_size_property = prop; + + prop = drm_property_create_enum(adev_to_drm(adev), + DRM_MODE_PROP_ENUM, +- "AMD_PLANE_DEGAMMA_TF", ++ "VALVE1_PLANE_DEGAMMA_TF", + drm_transfer_function_enum_list, + ARRAY_SIZE(drm_transfer_function_enum_list)); + if (!prop) +@@ -1300,28 +1300,28 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + adev->mode_info.plane_degamma_tf_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), +- 0, "AMD_PLANE_HDR_MULT", 0, U64_MAX); ++ 0, "VALVE1_PLANE_HDR_MULT", 0, U64_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_hdr_mult_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, +- "AMD_PLANE_SHAPER_LUT", 0); ++ "VALVE1_PLANE_SHAPER_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, +- "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX); ++ "VALVE1_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_size_property = prop; + + prop = drm_property_create_enum(adev_to_drm(adev), + DRM_MODE_PROP_ENUM, +- "AMD_PLANE_SHAPER_TF", ++ "VALVE1_PLANE_SHAPER_TF", + drm_transfer_function_enum_list, + ARRAY_SIZE(drm_transfer_function_enum_list)); + if (!prop) +@@ -1330,35 +1330,35 @@ amdgpu_display_create_color_properties(struct amdgpu_device *adev) + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, +- "AMD_PLANE_LUT3D", 0); ++ "VALVE1_PLANE_LUT3D", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, +- "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX); ++ "VALVE1_PLANE_LUT3D_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_size_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, +- "AMD_PLANE_BLEND_LUT", 0); ++ "VALVE1_PLANE_BLEND_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, +- "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); ++ "VALVE1_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_size_property = prop; + + prop = drm_property_create_enum(adev_to_drm(adev), + DRM_MODE_PROP_ENUM, +- "AMD_PLANE_BLEND_TF", ++ "VALVE1_PLANE_BLEND_TF", + drm_transfer_function_enum_list, + ARRAY_SIZE(drm_transfer_function_enum_list)); + if (!prop) +-- +2.40.1 + + +From 382168425feb5a2019cd0982e96b0e6e813fd33b Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Fri, 12 May 2023 18:43:46 +0000 +Subject: [PATCH 56/59] drm/amd/display: Reset CRTC color mgmt state if commit + fails + +If we failed our commit, if our new crtc was dirty color-wise, make +sure we forward that dirty bit on our old state now so we don't +forget to revert the work we did before we failed this commit on +the next commit. + +Fixes a bug in SteamOS/Gamescope where we could fail a +commit that changed the gamma of the CRTC and it would +persist even after we did a new commit with a different +gamma (as we were doing single plane optimizations +and didn't need degamma + gamma for correct blending) + +Signed-off-by: Joshua Ashton <joshua@froggi.es> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 32 +++++++++++++++++++ + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + + .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 1 + + 3 files changed, 34 insertions(+) + +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 cecf3dba945c5..b2158c17e9bbc 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -10012,6 +10012,21 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + } + } + } ++ ++ /* Propogate CM reset state */ ++ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ++ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); ++ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); ++ ++ if (dm_old_crtc_state->cm_needs_reset || dm_new_crtc_state->cm_needs_reset) ++ { ++ dm_old_crtc_state->cm_needs_reset = false; ++ dm_new_crtc_state->cm_needs_reset = false; ++ ++ dm_new_crtc_state->base.color_mgmt_changed = true; ++ } ++ } ++ + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + +@@ -10363,6 +10378,23 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, + return ret; + + fail: ++ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { ++ /* ++ * If we failed our commit, if our new crtc was dirty color-wise, make sure we forward that ++ * dirty bit on our old state now so we don't forget to revert the work we did before ++ * we failed this commit on the next commit. ++ * ++ * Store it on old and new state so we don't lose track of it for this CRTC. ++ */ ++ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); ++ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); ++ ++ if (new_crtc_state->color_mgmt_changed) { ++ dm_old_crtc_state->cm_needs_reset = true; ++ dm_new_crtc_state->cm_needs_reset = true; ++ } ++ } ++ + if (ret == -EDEADLK) + DRM_DEBUG_DRIVER("Atomic check stopped to avoid deadlock.\n"); + else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS) +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +index bf4a1d6be99e6..ec56a555721e3 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +@@ -796,6 +796,7 @@ struct dm_crtc_state { + struct dc_info_packet vrr_infopacket; + + int abm_level; ++ bool cm_needs_reset; + + /* AMD driver-private CRTC color management + * +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +index 4a725aeef3e84..73f7970a08ceb 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -255,6 +255,7 @@ static struct drm_crtc_state *dm_crtc_duplicate_state(struct drm_crtc *crtc) + state->regamma_tf = cur->regamma_tf; + state->crc_skip_count = cur->crc_skip_count; + state->mpo_requested = cur->mpo_requested; ++ state->cm_needs_reset = cur->cm_needs_reset; + /* TODO Duplicate dc_stream after objects are stream object is flattened */ + + return &state->base; +-- +2.40.1 + + +From ee349e3c6c78e085909da04232d6be7872ac820e Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Sat, 22 Apr 2023 14:08:47 -0100 +Subject: [PATCH 57/59] HACK: add KConfig to enable driver-specific color mgmt + props + +We are enabling a large set of color calibration features to enhance KMS +color mgmt but these properties are specific of AMD display HW, and +cannot be provided by other vendors. Therefore, set a config option to +enable AMD driver-private properties used on Steam Deck color mgmt +pipeline. Replace the agreed name `AMD_PRIVATE_COLOR` with +our downstream version `CONFIG_DRM_AMD_COLOR_STEAMDECK`. + +Signed-off-by: Melissa Wen <mwen@igalia.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 4 ++-- + drivers/gpu/drm/amd/display/Kconfig | 6 ++++++ + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 6 +++--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 6 +++--- + 4 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +index 8b3933a77e7b5..12e8db8f04209 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +@@ -1261,7 +1261,7 @@ static const struct drm_prop_enum_list drm_transfer_function_enum_list[] = { + { DRM_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, + }; + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + static int + amdgpu_display_create_color_properties(struct amdgpu_device *adev) + { +@@ -1445,7 +1445,7 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) + return -ENOMEM; + } + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + if (amdgpu_display_create_color_properties(adev)) + return -ENOMEM; + #endif +diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig +index 2d8e55e29637f..2357d2ef6fe60 100644 +--- a/drivers/gpu/drm/amd/display/Kconfig ++++ b/drivers/gpu/drm/amd/display/Kconfig +@@ -53,5 +53,11 @@ config DRM_AMD_SECURE_DISPLAY + of crc of specific region via debugfs. + Cooperate with specific DMCU FW. + ++config DRM_AMD_COLOR_STEAMDECK ++ bool "Enable color calibration features for Steam Deck" ++ depends on DRM_AMD_DC ++ help ++ Choose this option if you want to use AMDGPU features for broader ++ color management support on Steam Deck. + + endmenu +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +index 73f7970a08ceb..98a2877642997 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -290,7 +290,7 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc) + } + #endif + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + /** + * drm_crtc_additional_color_mgmt - enable additional color properties + * @crtc: DRM CRTC +@@ -371,7 +371,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { + #if defined(CONFIG_DEBUG_FS) + .late_register = amdgpu_dm_crtc_late_register, + #endif +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + .atomic_set_property = amdgpu_dm_atomic_crtc_set_property, + .atomic_get_property = amdgpu_dm_atomic_crtc_get_property, + #endif +@@ -538,7 +538,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, + + drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + dm_crtc_additional_color_mgmt(&acrtc->base); + #endif + return 0; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index ea13b49fa0215..5a03fba687b42 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1453,7 +1453,7 @@ static const struct drm_prop_enum_list drm_transfer_function_enum_list[] = { + { DRM_TRANSFER_FUNCTION_GAMMA26, "Gamma 2.6" }, + }; + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + static void + dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + struct drm_plane *plane) +@@ -1621,7 +1621,7 @@ static const struct drm_plane_funcs dm_plane_funcs = { + .atomic_duplicate_state = dm_drm_plane_duplicate_state, + .atomic_destroy_state = dm_drm_plane_destroy_state, + .format_mod_supported = dm_plane_format_mod_supported, +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + .atomic_set_property = dm_atomic_plane_set_property, + .atomic_get_property = dm_atomic_plane_get_property, + #endif +@@ -1695,7 +1695,7 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, + + drm_plane_helper_add(plane, &dm_plane_helper_funcs); + +-#ifdef AMD_PRIVATE_COLOR ++#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK + dm_atomic_plane_attach_color_mgmt_properties(dm, plane); + #endif + /* Create (reset) the plane state */ +-- +2.40.1 + + +From c029477e4ed957af0b3dc75e9cce2a6630b70393 Mon Sep 17 00:00:00 2001 +From: Melissa Wen <mwen@igalia.com> +Date: Sun, 11 Jun 2023 13:34:02 -0100 +Subject: [PATCH 58/59] Revert "drm/amd/display: mark plane as needing reset if + plane color mgmt changes" + +This reverts commit f3a18707a984d82ab842bd8b8666a442c1943d59. +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 --- + 1 file changed, 3 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 b2158c17e9bbc..ba2e43ab8df56 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -9519,9 +9519,6 @@ static bool should_reset_plane(struct drm_atomic_state *state, + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) + return true; + +- if (new_plane_state->color_mgmt_changed) +- return true; +- + /* + * If there are any new primary or overlay planes being added or + * removed then the z-order can potentially change. To ensure +-- +2.40.1 + + +From a5d8fb5b89a34ba97ffb423dceafc6d3cb5c35bf Mon Sep 17 00:00:00 2001 +From: Joshua Ashton <joshua@froggi.es> +Date: Fri, 14 Apr 2023 22:19:49 -0100 +Subject: [PATCH 59/59] drm/amd/display: mark plane as needing reset if color + props change + +Co-developed-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Melissa Wen <mwen@igalia.com> +Signed-off-by: Joshua Ashton <joshua@froggi.es> +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +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 ba2e43ab8df56..50bf1cd900156 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -9529,6 +9529,11 @@ static bool should_reset_plane(struct drm_atomic_state *state, + */ + for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { + struct amdgpu_framebuffer *old_afb, *new_afb; ++ struct dm_plane_state *dm_new_other_state, *dm_old_other_state; ++ ++ dm_new_other_state = to_dm_plane_state(new_other_state); ++ dm_old_other_state = to_dm_plane_state(old_other_state); ++ + if (other->type == DRM_PLANE_TYPE_CURSOR) + continue; + +@@ -9564,6 +9569,17 @@ static bool should_reset_plane(struct drm_atomic_state *state, + old_other_state->color_encoding != new_other_state->color_encoding) + return true; + ++ /* HDR/Transfer Function changes. */ ++ if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf || ++ dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut || ++ dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult || ++ dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut || ++ dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf || ++ dm_old_other_state->lut3d != dm_new_other_state->lut3d || ++ dm_old_other_state->blend_lut != dm_new_other_state->blend_lut || ++ dm_old_other_state->blend_tf != dm_new_other_state->blend_tf) ++ return true; ++ + /* Framebuffer checks fall at the end. */ + if (!old_other_state->fb || !new_other_state->fb) + continue; +-- +2.40.1 + @@ -12,7 +12,7 @@ pkgbase=linux-jcore pkgname=('linux-jcore' 'linux-jcore-headers') _kernelname=-jcore _hostname=jcore -pkgver=6.4.8 +pkgver=6.4.11 pkgrel=1 pkgdesc="Kernel for Manjaro/EndeavourOS/Arch (ACS override patch include)" arch=('x86_64') @@ -27,21 +27,45 @@ source=("https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$pkgver.tar.xz" # Upstream Patches # ARCH Patches '0101-ZEN_Add_sysctl_and_CONFIG_to_disallow_unprivileged_CLONE_NEWUSER.patch' - '0102-mm-disable_CONFIG_PER_VMA_LOCK.patch' + 'e65a5fe09577d17e2fded61067f759f2bf02f6c0.patch' # MANJARO Patches '0203-asus-ally-asus-hid-6.3-v2.patch' '0204-mt7921e_Perform_FLR_to_recovery_the_device.patch' '0206-asus-ally-bluetooth.patch' # ACS override patch - '0999-acs.gitpatch') -sha256sums=('c59f34e19e84db30206b9373041abf893f9d8a08765d163586570a5238c458b6' - '01d2816ad5365884470a76f719593dd529fa9c32e1781d52d0144ef7c81d31ab' + '0999-acs.gitpatch' + # fix sleep cs35l41 + '0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch' + '0002-ALSA-cs35l41-Poll-for-Power-Up-Down-rather-than-wait.patch' + '0003-ALSA-hda-cs35l41-Check-mailbox-status-of-pause-comma.patch' + '0004-ALSA-hda-cs35l41-Ensure-we-correctly-re-sync-regmap-.patch' + '0005-ALSA-hda-cs35l41-Ensure-we-pass-up-any-errors-during.patch' + '0006-ALSA-hda-cs35l41-Move-Play-and-Pause-into-separate-f.patch' + '0007-ALSA-hda-hda_component-Add-pre-and-post-playback-hoo.patch' + '0008-ALSA-hda-cs35l41-Use-pre-and-post-playback-hooks.patch' + '0009-ALSA-hda-cs35l41-Rework-System-Suspend-to-ensure-cor.patch' + '0010-ALSA-hda-cs35l41-Add-device_link-between-HDA-and-cs3.patch' + '0011-ALSA-hda-cs35l41-Ensure-amp-is-only-unmuted-during-p.patch') + +sha256sums=('546b68b5097d3c0d74722de62aae217729d98e45fbb6bd458b490ac21ea40918' + 'f55c1744ab79ba72a987c333c1feaf2290d5dcec709596a0d9f84f00839a51a7' '05f04019d4a2ee072238c32860fa80d673687d84d78ef436ae9332b6fb788467' - '7e79a1cc688189c66837611aa42ecf65a4f2fb071920830e9f4db923a13e9105' + '36a32f67a9725ae96ad0ba0fb8a6262f666c53e304cc142e88826daa0afc65aa' 'a38b50b8c73332d3d16950bf8adcae7ead34391a60f74d05a58935cd3dc8a12d' 'd673d034fbcd80426fd8d9c6af56537c5fe5b55fe49d74e313474d7fc285ecc1' 'd5f95fe43882fb68c0a7e1ce8d831788e222f841de3e636e85a89ea655fed40e' - '458d7e024d33d4965b14b9b987f01a2884ff28761cff5da7c6a54132a95e9f36') + '458d7e024d33d4965b14b9b987f01a2884ff28761cff5da7c6a54132a95e9f36' + '27aaf7e14c7f5e127f5b658352ca5c3650477a92462139557aefb73bcea2b418' + '74da118887929f06afb57eaee716ff433ee5972c9dc91166fc08e66f44edb8e8' + 'c5ac510677e58ac6b189939ac853e64bf9ad026a614a47f4cb535ad62bf41163' + '88f0d69dad01ccfef899b6b08abe162fc7743d40571232dff9a7d9093890d0a8' + '826bfa21b613d9c198d375d902958c90bb30171aee602c1806aaf99212abbb40' + '0dae5e24249b712f1501ead600c8ef4a5df21484e39e06a1dbafb57929c4999f' + '8dddf5537e3feedbf9f9c67f3c19fa7412d9e01b4f78023262b8fa340d3f47b2' + '3774b4eba753eb5f3768a28a68eb1a17557c0347275c19b8133f9f74d64a80df' + 'a5daf210a6f72dde5b477d4b6d38a162b2698cac6c5fcfd4e4fd606274f34cec' + 'b9298bde48a9f6c5d028150d627c05c71880e2693933ef2fe070f090e80876a5' + '4d53a6853b63c0f01b60b408bee61fa729656f925e50fa55ae3cba309668242a') prepare() { cd "linux-${pkgver}" @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.4.3-1 Kernel Configuration +# Linux/x86 6.4.11-1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.1.1 20230429" CONFIG_CC_IS_GCC=y diff --git a/e65a5fe09577d17e2fded61067f759f2bf02f6c0.patch b/e65a5fe09577d17e2fded61067f759f2bf02f6c0.patch new file mode 100644 index 000000000000..0cfe30283f3d --- /dev/null +++ b/e65a5fe09577d17e2fded61067f759f2bf02f6c0.patch @@ -0,0 +1,87 @@ +From e65a5fe09577d17e2fded61067f759f2bf02f6c0 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas <javierm@redhat.com> +Date: Thu, 19 May 2022 14:40:07 +0200 +Subject: [PATCH] drivers/firmware: skip simpledrm if nvidia-drm.modeset=1 is + set + +The Nvidia proprietary driver has some bugs that leads to issues if used +with the simpledrm driver. The most noticeable is that does not register +an emulated fbdev device. + +It just relies on a fbdev to be registered by another driver, that could +be that could be attached to the framebuffer console. On UEFI machines, +this is the efifb driver. + +This means that disabling the efifb driver will cause virtual consoles to +not be present in the system when using the Nvidia driver. Legacy BIOS is +not affected just because fbcon is not used there, but instead vgacon. + +Unless a VGA mode is specified using the vga= kernel command line option, +in that case the vesafb driver is used instead and its fbdev attached to +the fbcon. + +This is a problem because with CONFIG_SYSFB_SIMPLEFB=y, the sysfb platform +code attempts to register a "simple-framebuffer" platform device (that is +matched against simpledrm) and only registers either an "efi-framebuffer" +or "vesa-framebuffer" if this fails to be registered due the video modes +not being compatible. + +The Nvidia driver relying on another driver to register the fbdev is quite +fragile, since it can't really assume those will stick around. For example +there are patches posted to remove the EFI and VESA platform devices once +a real DRM or fbdev driver probes. + +But in any case, moving to a simpledrm + emulated fbdev only breaks this +assumption and causes users to not have VT if the Nvidia driver is used. + +So to prevent this, let's add a workaround and make the sysfb to skip the +"simple-framebuffer" registration when nvidia-drm.modeset=1 option is set. + +This is quite horrible, but honestly I can't think of any other approach. + +For this to work, the CONFIG_FB_EFI and CONFIG_FB_VESA config options must +be enabled besides CONFIG_DRM_SIMPLEDRM. + +Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> +(cherry picked from commit 811fe0e4dcfd86a0db5135d3bfef4936794efdb6) +For: https://bugs.archlinux.org/task/73720 +--- + drivers/firmware/sysfb.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c +index 3c197db42c9d93..16e4a2e90fae2a 100644 +--- a/drivers/firmware/sysfb.c ++++ b/drivers/firmware/sysfb.c +@@ -34,6 +34,22 @@ + #include <linux/screen_info.h> + #include <linux/sysfb.h> + ++static int skip_simpledrm; ++ ++static int __init simpledrm_disable(char *opt) ++{ ++ if (!opt) ++ return -EINVAL; ++ ++ get_option(&opt, &skip_simpledrm); ++ ++ if (skip_simpledrm) ++ pr_info("The simpledrm driver will not be probed\n"); ++ ++ return 0; ++} ++early_param("nvidia-drm.modeset", simpledrm_disable); ++ + static struct platform_device *pd; + static DEFINE_MUTEX(disable_lock); + static bool disabled; +@@ -85,7 +101,7 @@ static __init int sysfb_init(void) + + /* try to create a simple-framebuffer device */ + compatible = sysfb_parse_mode(si, &mode); +- if (compatible) { ++ if (compatible && !skip_simpledrm) { + pd = sysfb_create_simplefb(si, &mode); + if (!IS_ERR(pd)) + goto unlock_mutex; |