[PATCH v5 08/10] drm/mediatek: dp: Add support for embedded DisplayPort aux-bus

2023-07-13 Thread AngeloGioacchino Del Regno
For the eDP case we can support using aux-bus on MediaTek DP: this
gives us the possibility to declare our panel as generic "panel-edp"
which will automatically configure the timings and available modes
via the EDID that we read from it.

To do this, move the panel parsing at the end of the probe function
so that the hardware is initialized beforehand and also initialize
the DPTX AUX block and power both on as, when we populate the
aux-bus, the panel driver will trigger an EDID read to perform
panel detection.

Last but not least, since now the AUX transfers can happen in the
separated aux-bus, it was necessary to add an exclusion for the
cable_plugged_in check in `mtk_dp_aux_transfer()` and the easiest
way to do this is to simply ignore checking that when the bridge
type is eDP.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/Kconfig  |  1 +
 drivers/gpu/drm/mediatek/mtk_dp.c | 85 ---
 2 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index b451dee64d34..76cab28e010c 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -26,6 +26,7 @@ config DRM_MEDIATEK_DP
select PHY_MTK_DP
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DP_HELPER
+   select DRM_DP_AUX_BUS
help
  DRM/KMS Display Port driver for MediaTek SoCs.
 
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 1684dbf7bbff..8668ab17135d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2022 BayLibre
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -1313,9 +1314,11 @@ static void mtk_dp_power_disable(struct mtk_dp *mtk_dp)
 
 static void mtk_dp_initialize_priv_data(struct mtk_dp *mtk_dp)
 {
+   bool plugged_in = (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP);
+
mtk_dp->train_info.link_rate = DP_LINK_BW_5_4;
mtk_dp->train_info.lane_count = mtk_dp->max_lanes;
-   mtk_dp->train_info.cable_plugged_in = false;
+   mtk_dp->train_info.cable_plugged_in = plugged_in;
 
mtk_dp->info.format = DP_PIXELFORMAT_RGB;
memset(&mtk_dp->info.vm, 0, sizeof(struct videomode));
@@ -1617,6 +1620,16 @@ static int mtk_dp_parse_capabilities(struct mtk_dp 
*mtk_dp)
u8 val;
ssize_t ret;
 
+   /*
+* If we're eDP and capabilities were already parsed we can skip
+* reading again because eDP panels aren't hotpluggable hence the
+* caps and training information won't ever change in a boot life
+*/
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP &&
+   mtk_dp->rx_cap[DP_MAX_LINK_RATE] &&
+   mtk_dp->train_info.sink_ssc)
+   return 0;
+
drm_dp_read_dpcd_caps(&mtk_dp->aux, mtk_dp->rx_cap);
 
if (drm_dp_tps4_supported(mtk_dp->rx_cap))
@@ -2025,15 +2038,14 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
 static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux *mtk_aux,
   struct drm_dp_aux_msg *msg)
 {
-   struct mtk_dp *mtk_dp;
+   struct mtk_dp *mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
bool is_read;
u8 request;
size_t accessed_bytes = 0;
int ret;
 
-   mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
-
-   if (!mtk_dp->train_info.cable_plugged_in) {
+   if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP &&
+   !mtk_dp->train_info.cable_plugged_in) {
ret = -EAGAIN;
goto err;
}
@@ -2496,6 +2508,29 @@ static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
return 0;
 }
 
+static int mtk_dp_edp_link_panel(struct drm_dp_aux *mtk_aux)
+{
+   struct mtk_dp *mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
+   struct device *dev = mtk_aux->dev;
+   int ret;
+
+   mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+
+   /* Power off the DP and AUX: either detection is done, or no panel 
present */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+  DP_PWR_STATE_BANDGAP_TPLL,
+  DP_PWR_STATE_MASK);
+   mtk_dp_power_disable(mtk_dp);
+
+   if (IS_ERR(mtk_dp->next_bridge)) {
+   ret = PTR_ERR(mtk_dp->next_bridge);
+   mtk_dp->next_bridge = NULL;
+   return ret;
+   }
+
+   return 0;
+}
+
 static int mtk_dp_probe(struct platform_device *pdev)
 {
struct mtk_dp *mtk_dp;
@@ -2526,9 +2561,10 @@ static int mtk_dp_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "Failed to parse dt\n");
 
-   drm_dp_aux_init(&

[PATCH v5 05/10] drm/mediatek: dp: Enable event interrupt only when bridge attached

2023-07-13 Thread AngeloGioacchino Del Regno
It is useless and error-prone to enable the DisplayPort event interrupt
before finishing to probe and install the driver, as the DP training
cannot happen before the entire pipeline is correctly set up, as the
interrupt handler also requires the full hardware to be initialized by
mtk_dp_bridge_attach().

Anyway, depending in which state the controller is left from the
bootloader, this may cause an interrupt storm and consequently hang
the kernel during boot, so, avoid enabling the interrupt until we
reach a clean state by adding the IRQ_NOAUTOEN flag before requesting
it at probe time and manage the enablement of the ISR in the .attach()
and .detach() handlers for the DP bridge.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index b4e775e040ee..d67dbafbac8e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -100,6 +100,7 @@ struct mtk_dp_efuse_fmt {
 struct mtk_dp {
bool enabled;
bool need_debounce;
+   int irq;
u8 max_lanes;
u8 max_linkrate;
u8 rx_cap[DP_RECEIVER_CAP_SIZE];
@@ -2136,6 +2137,8 @@ static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
 
mtk_dp->drm_dev = bridge->dev;
 
+   irq_clear_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   enable_irq(mtk_dp->irq);
mtk_dp_hwirq_enable(mtk_dp, true);
 
return 0;
@@ -2152,6 +2155,7 @@ static void mtk_dp_bridge_detach(struct drm_bridge 
*bridge)
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
 
mtk_dp_hwirq_enable(mtk_dp, false);
+   disable_irq(mtk_dp->irq);
mtk_dp->drm_dev = NULL;
mtk_dp_poweroff(mtk_dp);
drm_dp_aux_unregister(&mtk_dp->aux);
@@ -2470,7 +2474,7 @@ static int mtk_dp_probe(struct platform_device *pdev)
 {
struct mtk_dp *mtk_dp;
struct device *dev = &pdev->dev;
-   int ret, irq_num;
+   int ret;
 
mtk_dp = devm_kzalloc(dev, sizeof(*mtk_dp), GFP_KERNEL);
if (!mtk_dp)
@@ -2479,9 +2483,9 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->dev = dev;
mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
 
-   irq_num = platform_get_irq(pdev, 0);
-   if (irq_num < 0)
-   return dev_err_probe(dev, irq_num,
+   mtk_dp->irq = platform_get_irq(pdev, 0);
+   if (mtk_dp->irq < 0)
+   return dev_err_probe(dev, mtk_dp->irq,
 "failed to request dp irq resource\n");
 
mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
@@ -2502,7 +2506,8 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
spin_lock_init(&mtk_dp->irq_thread_lock);
 
-   ret = devm_request_threaded_irq(dev, irq_num, mtk_dp_hpd_event,
+   irq_set_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   ret = devm_request_threaded_irq(dev, mtk_dp->irq, mtk_dp_hpd_event,
mtk_dp_hpd_event_thread,
IRQ_TYPE_LEVEL_HIGH, dev_name(dev),
mtk_dp);
-- 
2.40.1



[PATCH v5 07/10] drm/mediatek: dp: Move PHY registration to new function

2023-07-13 Thread AngeloGioacchino Del Regno
In preparation for adding support for eDP, move the PHY registration
code to a new mtk_dp_register_phy() function for better readability.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dp.c | 43 +++
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 3cb234b502a5..1684dbf7bbff 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2473,6 +2473,29 @@ static int mtk_dp_register_audio_driver(struct device 
*dev)
return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
 }
 
+static int mtk_dp_register_phy(struct mtk_dp *mtk_dp)
+{
+   struct device *dev = mtk_dp->dev;
+
+   mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
+   PLATFORM_DEVID_AUTO,
+   &mtk_dp->regs,
+   sizeof(struct regmap 
*));
+   if (IS_ERR(mtk_dp->phy_dev))
+   return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
+"Failed to create device 
mediatek-dp-phy\n");
+
+   mtk_dp_get_calibration_data(mtk_dp);
+
+   mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
+   if (IS_ERR(mtk_dp->phy)) {
+   platform_device_unregister(mtk_dp->phy_dev);
+   return dev_err_probe(dev, PTR_ERR(mtk_dp->phy), "Failed to get 
phy\n");
+   }
+
+   return 0;
+}
+
 static int mtk_dp_probe(struct platform_device *pdev)
 {
struct mtk_dp *mtk_dp;
@@ -2531,23 +2554,9 @@ static int mtk_dp_probe(struct platform_device *pdev)
}
}
 
-   mtk_dp->phy_dev = platform_device_register_data(dev, "mediatek-dp-phy",
-   PLATFORM_DEVID_AUTO,
-   &mtk_dp->regs,
-   sizeof(struct regmap 
*));
-   if (IS_ERR(mtk_dp->phy_dev))
-   return dev_err_probe(dev, PTR_ERR(mtk_dp->phy_dev),
-"Failed to create device 
mediatek-dp-phy\n");
-
-   mtk_dp_get_calibration_data(mtk_dp);
-
-   mtk_dp->phy = devm_phy_get(&mtk_dp->phy_dev->dev, "dp");
-
-   if (IS_ERR(mtk_dp->phy)) {
-   platform_device_unregister(mtk_dp->phy_dev);
-   return dev_err_probe(dev, PTR_ERR(mtk_dp->phy),
-"Failed to get phy\n");
-   }
+   ret = mtk_dp_register_phy(mtk_dp);
+   if (ret)
+   return ret;
 
mtk_dp->bridge.funcs = &mtk_dp_bridge_funcs;
mtk_dp->bridge.of_node = dev->of_node;
-- 
2.40.1



[PATCH v5 10/10] drm/mediatek: dp: Don't register HPD interrupt handler for eDP case

2023-07-13 Thread AngeloGioacchino Del Regno
The interrupt handler for HPD is useful only if a display is actually
supposed to be hotpluggable, as that manages the machinery to perform
cable (un)plug detection, debouncing and setup for re-training.

Since eDP panels are not supposed to be hotpluggable we can avoid
using the HPD interrupts altogether and rely on HPD polling only
for the suspend/resume case, saving us some spinlocking action and
the overhead of interrupts firing at every suspend/resume cycle,
achieving a faster (even if just slightly) display resume.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dp.c | 81 ++-
 1 file changed, 46 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index a00bf6693b28..14eeb4a74191 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2175,9 +2175,11 @@ static int mtk_dp_bridge_attach(struct drm_bridge 
*bridge,
 
mtk_dp->drm_dev = bridge->dev;
 
-   irq_clear_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
-   enable_irq(mtk_dp->irq);
-   mtk_dp_hwirq_enable(mtk_dp, true);
+   if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP) {
+   irq_clear_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   enable_irq(mtk_dp->irq);
+   mtk_dp_hwirq_enable(mtk_dp, true);
+   }
 
return 0;
 
@@ -2192,8 +2194,10 @@ static void mtk_dp_bridge_detach(struct drm_bridge 
*bridge)
 {
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
 
-   mtk_dp_hwirq_enable(mtk_dp, false);
-   disable_irq(mtk_dp->irq);
+   if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP) {
+   mtk_dp_hwirq_enable(mtk_dp, false);
+   disable_irq(mtk_dp->irq);
+   }
mtk_dp->drm_dev = NULL;
mtk_dp_poweroff(mtk_dp);
drm_dp_aux_unregister(&mtk_dp->aux);
@@ -2567,40 +2571,44 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->dev = dev;
mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
 
-   mtk_dp->irq = platform_get_irq(pdev, 0);
-   if (mtk_dp->irq < 0)
-   return dev_err_probe(dev, mtk_dp->irq,
-"failed to request dp irq resource\n");
-
-   mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
-   if (IS_ERR(mtk_dp->next_bridge) &&
-   PTR_ERR(mtk_dp->next_bridge) == -ENODEV)
-   mtk_dp->next_bridge = NULL;
-   else if (IS_ERR(mtk_dp->next_bridge))
-   return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
-"Failed to get bridge\n");
-
ret = mtk_dp_dt_parse(mtk_dp, pdev);
if (ret)
return dev_err_probe(dev, ret, "Failed to parse dt\n");
 
+   /*
+* Request the interrupt and install service routine only if we are
+* on full DisplayPort.
+* For eDP, polling the HPD instead is more convenient because we
+* don't expect any (un)plug events during runtime, hence we can
+* avoid some locking.
+*/
+   if (mtk_dp->data->bridge_type != DRM_MODE_CONNECTOR_eDP) {
+   mtk_dp->irq = platform_get_irq(pdev, 0);
+   if (mtk_dp->irq < 0)
+   return dev_err_probe(dev, mtk_dp->irq,
+"failed to request dp irq 
resource\n");
+
+   spin_lock_init(&mtk_dp->irq_thread_lock);
+
+   irq_set_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   ret = devm_request_threaded_irq(dev, mtk_dp->irq, 
mtk_dp_hpd_event,
+   mtk_dp_hpd_event_thread,
+   IRQ_TYPE_LEVEL_HIGH, 
dev_name(dev),
+   mtk_dp);
+   if (ret)
+   return dev_err_probe(dev, ret,
+"failed to request mediatek dptx 
irq\n");
+
+   mtk_dp->need_debounce = true;
+   timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
+   }
+
mtk_dp->aux.name = "aux_mtk_dp";
mtk_dp->aux.dev = dev;
mtk_dp->aux.transfer = mtk_dp_aux_transfer;
mtk_dp->aux.wait_hpd_asserted = mtk_dp_wait_hpd_asserted;
drm_dp_aux_init(&mtk_dp->aux);
 
-   spin_lock_init(&mtk_dp->irq_thread_lock);
-
-   irq_set_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
-   ret = devm_request_threaded_irq(dev, mtk_dp->irq, mtk_dp_hpd_event,
-   mtk_dp_hpd_event_thread,
-   IRQ_TYPE_LEVEL_HIGH, dev_name(dev),
- 

[PATCH v5 06/10] drm/mediatek: dp: Avoid mutex locks if audio is not supported/enabled

2023-07-13 Thread AngeloGioacchino Del Regno
If a controller (usually, eDP!) does not support audio, or audio is not
enabled because the endpoint has no audio support, it's useless to lock
a mutex only to unlock it right after because there's no .plugged_cb().

Check if the audio is supported and enabled before locking the mutex in
mtk_dp_update_plugged_status(): if not, we simply return immediately.

While at it, since the update_plugged_status_lock mutex would not be
used if the controller doesn't support audio at all, initialize it
only if `audio_supported` is true.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dp.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index d67dbafbac8e..3cb234b502a5 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1943,6 +1943,9 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp,
 
 static void mtk_dp_update_plugged_status(struct mtk_dp *mtk_dp)
 {
+   if (!mtk_dp->data->audio_supported || !mtk_dp->audio_enable)
+   return;
+
mutex_lock(&mtk_dp->update_plugged_status_lock);
if (mtk_dp->plugged_cb && mtk_dp->codec_dev)
mtk_dp->plugged_cb(mtk_dp->codec_dev,
@@ -2515,11 +2518,11 @@ static int mtk_dp_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret,
 "failed to request mediatek dptx irq\n");
 
-   mutex_init(&mtk_dp->update_plugged_status_lock);
-
platform_set_drvdata(pdev, mtk_dp);
 
if (mtk_dp->data->audio_supported) {
+   mutex_init(&mtk_dp->update_plugged_status_lock);
+
ret = mtk_dp_register_audio_driver(dev);
if (ret) {
dev_err(dev, "Failed to register audio driver: %d\n",
-- 
2.40.1



[PATCH v5 04/10] drm/mediatek: dp: Move AUX_P0 setting to mtk_dp_initialize_aux_settings()

2023-07-13 Thread AngeloGioacchino Del Regno
Move the register write to MTK_DP_AUX_P0_3690 to set the AUX reply mode
to function mtk_dp_initialize_aux_settings(), as this is effectively
part of the DPTX AUX setup sequence.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 9dea78529697..b4e775e040ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1009,6 +1009,11 @@ static void mtk_dp_initialize_aux_settings(struct mtk_dp 
*mtk_dp)
mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_37C8,
   MTK_ATOP_EN_AUX_TX_P0,
   MTK_ATOP_EN_AUX_TX_P0);
+
+   /* Set complete reply mode for AUX */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
+  RX_REPLY_COMPLETE_MODE_AUX_TX_P0,
+  RX_REPLY_COMPLETE_MODE_AUX_TX_P0);
 }
 
 static void mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
@@ -1821,10 +1826,6 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
mtk_dp_initialize_settings(mtk_dp);
mtk_dp_initialize_aux_settings(mtk_dp);
mtk_dp_initialize_digital_settings(mtk_dp);
-
-   mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
-  RX_REPLY_COMPLETE_MODE_AUX_TX_P0,
-  RX_REPLY_COMPLETE_MODE_AUX_TX_P0);
mtk_dp_initialize_hpd_detect_settings(mtk_dp);
 
mtk_dp_digital_sw_reset(mtk_dp);
-- 
2.40.1



[PATCH v5 00/10] MediaTek DisplayPort: support eDP and aux-bus

2023-07-13 Thread AngeloGioacchino Del Regno
};
};
};

aux-bus {
panel: panel {
compatible = "edp-panel";
power-supply = <&pp3300_disp_x>;
    backlight = <&backlight_lcd0>;
port {
panel_in: endpoint {
remote-endpoint = <&edp_out>;
};
};
};
};
};

AngeloGioacchino Del Regno (10):
  drm/mediatek: dp: Move AUX and panel poweron/off sequence to function
  drm/mediatek: dp: Change logging to dev for mtk_dp_aux_transfer()
  drm/mediatek: dp: Use devm variant of drm_bridge_add()
  drm/mediatek: dp: Move AUX_P0 setting to
mtk_dp_initialize_aux_settings()
  drm/mediatek: dp: Enable event interrupt only when bridge attached
  drm/mediatek: dp: Avoid mutex locks if audio is not supported/enabled
  drm/mediatek: dp: Move PHY registration to new function
  drm/mediatek: dp: Add support for embedded DisplayPort aux-bus
  drm/mediatek: dp: Add .wait_hpd_asserted() for AUX bus
  drm/mediatek: dp: Don't register HPD interrupt handler for eDP case

 drivers/gpu/drm/mediatek/Kconfig  |   1 +
 drivers/gpu/drm/mediatek/mtk_dp.c | 335 --
 2 files changed, 224 insertions(+), 112 deletions(-)

-- 
2.40.1



[PATCH v5 01/10] drm/mediatek: dp: Move AUX and panel poweron/off sequence to function

2023-07-13 Thread AngeloGioacchino Del Regno
Everytime we run bridge detection and/or EDID read we run a poweron
and poweroff sequence for both the AUX and the panel; moreover, this
is also done when enabling the bridge in the .atomic_enable() callback.

Move this power on/off sequence to a new mtk_dp_aux_panel_poweron()
function as to commonize it.
Note that, before this commit, in mtk_dp_bridge_atomic_enable() only
the AUX was getting powered on but the panel was left powered off if
the DP cable wasn't plugged in while now we unconditionally send a D0
request and this is done for two reasons:
 - First, whether this request fails or not, it takes the same time
   and anyway the DP hardware won't produce any error (or, if it
   does, it's ignorable because it won't block further commands)
 - Second, training the link between a sleeping/standby/unpowered
   display makes little sense.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 76 ---
 1 file changed, 30 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 64eee77452c0..8b7ded1746f3 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1251,6 +1251,29 @@ static void mtk_dp_audio_mute(struct mtk_dp *mtk_dp, 
bool mute)
   val[2], AU_TS_CFG_DP_ENC0_P0_MASK);
 }
 
+static void mtk_dp_aux_panel_poweron(struct mtk_dp *mtk_dp, bool pwron)
+{
+   if (pwron) {
+   /* power on aux */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+  DP_PWR_STATE_BANDGAP_TPLL_LANE,
+  DP_PWR_STATE_MASK);
+
+   /* power on panel */
+   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+   usleep_range(2000, 5000);
+   } else {
+   /* power off panel */
+   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
+   usleep_range(2000, 3000);
+
+   /* power off aux */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+  DP_PWR_STATE_BANDGAP_TPLL,
+  DP_PWR_STATE_MASK);
+   }
+}
+
 static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 {
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
@@ -1936,16 +1959,9 @@ static enum drm_connector_status 
mtk_dp_bdg_detect(struct drm_bridge *bridge)
if (!mtk_dp->train_info.cable_plugged_in)
return ret;
 
-   if (!enabled) {
-   /* power on aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL_LANE,
-  DP_PWR_STATE_MASK);
+   if (!enabled)
+   mtk_dp_aux_panel_poweron(mtk_dp, true);
 
-   /* power on panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
-   usleep_range(2000, 5000);
-   }
/*
 * Some dongles still source HPD when they do not connect to any
 * sink device. To avoid this, we need to read the sink count
@@ -1957,16 +1973,8 @@ static enum drm_connector_status 
mtk_dp_bdg_detect(struct drm_bridge *bridge)
if (DP_GET_SINK_COUNT(sink_count))
ret = connector_status_connected;
 
-   if (!enabled) {
-   /* power off panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
-   usleep_range(2000, 3000);
-
-   /* power off aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL,
-  DP_PWR_STATE_MASK);
-   }
+   if (!enabled)
+   mtk_dp_aux_panel_poweron(mtk_dp, false);
 
return ret;
 }
@@ -1982,15 +1990,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
 
if (!enabled) {
drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
-
-   /* power on aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL_LANE,
-  DP_PWR_STATE_MASK);
-
-   /* power on panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
-   usleep_range(2000, 5000);
+   mtk_dp_aux_panel_poweron(mtk_dp, true);
}
 
new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
@@ -2010,15 +2010,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
}
 
if (!enabled) {
-   /* power off panel */
-   drm_dp_dpcd_writeb(&mtk_dp-&g

[PATCH v5 02/10] drm/mediatek: dp: Change logging to dev for mtk_dp_aux_transfer()

2023-07-13 Thread AngeloGioacchino Del Regno
Change logging from drm_{err,info}() to dev_{err,info}() in functions
mtk_dp_aux_transfer() and mtk_dp_aux_do_transfer(): this will be
essential to avoid getting NULL pointer kernel panics if any kind
of error happens during AUX transfers happening before the bridge
is attached.

This may potentially start happening in a later commit implementing
aux-bus support, as AUX transfers will be triggered from the panel
driver (for EDID) before the mtk-dp bridge gets attached, and it's
done in preparation for the same.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 8b7ded1746f3..a6a05ea6a53c 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -847,7 +847,7 @@ static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, 
bool is_read, u8 cmd,
u32 phy_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3628) &
 AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
-   drm_err(mtk_dp->drm_dev,
+   dev_err(mtk_dp->dev,
"AUX Rx Aux hang, need SW reset\n");
return -EIO;
}
@@ -2049,7 +2049,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux 
*mtk_aux,
is_read = true;
break;
default:
-   drm_err(mtk_aux->drm_dev, "invalid aux cmd = %d\n",
+   dev_err(mtk_dp->dev, "invalid aux cmd = %d\n",
msg->request);
ret = -EINVAL;
goto err;
@@ -2065,7 +2065,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux 
*mtk_aux,
 to_access, &msg->reply);
 
if (ret) {
-   drm_info(mtk_dp->drm_dev,
+   dev_info(mtk_dp->dev,
 "Failed to do AUX transfer: %d\n", ret);
goto err;
}
-- 
2.40.1



Re: [PATCH 0/4] drm/mediatek: Small mtk-dpi cleanups

2023-07-13 Thread AngeloGioacchino Del Regno

Il 12/04/23 13:52, AngeloGioacchino Del Regno ha scritto:

This is a small cleanup of the mtk-dpi driver, switching it to devm
variants where possible and where it made sense, and reducing lines
while retaining and improving human readability.

AngeloGioacchino Del Regno (4):
   drm/mediatek: mtk_dpi: Simplify with devm_drm_bridge_add()
   drm/mediatek: mtk_dpi: Simplify with dev_err_probe()
   drm/mediatek: mtk_dpi: Switch to devm_drm_of_get_bridge()
   drm/mediatek: mtk_dpi: Use devm_platform_get_and_ioremap_resource()

  drivers/gpu/drm/mediatek/mtk_dpi.c | 59 +++---
  1 file changed, 21 insertions(+), 38 deletions(-)



Ping for a fully ready and well tested series that I've sent *3 months* ago.

Thanks,
Angelo


Re: [PATCH] phy: phy-mtk-dp: Fix an error code in probe()

2023-07-11 Thread AngeloGioacchino Del Regno

Il 11/07/23 08:13, Dan Carpenter ha scritto:

Negative -EINVAL was intended instead of positive EINVAL.

Fixes: 6a23afad443a ("phy: phy-mtk-dp: Add driver for DP phy")
Signed-off-by: Dan Carpenter 


Reviewed-by: AngeloGioacchino Del Regno 





Re: [PATCH v3 2/2] drm/mediatek: Fix iommu fault during crtc enabling

2023-07-10 Thread AngeloGioacchino Del Regno

Il 10/07/23 11:32, Jason-JH.Lin ha scritto:

OVL layer should not be enabled before crtc is enabled.
The plane_state of drm_atomic_state is not sync to
the plane_state stored in mtk_crtc during crtc enabling,
so just set all planes to disabled.

Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.")
Signed-off-by: Jason-JH.Lin 


Reviewed-by: AngeloGioacchino Del Regno 



---
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..51d10e65004e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -410,6 +410,9 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc 
*mtk_crtc)
unsigned int local_layer;
  
  		plane_state = to_mtk_plane_state(plane->state);

+
+   /* should not enable layer before crtc enabled */
+   plane_state->pending.enable = false;
comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
if (comp)
mtk_ddp_comp_layer_config(comp, local_layer,




Re: [PATCH v2 2/2] drm/mediatek: Fix iommu fault during crtc enabling

2023-07-10 Thread AngeloGioacchino Del Regno

Il 09/07/23 18:26, Jason-JH.Lin ha scritto:

OVL layer should not be enabled before crtc is enabled.
The plane_state of drm_atomic_state is not sync to
the plane_state stored in mtk_crtc during crtc enabling,
so just set all planes to disabled.



Please add the relevant Fixes tag and resend.

Thanks,
Angelo


Signed-off-by: Jason-JH.Lin  > ---
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..51d10e65004e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -410,6 +410,9 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc 
*mtk_crtc)
unsigned int local_layer;
  
  		plane_state = to_mtk_plane_state(plane->state);

+
+   /* should not enable layer before crtc enabled */
+   plane_state->pending.enable = false;
comp = mtk_drm_ddp_comp_for_plane(crtc, plane, &local_layer);
if (comp)
mtk_ddp_comp_layer_config(comp, local_layer,




Re: [PATCH v2 1/2] drm/mediatek: Fix iommu fault by swapping FBs after updating plane state

2023-07-10 Thread AngeloGioacchino Del Regno

Il 09/07/23 18:26, Jason-JH.Lin ha scritto:

According to the comment in drm_atomic_helper_async_commit(),
we should make sure FBs have been swapped, so that cleanups in the
new_state performs a cleanup in the old FB.

So we should move swapping FBs after calling mtk_plane_update_new_state(),
to avoid using the old FB which could be freed.

Fixes: 1a64a7aff8da ("drm/mediatek: Fix cursor plane no update")
Signed-off-by: Jason-JH.Lin 


Reviewed-by: AngeloGioacchino Del Regno 





Re: [PATCH v4 0/9] MediaTek DisplayPort: support eDP and aux-bus

2023-07-10 Thread AngeloGioacchino Del Regno

Il 07/07/23 10:23, Chen-Yu Tsai ha scritto:

On Thu, Jul 6, 2023 at 8:30 PM AngeloGioacchino Del Regno
 wrote:


Changes in v4:
  - Set data lanes to idle to prevent stalls if bootloader didn't
properly close the eDP port
  - Now using the .done_probing() callback for AUX bus to prevent
probe deferral loops in case the panel-edp driver is a module
as previously seen with another bridge driver (ANX7625) on
some other SoCs (MT8192 and others)
  - Rebased over next-20230706
  - Dropped Chen-Yu's T-b tag on last patch as some logic changed
(before, I wasn't using the .done_probing() callback).

Changes in v3:
  - Added DPTX AUX block initialization before trying to communicate
to stop relying on the bootloader keeping it initialized before
booting Linux.
  - Fixed commit description for patch [09/09] and removed commented
out code (that slipped from dev phase.. sorry!).

This series adds "real" support for eDP in the mtk-dp DisplayPort driver.

Explaining the "real":
Before this change, the DisplayPort driver did support eDP to some
extent, but it was treating it entirely like a regular DP interface
which is partially fine, after all, embedded DisplayPort *is* actually
DisplayPort, but there might be some differences to account for... and
this is for both small performance improvements and, more importantly,
for correct functionality in some systems.

Functionality first:

One of the common differences found in various boards implementing eDP
and machines using an eDP panel is that many times the HPD line is not
connected. This *must* be accounted for: at startup, this specific IP
will raise a HPD interrupt (which should maybe be ignored... as it does
not appear to be a "real" event...) that will make the eDP panel to be
detected and to actually work but, after a suspend-resume cycle, there
will be no HPD interrupt (as there's no HPD line in my case!) producing
a functionality issue - specifically, the DP Link Training fails because
the panel doesn't get powered up, then it stays black and won't work
until rebooting the machine (or removing and reinserting the module I
think, but I haven't tried that).

Now for.. both:
eDP panels are *e*DP because they are *not* removable (in the sense that
you can't unplug the cable without disassembling the machine, in which
case, the machine shall be powered down..!): this (correct) assumption
makes us able to solve some issues and to also gain a little performance
during PM operations.

What was done here is:
  - Caching the EDID if the panel is eDP: we're always going to read the
same data everytime, so we can just cache that (as it's small enough)
shortening PM resume times for the eDP driver instance;
  - Always return connector_status_connected if it's eDP: non-removable
means connector_status_disconnected can't happen during runtime...
this also saves us some time and even power, as we won't have to
perform yet another power cycle of the HW;
  - Added aux-bus support!
This makes us able to rely on panel autodetection from the EDID,
avoiding to add more and more panel timings to panel-edp and, even
better, allowing to use one panel node in devicetrees for multiple
variants of the same machine since, at that point, it's not important
to "preventively know" what panel we have (eh, it's autodetected...!).

This was tested on a MT8195 Cherry Tomato Chromebook (panel-edp on aux-bus)


Do you have panel-edp built as a module? If I have it built in, the panel
can correctly display stuff. If I have it built as a module, the panel is
correctly detected, but the panel stays black even if DRM thinks it is
displaying stuff.



I tested both. I'll recheck on a clean tree just to be sure...


And it looks like EDID reading and panel power sequencing is still not
working correctly, i.e. needs regulator-always-on?


Yeah that's still needed with this version, I'm still trying to get *at least*
some support upstreamed before refining it.

Cheers,
Angelo



ChenYu


P.S.: For your own testing commodity, here's a reference devicetree:
&edp_tx {
 status = "okay";

 pinctrl-names = "default";
 pinctrl-0 = <&edptx_pins_default>;

 ports {
 #address-cells = <1>;
 #size-cells = <0>;

 port@0 {
 reg = <0>;
 edp_in: endpoint {
 remote-endpoint = <&dp_intf0_out>;
 };
 };

 port@1 {
 reg = <1>;
 edp_out: endpoint {
 data-lanes = <0 1 2 3>;
 remote-endpoint = <&panel_in>;

Re: [PATCH] drm/mediatek: Fix potential memory leak if vmap() fail

2023-07-06 Thread AngeloGioacchino Del Regno

Il 26/06/23 20:58, Sui Jingfeng ha scritto:

Also return -ENOMEM if such a failure happens, the implement should take
responsibility for the error handling.

Signed-off-by: Sui Jingfeng 


This commit needs a Fixes tag. Please add the relevant one and resend.

Thanks,
Angelo


---
  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 6 +-
  1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index a25b28d3ee90..9f364df52478 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -247,7 +247,11 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object *obj, 
struct iosys_map *map)
  
  	mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,

   pgprot_writecombine(PAGE_KERNEL));
-
+   if (!mtk_gem->kvaddr) {
+   kfree(sgt);
+   kfree(mtk_gem->pages);
+   return -ENOMEM;
+   }
  out:
kfree(sgt);
iosys_map_set_vaddr(map, mtk_gem->kvaddr);






[PATCH v4 9/9] drm/mediatek: dp: Add support for embedded DisplayPort aux-bus

2023-07-06 Thread AngeloGioacchino Del Regno
For the eDP case we can support using aux-bus on MediaTek DP: this
gives us the possibility to declare our panel as generic "panel-edp"
which will automatically configure the timings and available modes
via the EDID that we read from it.

To do this, move the panel parsing at the end of the probe function
so that the hardware is initialized beforehand and also initialize
the DPTX AUX block and power both on as, when we populate the
aux-bus, the panel driver will trigger an EDID read to perform
panel detection.

Last but not least, since now the AUX transfers can happen in the
separated aux-bus, it was necessary to add an exclusion for the
cable_plugged_in check in `mtk_dp_aux_transfer()` and the easiest
way to do this is to simply ignore checking that when the bridge
type is eDP.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dp.c | 72 ++-
 1 file changed, 62 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 2ad836fbb7c4..16109d5ca5ae 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -4,6 +4,7 @@
  * Copyright (c) 2022 BayLibre
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -2042,7 +2043,8 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux 
*mtk_aux,
 
mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
 
-   if (!mtk_dp->train_info.cable_plugged_in) {
+   if (mtk_dp->bridge.type != DRM_MODE_CONNECTOR_eDP &&
+   !mtk_dp->train_info.cable_plugged_in) {
ret = -EAGAIN;
goto err;
}
@@ -2153,6 +2155,11 @@ static int mtk_dp_bridge_attach(struct drm_bridge 
*bridge,
enable_irq(mtk_dp->irq);
mtk_dp_hwirq_enable(mtk_dp, true);
 
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
+   mtk_dp->train_info.cable_plugged_in = true;
+   drm_helper_hpd_irq_event(mtk_dp->drm_dev);
+   }
+
return 0;
 
 err_bridge_attach:
@@ -2482,6 +2489,25 @@ static int mtk_dp_register_audio_driver(struct device 
*dev)
return PTR_ERR_OR_ZERO(mtk_dp->audio_pdev);
 }
 
+static int mtk_dp_edp_link_panel(struct drm_dp_aux *mtk_aux)
+{
+   struct mtk_dp *mtk_dp = container_of(mtk_aux, struct mtk_dp, aux);
+   struct device *dev = mtk_aux->dev;
+   struct drm_bridge *panel_aux_bridge;
+
+   panel_aux_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+
+   /* Power off the DP: either detection is done, or no panel present */
+   mtk_dp_aux_panel_poweron(mtk_dp, false);
+   mtk_dp_power_disable(mtk_dp);
+
+   if (IS_ERR(panel_aux_bridge))
+   return PTR_ERR(panel_aux_bridge);
+
+   mtk_dp->next_bridge = panel_aux_bridge;
+   return 0;
+}
+
 static int mtk_dp_probe(struct platform_device *pdev)
 {
struct mtk_dp *mtk_dp;
@@ -2500,21 +2526,14 @@ static int mtk_dp_probe(struct platform_device *pdev)
return dev_err_probe(dev, mtk_dp->irq,
 "failed to request dp irq resource\n");
 
-   mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
-   if (IS_ERR(mtk_dp->next_bridge) &&
-   PTR_ERR(mtk_dp->next_bridge) == -ENODEV)
-   mtk_dp->next_bridge = NULL;
-   else if (IS_ERR(mtk_dp->next_bridge))
-   return dev_err_probe(dev, PTR_ERR(mtk_dp->next_bridge),
-"Failed to get bridge\n");
-
ret = mtk_dp_dt_parse(mtk_dp, pdev);
if (ret)
return dev_err_probe(dev, ret, "Failed to parse dt\n");
 
-   drm_dp_aux_init(&mtk_dp->aux);
mtk_dp->aux.name = "aux_mtk_dp";
+   mtk_dp->aux.dev = dev;
mtk_dp->aux.transfer = mtk_dp_aux_transfer;
+   drm_dp_aux_init(&mtk_dp->aux);
 
spin_lock_init(&mtk_dp->irq_thread_lock);
 
@@ -2570,6 +2589,39 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->need_debounce = true;
timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
 
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP) {
+   /*
+* Set the data lanes to idle in case the bootloader didn't
+* properly close the eDP port to avoid stalls and then
+* reinitialize, reset and power on the AUX block.
+*/
+   mtk_dp_set_idle_pattern(mtk_dp, true);
+   mtk_dp_initialize_aux_settings(mtk_dp);
+   mtk_dp_power_enable(mtk_dp);
+
+   /*
+* Power on the panel to allow reading the EDID from aux-bus:
+* please note that it is necessary to call power off in the
+* .done_probing() callback (mtk_dp_edp_

[PATCH v4 2/9] drm/mediatek: dp: Move AUX and panel poweron/off sequence to function

2023-07-06 Thread AngeloGioacchino Del Regno
Everytime we run bridge detection and/or EDID read we run a poweron
and poweroff sequence for both the AUX and the panel; moreover, this
is also done when enabling the bridge in the .atomic_enable() callback.

Move this power on/off sequence to a new mtk_dp_aux_panel_poweron()
function as to commonize it.
Note that, before this commit, in mtk_dp_bridge_atomic_enable() only
the AUX was getting powered on but the panel was left powered off if
the DP cable wasn't plugged in while now we unconditionally send a D0
request and this is done for two reasons:
 - First, whether this request fails or not, it takes the same time
   and anyway the DP hardware won't produce any error (or, if it
   does, it's ignorable because it won't block further commands)
 - Second, training the link between a sleeping/standby/unpowered
   display makes little sense.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 76 ---
 1 file changed, 30 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index fdf5b7686884..8f7d4af7076f 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1252,6 +1252,29 @@ static void mtk_dp_audio_mute(struct mtk_dp *mtk_dp, 
bool mute)
   val[2], AU_TS_CFG_DP_ENC0_P0_MASK);
 }
 
+static void mtk_dp_aux_panel_poweron(struct mtk_dp *mtk_dp, bool pwron)
+{
+   if (pwron) {
+   /* power on aux */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+  DP_PWR_STATE_BANDGAP_TPLL_LANE,
+  DP_PWR_STATE_MASK);
+
+   /* power on panel */
+   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+   usleep_range(2000, 5000);
+   } else {
+   /* power off panel */
+   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
+   usleep_range(2000, 3000);
+
+   /* power off aux */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
+  DP_PWR_STATE_BANDGAP_TPLL,
+  DP_PWR_STATE_MASK);
+   }
+}
+
 static void mtk_dp_power_enable(struct mtk_dp *mtk_dp)
 {
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_RESET_AND_PROBE,
@@ -1937,16 +1960,9 @@ static enum drm_connector_status 
mtk_dp_bdg_detect(struct drm_bridge *bridge)
if (!mtk_dp->train_info.cable_plugged_in)
return ret;
 
-   if (!enabled) {
-   /* power on aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL_LANE,
-  DP_PWR_STATE_MASK);
+   if (!enabled)
+   mtk_dp_aux_panel_poweron(mtk_dp, true);
 
-   /* power on panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
-   usleep_range(2000, 5000);
-   }
/*
 * Some dongles still source HPD when they do not connect to any
 * sink device. To avoid this, we need to read the sink count
@@ -1958,16 +1974,8 @@ static enum drm_connector_status 
mtk_dp_bdg_detect(struct drm_bridge *bridge)
if (DP_GET_SINK_COUNT(sink_count))
ret = connector_status_connected;
 
-   if (!enabled) {
-   /* power off panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3);
-   usleep_range(2000, 3000);
-
-   /* power off aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL,
-  DP_PWR_STATE_MASK);
-   }
+   if (!enabled)
+   mtk_dp_aux_panel_poweron(mtk_dp, false);
 
return ret;
 }
@@ -1983,15 +1991,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
 
if (!enabled) {
drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
-
-   /* power on aux */
-   mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
-  DP_PWR_STATE_BANDGAP_TPLL_LANE,
-  DP_PWR_STATE_MASK);
-
-   /* power on panel */
-   drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
-   usleep_range(2000, 5000);
+   mtk_dp_aux_panel_poweron(mtk_dp, true);
}
 
/* eDP panels aren't removable, so we can return a cached EDID. */
@@ -2015,15 +2015,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
}
 
if (!enabled) {
-   /* power off panel */
-   drm_dp_dpcd_writeb(&mtk_dp->

[PATCH v4 7/9] drm/mediatek: dp: Use devm variant of drm_bridge_add()

2023-07-06 Thread AngeloGioacchino Del Regno
In preparation for adding support for aux-bus, which will add a code
path that may fail after the drm_bridge_add() call, change that to
devm_drm_bridge_add() to simplify failure paths later.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index eebcb32e67ee..6bc620aded45 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2564,7 +2564,7 @@ static int mtk_dp_probe(struct platform_device *pdev)
DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
mtk_dp->bridge.type = mtk_dp->data->bridge_type;
 
-   drm_bridge_add(&mtk_dp->bridge);
+   devm_drm_bridge_add(dev, &mtk_dp->bridge);
 
mtk_dp->need_debounce = true;
timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0);
-- 
2.40.1



[PATCH v4 6/9] drm/mediatek: dp: Enable event interrupt only when bridge attached

2023-07-06 Thread AngeloGioacchino Del Regno
In preparation for implementing support for aux-bus in this driver,
add a IRQ_NOAUTOEN flag to the event interrupt that we request at
probe time and manage the enablement of the ISR at bridge_attach
and detach time.

When aux-bus will be implemented, enabling the interrupt before
attaching the bridge will create an event storm and hang the kernel
during boot.
In any case, the interrupt handler anyway requires resources that
are initialized by mtk_dp_bridge_attach(), so it cannot do anything
meaningful without... and even crash, but that's not happening in
the current code because the HW remains unpowered until resources
are made available.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 274119356dfb..eebcb32e67ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -100,6 +100,7 @@ struct mtk_dp_efuse_fmt {
 struct mtk_dp {
bool enabled;
bool need_debounce;
+   int irq;
u8 max_lanes;
u8 max_linkrate;
u8 rx_cap[DP_RECEIVER_CAP_SIZE];
@@ -2147,6 +2148,8 @@ static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
 
mtk_dp->drm_dev = bridge->dev;
 
+   irq_clear_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   enable_irq(mtk_dp->irq);
mtk_dp_hwirq_enable(mtk_dp, true);
 
return 0;
@@ -2163,6 +2166,7 @@ static void mtk_dp_bridge_detach(struct drm_bridge 
*bridge)
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
 
mtk_dp_hwirq_enable(mtk_dp, false);
+   disable_irq(mtk_dp->irq);
mtk_dp->drm_dev = NULL;
mtk_dp_poweroff(mtk_dp);
drm_dp_aux_unregister(&mtk_dp->aux);
@@ -2481,7 +2485,7 @@ static int mtk_dp_probe(struct platform_device *pdev)
 {
struct mtk_dp *mtk_dp;
struct device *dev = &pdev->dev;
-   int ret, irq_num;
+   int ret;
 
mtk_dp = devm_kzalloc(dev, sizeof(*mtk_dp), GFP_KERNEL);
if (!mtk_dp)
@@ -2490,9 +2494,9 @@ static int mtk_dp_probe(struct platform_device *pdev)
mtk_dp->dev = dev;
mtk_dp->data = (struct mtk_dp_data *)of_device_get_match_data(dev);
 
-   irq_num = platform_get_irq(pdev, 0);
-   if (irq_num < 0)
-   return dev_err_probe(dev, irq_num,
+   mtk_dp->irq = platform_get_irq(pdev, 0);
+   if (mtk_dp->irq < 0)
+   return dev_err_probe(dev, mtk_dp->irq,
 "failed to request dp irq resource\n");
 
mtk_dp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
@@ -2513,7 +2517,8 @@ static int mtk_dp_probe(struct platform_device *pdev)
 
spin_lock_init(&mtk_dp->irq_thread_lock);
 
-   ret = devm_request_threaded_irq(dev, irq_num, mtk_dp_hpd_event,
+   irq_set_status_flags(mtk_dp->irq, IRQ_NOAUTOEN);
+   ret = devm_request_threaded_irq(dev, mtk_dp->irq, mtk_dp_hpd_event,
mtk_dp_hpd_event_thread,
IRQ_TYPE_LEVEL_HIGH, dev_name(dev),
mtk_dp);
-- 
2.40.1



[PATCH v4 4/9] drm/mediatek: dp: Always set cable_plugged_in at resume for eDP panel

2023-07-06 Thread AngeloGioacchino Del Regno
eDP panels are not removable: at PM resume, the cable will obviously
still be plugged in.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 5b35a2e23896..35f3549d258e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2606,6 +2606,9 @@ static int mtk_dp_resume(struct device *dev)
mtk_dp_hwirq_enable(mtk_dp, true);
mtk_dp_power_enable(mtk_dp);
 
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP)
+   mtk_dp->train_info.cable_plugged_in = true;
+
return 0;
 }
 #endif
-- 
2.40.1



[PATCH v4 8/9] drm/mediatek: dp: Move AUX_P0 setting to mtk_dp_initialize_aux_settings()

2023-07-06 Thread AngeloGioacchino Del Regno
Move the register write to MTK_DP_AUX_P0_3690 to set the AUX reply mode
to function mtk_dp_initialize_aux_settings(), as this is effectively
part of the DPTX AUX setup sequence.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 6bc620aded45..2ad836fbb7c4 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1011,6 +1011,11 @@ static void mtk_dp_initialize_aux_settings(struct mtk_dp 
*mtk_dp)
mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_37C8,
   MTK_ATOP_EN_AUX_TX_P0,
   MTK_ATOP_EN_AUX_TX_P0);
+
+   /* Set complete reply mode for AUX */
+   mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
+  RX_REPLY_COMPLETE_MODE_AUX_TX_P0,
+  RX_REPLY_COMPLETE_MODE_AUX_TX_P0);
 }
 
 static void mtk_dp_initialize_digital_settings(struct mtk_dp *mtk_dp)
@@ -1823,10 +1828,6 @@ static void mtk_dp_init_port(struct mtk_dp *mtk_dp)
mtk_dp_initialize_settings(mtk_dp);
mtk_dp_initialize_aux_settings(mtk_dp);
mtk_dp_initialize_digital_settings(mtk_dp);
-
-   mtk_dp_update_bits(mtk_dp, MTK_DP_AUX_P0_3690,
-  RX_REPLY_COMPLETE_MODE_AUX_TX_P0,
-  RX_REPLY_COMPLETE_MODE_AUX_TX_P0);
mtk_dp_initialize_hpd_detect_settings(mtk_dp);
 
mtk_dp_digital_sw_reset(mtk_dp);
-- 
2.40.1



[PATCH v4 5/9] drm/mediatek: dp: Change logging to dev for mtk_dp_aux_transfer()

2023-07-06 Thread AngeloGioacchino Del Regno
Change logging from drm_{err,info}() to dev_{err,info}() in functions
mtk_dp_aux_transfer() and mtk_dp_aux_do_transfer(): this will be
essential to avoid getting NULL pointer kernel panics if any kind
of error happens during AUX transfers happening before the bridge
is attached.

This may potentially start happening in a later commit implementing
aux-bus support, as AUX transfers will be triggered from the panel
driver (for EDID) before the mtk-dp bridge gets attached, and it's
done in preparation for the same.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 35f3549d258e..274119356dfb 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -848,7 +848,7 @@ static int mtk_dp_aux_do_transfer(struct mtk_dp *mtk_dp, 
bool is_read, u8 cmd,
u32 phy_status = mtk_dp_read(mtk_dp, MTK_DP_AUX_P0_3628) &
 AUX_RX_PHY_STATE_AUX_TX_P0_MASK;
if (phy_status != AUX_RX_PHY_STATE_AUX_TX_P0_RX_IDLE) {
-   drm_err(mtk_dp->drm_dev,
+   dev_err(mtk_dp->dev,
"AUX Rx Aux hang, need SW reset\n");
return -EIO;
}
@@ -2061,7 +2061,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux 
*mtk_aux,
is_read = true;
break;
default:
-   drm_err(mtk_aux->drm_dev, "invalid aux cmd = %d\n",
+   dev_err(mtk_dp->dev, "invalid aux cmd = %d\n",
msg->request);
ret = -EINVAL;
goto err;
@@ -2077,7 +2077,7 @@ static ssize_t mtk_dp_aux_transfer(struct drm_dp_aux 
*mtk_aux,
 to_access, &msg->reply);
 
if (ret) {
-   drm_info(mtk_dp->drm_dev,
+   dev_info(mtk_dp->dev,
 "Failed to do AUX transfer: %d\n", ret);
goto err;
}
-- 
2.40.1



[PATCH v4 3/9] drm/mediatek: dp: Always return connected status for eDP in .detect()

2023-07-06 Thread AngeloGioacchino Del Regno
If this is an eDP panel it's not removable, hence it's always connected:
as a shortcut, always return connector_status_connected in the .detect()
callback for eDP connector, avoiding a poweron, a check for sink count
and a poweroff.

Signed-off-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 8f7d4af7076f..5b35a2e23896 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1957,6 +1957,9 @@ static enum drm_connector_status mtk_dp_bdg_detect(struct 
drm_bridge *bridge)
bool enabled = mtk_dp->enabled;
u8 sink_count = 0;
 
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP)
+   return connector_status_connected;
+
if (!mtk_dp->train_info.cable_plugged_in)
return ret;
 
-- 
2.40.1



[PATCH v4 0/9] MediaTek DisplayPort: support eDP and aux-bus

2023-07-06 Thread AngeloGioacchino Del Regno
Changes in v4:
 - Set data lanes to idle to prevent stalls if bootloader didn't
   properly close the eDP port
 - Now using the .done_probing() callback for AUX bus to prevent
   probe deferral loops in case the panel-edp driver is a module
   as previously seen with another bridge driver (ANX7625) on
   some other SoCs (MT8192 and others)
 - Rebased over next-20230706
 - Dropped Chen-Yu's T-b tag on last patch as some logic changed
   (before, I wasn't using the .done_probing() callback).

Changes in v3:
 - Added DPTX AUX block initialization before trying to communicate
   to stop relying on the bootloader keeping it initialized before
   booting Linux.
 - Fixed commit description for patch [09/09] and removed commented
   out code (that slipped from dev phase.. sorry!).

This series adds "real" support for eDP in the mtk-dp DisplayPort driver.

Explaining the "real":
Before this change, the DisplayPort driver did support eDP to some
extent, but it was treating it entirely like a regular DP interface
which is partially fine, after all, embedded DisplayPort *is* actually
DisplayPort, but there might be some differences to account for... and
this is for both small performance improvements and, more importantly,
for correct functionality in some systems.

Functionality first:

One of the common differences found in various boards implementing eDP
and machines using an eDP panel is that many times the HPD line is not
connected. This *must* be accounted for: at startup, this specific IP
will raise a HPD interrupt (which should maybe be ignored... as it does
not appear to be a "real" event...) that will make the eDP panel to be
detected and to actually work but, after a suspend-resume cycle, there
will be no HPD interrupt (as there's no HPD line in my case!) producing
a functionality issue - specifically, the DP Link Training fails because
the panel doesn't get powered up, then it stays black and won't work
until rebooting the machine (or removing and reinserting the module I
think, but I haven't tried that).

Now for.. both:
eDP panels are *e*DP because they are *not* removable (in the sense that
you can't unplug the cable without disassembling the machine, in which
case, the machine shall be powered down..!): this (correct) assumption
makes us able to solve some issues and to also gain a little performance
during PM operations.

What was done here is:
 - Caching the EDID if the panel is eDP: we're always going to read the
   same data everytime, so we can just cache that (as it's small enough)
   shortening PM resume times for the eDP driver instance;
 - Always return connector_status_connected if it's eDP: non-removable
   means connector_status_disconnected can't happen during runtime...
   this also saves us some time and even power, as we won't have to
   perform yet another power cycle of the HW;
 - Added aux-bus support!
   This makes us able to rely on panel autodetection from the EDID,
   avoiding to add more and more panel timings to panel-edp and, even
   better, allowing to use one panel node in devicetrees for multiple
   variants of the same machine since, at that point, it's not important
   to "preventively know" what panel we have (eh, it's autodetected...!).

This was tested on a MT8195 Cherry Tomato Chromebook (panel-edp on aux-bus)


P.S.: For your own testing commodity, here's a reference devicetree:
&edp_tx {
status = "okay";

pinctrl-names = "default";
pinctrl-0 = <&edptx_pins_default>;

ports {
#address-cells = <1>;
#size-cells = <0>;

port@0 {
reg = <0>;
edp_in: endpoint {
remote-endpoint = <&dp_intf0_out>;
};
};

port@1 {
reg = <1>;
edp_out: endpoint {
data-lanes = <0 1 2 3>;
remote-endpoint = <&panel_in>;
};
};
};

aux-bus {
panel: panel {
compatible = "edp-panel";
power-supply = <&pp3300_disp_x>;
backlight = <&backlight_lcd0>;
    port {
        panel_in: endpoint {
remote-endpoint = <&edp_out>;
};
};
};
};
};


AngeloGioacchino Del Regno (9):
  drm/mediatek: dp: Cache EDID for eDP panel
  drm/mediatek: dp: Move AUX and panel poweron/off sequence to function
  drm/mediatek: dp: Always return connected status for eDP i

[PATCH v4 1/9] drm/mediatek: dp: Cache EDID for eDP panel

2023-07-06 Thread AngeloGioacchino Del Regno
Since eDP panels are not removable it is safe to cache the EDID:
this will avoid a relatively long read transaction at every PM
resume that is unnecessary only in the "special" case of eDP,
hence speeding it up a little, as from now on, as resume operation,
we will perform only link training.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Matthias Brugger 
Tested-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 64eee77452c0..fdf5b7686884 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -118,6 +118,7 @@ struct mtk_dp {
const struct mtk_dp_data *data;
struct mtk_dp_info info;
struct mtk_dp_train_info train_info;
+   struct edid *edid;
 
struct platform_device *phy_dev;
struct phy *phy;
@@ -1993,7 +1994,11 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
usleep_range(2000, 5000);
}
 
-   new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
+   /* eDP panels aren't removable, so we can return a cached EDID. */
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP && mtk_dp->edid)
+   new_edid = drm_edid_duplicate(mtk_dp->edid);
+   else
+   new_edid = drm_get_edid(connector, &mtk_dp->aux.ddc);
 
/*
 * Parse capability here to let atomic_get_input_bus_fmts and
@@ -2022,6 +2027,10 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
}
 
+   /* If this is an eDP panel and the read EDID is good, cache it for 
later */
+   if (mtk_dp->bridge.type == DRM_MODE_CONNECTOR_eDP && !mtk_dp->edid && 
new_edid)
+   mtk_dp->edid = drm_edid_duplicate(new_edid);
+
return new_edid;
 }
 
-- 
2.40.1



Re: [PATCH v2,2/2] drm/mediatek: dp: Add the audio control to mtk_dp_data struct

2023-07-06 Thread AngeloGioacchino Del Regno

Il 06/07/23 04:14, Shuijing Li ha scritto:

Mainly add the following two flag:

1.The audio packet arrangement function is to only arrange audio
packets into the Hblanking area. In order to align with the HW
default setting of g1200, this function needs to be turned off.

2.Due to the difference of HW, different dividers need to be set.

Signed-off-by: Shuijing Li 
Signed-off-by: Jitao Shi 
---
Changes in v2:
- change the variables' name to be more descriptive
- add a comment that describes the function of mtk_dp_audio_sample_arrange
- reduce indentation by doing the inverse check
- add a definition of some bits
- add support for mediatek, mt8188-edp-tx
per suggestion from the previous thread:
https://lore.kernel.org/lkml/ac0fcec9-a2fe-06cc-c727-189ef7bab...@collabora.com/
---
  drivers/gpu/drm/mediatek/mtk_dp.c | 47 ++-
  drivers/gpu/drm/mediatek/mtk_dp_reg.h |  6 
  2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 64eee77452c0..8e1a13ab2ba2 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -139,6 +139,8 @@ struct mtk_dp_data {
unsigned int smc_cmd;
const struct mtk_dp_efuse_fmt *efuse_fmt;
bool audio_supported;
+   bool audio_pkt_in_hblank_area;
+   u16 audio_m_div2_bit;
  };
  
  static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = {

@@ -647,7 +649,7 @@ static void mtk_dp_audio_sdp_asp_set_channels(struct mtk_dp 
*mtk_dp,
  static void mtk_dp_audio_set_divider(struct mtk_dp *mtk_dp)
  {
mtk_dp_update_bits(mtk_dp, MTK_DP_ENC0_P0_30BC,
-  AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+  mtk_dp->data->audio_m_div2_bit,
   AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_MASK);
  }
  
@@ -1362,6 +1364,18 @@ static void mtk_dp_sdp_set_down_cnt_init_in_hblank(struct mtk_dp *mtk_dp)

   SDP_DOWN_CNT_INIT_IN_HBLANK_DP_ENC1_P0_MASK);
  }
  
+static void mtk_dp_audio_sample_arrange(struct mtk_dp *mtk_dp)

+{
+   /* arrange audio packets into the Hblanking and Vblanking area */
+   if (!mtk_dp->data->audio_pkt_in_hblank_area)
+   return;


There's only one remaining question: why is this done for MT8188 but *not* for
MT8195?

Thanks,
Angelo


+
+   mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3374, 0,
+  SDP_ASP_INSERT_IN_HBLANK_DP_ENC1_P0_MASK);
+   mtk_dp_update_bits(mtk_dp, MTK_DP_ENC1_P0_3374, 0,
+  SDP_DOWN_ASP_CNT_INIT_DP_ENC1_P0_MASK);
+}
+
  static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
  {
u32 sram_read_start = min_t(u32, MTK_DP_TBC_BUF_READ_START_ADDR,
@@ -1371,6 +1385,7 @@ static void mtk_dp_setup_tu(struct mtk_dp *mtk_dp)
MTK_DP_PIX_PER_ADDR);
mtk_dp_set_sram_read_start(mtk_dp, sram_read_start);
mtk_dp_setup_encoder(mtk_dp);
+   mtk_dp_audio_sample_arrange(mtk_dp);
mtk_dp_sdp_set_down_cnt_init_in_hblank(mtk_dp);
mtk_dp_sdp_set_down_cnt_init(mtk_dp, sram_read_start);
  }
@@ -2616,11 +2631,31 @@ static int mtk_dp_resume(struct device *dev)
  
  static SIMPLE_DEV_PM_OPS(mtk_dp_pm_ops, mtk_dp_suspend, mtk_dp_resume);
  
+static const struct mtk_dp_data mt8188_edp_data = {

+   .bridge_type = DRM_MODE_CONNECTOR_eDP,
+   .smc_cmd = MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE,
+   .efuse_fmt = mt8195_edp_efuse_fmt,
+   .audio_supported = false,
+   .audio_pkt_in_hblank_area = false,
+   .audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+};
+
+static const struct mtk_dp_data mt8188_dp_data = {
+   .bridge_type = DRM_MODE_CONNECTOR_DisplayPort,
+   .smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE,
+   .efuse_fmt = mt8195_dp_efuse_fmt,
+   .audio_supported = true,
+   .audio_pkt_in_hblank_area = true,
+   .audio_m_div2_bit = MT8188_AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
+};
+
  static const struct mtk_dp_data mt8195_edp_data = {
.bridge_type = DRM_MODE_CONNECTOR_eDP,
.smc_cmd = MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE,
.efuse_fmt = mt8195_edp_efuse_fmt,
.audio_supported = false,
+   .audio_pkt_in_hblank_area = false,
+   .audio_m_div2_bit = AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
  };
  
  static const struct mtk_dp_data mt8195_dp_data = {

@@ -2628,9 +2663,19 @@ static const struct mtk_dp_data mt8195_dp_data = {
.smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE,
.efuse_fmt = mt8195_dp_efuse_fmt,
.audio_supported = true,
+   .audio_pkt_in_hblank_area = false,
+   .audio_m_div2_bit = AUDIO_M_CODE_MULT_DIV_SEL_DP_ENC0_P0_DIV_2,
  };
  
  static const struct of_device_id mtk_dp_of_match[] = {

+   {
+   .compatible = "mediatek,mt8188-edp-tx",
+   .data = &mt8188_edp_data,
+   },
+   {
+   .compatible = 

Re: [PATCH v2, 1/2] dt-bindings: display: mediatek: dp: Add compatible for MediaTek MT8188

2023-07-06 Thread AngeloGioacchino Del Regno

Il 06/07/23 04:14, Shuijing Li ha scritto:

Add dt-binding documentation of dp-tx for MediaTek MT8188 SoC.

Signed-off-by: Shuijing Li 
Signed-off-by: Jitao Shi 


Reviewed-by: AngeloGioacchino Del Regno 





[PATCH v2 2/3] drm/mediatek: Use dev_err_probe() in probe functions

2023-07-05 Thread AngeloGioacchino Del Regno
Convert all instances of dev_err() -> return to dev_err_probe() and
where it makes sense to, change instances of `return ret` at the end
of probe functions to `return 0`, as errors are returned earlier.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Alexandre Mergnat 
Reviewed-by: CK Hu 
---
 drivers/gpu/drm/mediatek/mtk_cec.c| 26 +
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 17 +--
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 25 +++-
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 23 ++-
 .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   |  6 ++--
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 29 +++
 drivers/gpu/drm/mediatek/mtk_dsi.c| 18 +---
 drivers/gpu/drm/mediatek/mtk_ethdr.c  | 18 +---
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 14 +++--
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 12 +++-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 18 +---
 14 files changed, 96 insertions(+), 158 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c 
b/drivers/gpu/drm/mediatek/mtk_cec.c
index c3b89a5c138a..56b3917801d7 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -196,18 +196,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
spin_lock_init(&cec->lock);
 
cec->regs = devm_platform_ioremap_resource(pdev, 0);
-   if (IS_ERR(cec->regs)) {
-   ret = PTR_ERR(cec->regs);
-   dev_err(dev, "Failed to ioremap cec: %d\n", ret);
-   return ret;
-   }
+   if (IS_ERR(cec->regs))
+   return dev_err_probe(dev, PTR_ERR(cec->regs), "Failed to 
ioremap cec\n");
 
cec->clk = devm_clk_get(dev, NULL);
-   if (IS_ERR(cec->clk)) {
-   ret = PTR_ERR(cec->clk);
-   dev_err(dev, "Failed to get cec clock: %d\n", ret);
-   return ret;
-   }
+   if (IS_ERR(cec->clk))
+   return dev_err_probe(dev, PTR_ERR(cec->clk), "Failed to get cec 
clock\n");
 
cec->irq = platform_get_irq(pdev, 0);
if (cec->irq < 0)
@@ -217,16 +211,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
mtk_cec_htplg_isr_thread,
IRQF_SHARED | IRQF_TRIGGER_LOW |
IRQF_ONESHOT, "hdmi hpd", dev);
-   if (ret) {
-   dev_err(dev, "Failed to register cec irq: %d\n", ret);
-   return ret;
-   }
+   if (ret)
+   return dev_err_probe(dev, ret, "Failed to register cec irq\n");
 
ret = clk_prepare_enable(cec->clk);
-   if (ret) {
-   dev_err(dev, "Failed to enable cec clock: %d\n", ret);
-   return ret;
-   }
+   if (ret)
+   return dev_err_probe(dev, ret, "Failed to enable cec clock\n");
 
mtk_cec_htplg_irq_init(cec);
mtk_cec_htplg_irq_enable(cec);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index bd1d67a5baff..c60aa244de67 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -111,16 +111,12 @@ static int mtk_disp_aal_probe(struct platform_device 
*pdev)
return -ENOMEM;
 
priv->clk = devm_clk_get(dev, NULL);
-   if (IS_ERR(priv->clk)) {
-   dev_err(dev, "failed to get aal clk\n");
-   return PTR_ERR(priv->clk);
-   }
+   if (IS_ERR(priv->clk))
+   return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to get 
aal clk\n");
 
priv->regs = devm_platform_ioremap_resource(pdev, 0);
-   if (IS_ERR(priv->regs)) {
-   dev_err(dev, "failed to ioremap aal\n");
-   return PTR_ERR(priv->regs);
-   }
+   if (IS_ERR(priv->regs))
+   return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap aal\n");
 
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -133,9 +129,9 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
 
ret = component_add(dev, &mtk_disp_aal_component_ops);
if (ret)
-   dev_err(dev, "Failed to add component: %d\n", ret);
+   return dev_err_probe(dev, ret, "Failed to add component\n");
 
-   return ret;
+   return 0;
 }
 
 static int mtk_disp_aal_remove(struct platform_device *pdev)
diff --git 

[PATCH v2 1/3] drm/mediatek: Use devm_platform_ioremap_resource()

2023-07-05 Thread AngeloGioacchino Del Regno
Instead of open coding calls to platform_get_resource() followed by
devm_ioremap_resource(), perform a single call to the helper
devm_platform_ioremap_resource().

Also, in order to drop the now useless struct resource pointer in
all of the probe functions, it was also necessary to remove a
dev_dbg() in mtk_hdmi_ddc.c that was printing the iospace start/end.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_cec.c| 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 4 +---
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 4 +---
 drivers/gpu/drm/mediatek/mtk_dpi.c| 3 +--
 drivers/gpu/drm/mediatek/mtk_dsi.c| 4 +---
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 4 +---
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 6 +-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 4 +---
 13 files changed, 13 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c 
b/drivers/gpu/drm/mediatek/mtk_cec.c
index b640bc0559e7..c3b89a5c138a 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -195,8 +195,7 @@ static int mtk_cec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cec);
spin_lock_init(&cec->lock);
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   cec->regs = devm_ioremap_resource(dev, res);
+   cec->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(cec->regs)) {
ret = PTR_ERR(cec->regs);
dev_err(dev, "Failed to ioremap cec: %d\n", ret);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 8ddf7a97e583..bd1d67a5baff 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -104,7 +104,6 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
struct mtk_disp_aal *priv;
-   struct resource *res;
int ret;
 
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -117,8 +116,7 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap aal\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 1773379b2439..5cee84cce0be 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -159,7 +159,6 @@ static int mtk_disp_ccorr_probe(struct platform_device 
*pdev)
 {
struct device *dev = &pdev->dev;
struct mtk_disp_ccorr *priv;
-   struct resource *res;
int ret;
 
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -172,8 +171,7 @@ static int mtk_disp_ccorr_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap ccorr\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c 
b/drivers/gpu/drm/mediatek/mtk_disp_color.c
index cac9206079e7..e3816730ab51 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -97,7 +97,6 @@ static int mtk_disp_color_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
struct mtk_disp_color *priv;
-   struct resource *res;
int ret;
 
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -110,8 +109,7 @@ static int mtk_disp_color_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap color\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index bd530e603264..6ab67e6392c7 100644
-

[PATCH v2 3/3] drm/mediatek: Use devm variant for pm_runtime_enable() when possible

2023-07-05 Thread AngeloGioacchino Del Regno
Simplify the error path of return functions and drop the call to
pm_runtime_disable() in remove functions by switching to
devm_pm_runtime_enable() where possible.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Alexandre Mergnat 
Reviewed-by: CK Hu 
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c |  9 -
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c| 11 ---
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c | 10 +-
 3 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index 1993b688befa..14e8ad6c78c3 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -519,13 +519,13 @@ static int mtk_disp_ovl_adaptor_probe(struct 
platform_device *pdev)
 
component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, 
match);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_disp_ovl_adaptor_comp_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
 
return 0;
 }
@@ -533,7 +533,6 @@ static int mtk_disp_ovl_adaptor_probe(struct 
platform_device *pdev)
 static int mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
 {
component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops);
-   pm_runtime_disable(&pdev->dev);
return 0;
 }
 
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index cfbc037a0f6d..0469076cf715 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -360,13 +360,13 @@ static int mtk_disp_rdma_probe(struct platform_device 
*pdev)
 
platform_set_drvdata(pdev, priv);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_disp_rdma_component_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
 
return 0;
 }
@@ -374,9 +374,6 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
 static int mtk_disp_rdma_remove(struct platform_device *pdev)
 {
component_del(&pdev->dev, &mtk_disp_rdma_component_ops);
-
-   pm_runtime_disable(&pdev->dev);
-
return 0;
 }
 
diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c 
b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
index ae05d9660592..a5d811c37207 100644
--- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
@@ -299,20 +299,20 @@ static int mtk_mdp_rdma_probe(struct platform_device 
*pdev)
 #endif
platform_set_drvdata(pdev, priv);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_mdp_rdma_component_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
+
return 0;
 }
 
 static int mtk_mdp_rdma_remove(struct platform_device *pdev)
 {
component_del(&pdev->dev, &mtk_mdp_rdma_component_ops);
-   pm_runtime_disable(&pdev->dev);
return 0;
 }
 
-- 
2.40.1



[PATCH v2 0/3] drm/mediatek: General cleanups

2023-07-05 Thread AngeloGioacchino Del Regno
This series performs some cleanups in drm/mediatek; specifically, changes
it to use devm_platform_ioremap_resource(), dev_err_probe() and
devm_pm_runtime_enable, hence harmonizing log formats and removing some
unneeded lines of code.

Changes in v2:
 - Switched from devm_platform_get_and_ioremap_resource() to dropping
   struct resource pointer with using devm_platform_ioremap_resource()

AngeloGioacchino Del Regno (3):
  drm/mediatek: Use devm_platform_ioremap_resource()
  drm/mediatek: Use dev_err_probe() in probe functions
  drm/mediatek: Use devm variant for pm_runtime_enable() when possible

 drivers/gpu/drm/mediatek/mtk_cec.c| 29 
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 22 --
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 20 +++--
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 23 --
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 20 +++--
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 29 +---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 27 +---
 .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   | 13 +++---
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 44 +++
 drivers/gpu/drm/mediatek/mtk_dpi.c|  3 +-
 drivers/gpu/drm/mediatek/mtk_dsi.c| 22 --
 drivers/gpu/drm/mediatek/mtk_ethdr.c  | 18 
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 18 +++-
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 18 +++-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 30 +
 15 files changed, 122 insertions(+), 214 deletions(-)

-- 
2.40.1



Re: [v4, PATCH] drm/mediatek: add dma buffer control for drm plane disable

2023-07-04 Thread AngeloGioacchino Del Regno

Il 04/07/23 11:04, Yongqiang Niu ha scritto:

dma buffer release before overlay disable, that will cause
m4u translation fault warning.

add dma buffer control flow in mediatek driver:
get dma buffer when drm plane disable
put dma buffer when overlay really disable

Fixes: 41016fe1028e4 ("drm: Rename plane->state variables in atomic update and 
disable")
Signed-off-by: Yongqiang Niu 


Hello,

could you please rebase this over [1] for linux-next, while retaining this for
stable backports?

[1]: 
https://lore.kernel.org/lkml/20230623094931.117918-1-angelogioacchino.delre...@collabora.com/


Thanks,
Angelo


---
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c  | 25 
  drivers/gpu/drm/mediatek/mtk_drm_plane.c | 12 
  drivers/gpu/drm/mediatek/mtk_drm_plane.h |  1 +
  3 files changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..49d671100785 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -4,6 +4,7 @@
   */
  
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -283,6 +284,23 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct 
drm_crtc *crtc,
return NULL;
  }
  
+static void mtk_drm_dma_buf_put(struct mtk_drm_crtc *mtk_crtc)

+{
+   unsigned int i;
+
+   for (i = 0; i < mtk_crtc->layer_nr; i++) {
+   struct drm_plane *plane = &mtk_crtc->planes[i];
+   struct mtk_plane_state *plane_state;
+
+   plane_state = to_mtk_plane_state(plane->state);
+
+   if (plane_state && plane_state->pending.dma_buf) {
+   dma_buf_put(plane_state->pending.dma_buf);
+   plane_state->pending.dma_buf = NULL;
+   }
+   }
+}
+
  #if IS_REACHABLE(CONFIG_MTK_CMDQ)
  static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
  {
@@ -323,6 +341,8 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
mtk_crtc->pending_async_planes = false;
}
  
+	mtk_drm_dma_buf_put(mtk_crtc);

+
mtk_crtc->cmdq_vblank_cnt = 0;
wake_up(&mtk_crtc->cb_blocking_queue);
  }
@@ -624,9 +644,14 @@ static void mtk_crtc_ddp_irq(void *data)
else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt 
== 0)
DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
  drm_crtc_index(&mtk_crtc->base));
+
+   if (!mtk_crtc->cmdq_client.chan)
+   mtk_drm_dma_buf_put(mtk_crtc);
  #else
if (!priv->data->shadow_register)
mtk_crtc_ddp_config(crtc, NULL);
+
+   mtk_drm_dma_buf_put(mtk_crtc);
  #endif
mtk_drm_finish_page_flip(mtk_crtc);
  }
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c 
b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 31f9420aff6f..66e6393e45ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -12,6 +12,7 @@
  #include 
  #include 
  #include 
+#include 
  
  #include "mtk_drm_crtc.h"

  #include "mtk_drm_ddp_comp.h"
@@ -266,6 +267,17 @@ static void mtk_plane_atomic_disable(struct drm_plane 
*plane,
struct drm_plane_state *new_state = 
drm_atomic_get_new_plane_state(state,
   
plane);
struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
+   struct drm_plane_state *old_state = 
drm_atomic_get_old_plane_state(state,
+  
plane);
+
+   if (old_state && old_state->fb) {
+   struct drm_gem_object *gem = old_state->fb->obj[0];
+
+   if (gem && gem->dma_buf) {
+   get_dma_buf(gem->dma_buf);
+   mtk_plane_state->pending.dma_buf = gem->dma_buf;
+   }
+   }
mtk_plane_state->pending.enable = false;
wmb(); /* Make sure the above parameter is set before update */
mtk_plane_state->pending.dirty = true;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.h 
b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
index 99aff7da0831..3aba0b58ef3c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.h
@@ -33,6 +33,7 @@ struct mtk_plane_pending_state {
boolasync_dirty;
boolasync_config;
enum drm_color_encoding color_encoding;
+   struct dma_buf  *dma_buf;
  };
  
  struct mtk_plane_state {





[PATCH 3/3] drm/mediatek: Move CMDQ setup to mtk_drm_cmdq_init() function

2023-06-23 Thread AngeloGioacchino Del Regno
In order to enhance human readability, separating the optional
CMDQ mailbox initialization from the rest of the CRTC creation
machinery, move it to a new mtk_drm_cmdq_init() function.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 83 ++---
 1 file changed, 48 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 88c63330a421..bff65c8c6a0e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -826,6 +826,48 @@ struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc 
*crtc)
return mtk_crtc->dma_dev;
 }
 
+static int mtk_drm_cmdq_init(struct device *dev, struct mtk_drm_private *priv,
+struct mtk_drm_crtc *mtk_crtc)
+{
+   int ret;
+
+   mtk_crtc->cmdq_client = cmdq_mbox_create(mtk_crtc->mmsys_dev, 
priv->mbox_index);
+   if (IS_ERR(mtk_crtc->cmdq_client)) {
+   ret = PTR_ERR(mtk_crtc->cmdq_client);
+   dev_dbg(dev, "Failed to create CMDQ client: %d\n", ret);
+   goto error;
+   }
+
+   /* Setup the CMDQ handler callback */
+   mtk_crtc->cmdq_client->priv = mtk_crtc;
+   mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb;
+
+   ret = of_property_read_u32_index(priv->mutex_node, 
"mediatek,gce-events",
+priv->mbox_index, 
&mtk_crtc->cmdq_event);
+   if (ret) {
+   dev_dbg(dev, "Failed to get mediatek,gce-events: %d\n", ret);
+   goto free_mbox;
+   }
+
+   mtk_crtc->cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, 
PAGE_SIZE);
+   if (IS_ERR(mtk_crtc->cmdq_handle)) {
+   ret = PTR_ERR(mtk_crtc->cmdq_handle);
+   dev_err(dev, "Failed to create cmdq packet: %d\n", ret);
+   goto free_mbox;
+   }
+
+   /* for sending blocking cmd in crtc disable */
+   init_waitqueue_head(&mtk_crtc->cb_blocking_queue);
+
+   return 0;
+
+free_mbox:
+   cmdq_mbox_destroy(mtk_crtc->cmdq_client);
+error:
+   mtk_crtc->cmdq_client = NULL;
+   return ret;
+}
+
 int mtk_drm_crtc_create(struct drm_device *drm_dev,
const unsigned int *path, unsigned int path_len,
int priv_data_index)
@@ -942,42 +984,13 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size);
mutex_init(&mtk_crtc->hw_lock);
 
-   i = priv->mbox_index++;
-
-   mtk_crtc->cmdq_client = cmdq_mbox_create(mtk_crtc->mmsys_dev, i);
-   if (IS_ERR(mtk_crtc->cmdq_client)) {
-   ret = PTR_ERR(mtk_crtc->cmdq_client);
-   dev_dbg(dev, "Failed to create CMDQ client: %d\n", ret);
-   mtk_crtc->cmdq_client = NULL;
-   return 0;
-   }
-
-   /* Setup the CMDQ handler callback */
-   mtk_crtc->cmdq_client->priv = mtk_crtc;
-   mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb;
+   ret = mtk_drm_cmdq_init(dev, priv, mtk_crtc);
+   if (ret)
+   dev_info(dev, "No CMDQ support for CRTC%d: using CPU writes\n",
+drm_crtc_index(&mtk_crtc->base));
 
-   if (mtk_crtc->cmdq_client) {
-   ret = of_property_read_u32_index(priv->mutex_node,
-"mediatek,gce-events",
-i,
-&mtk_crtc->cmdq_event);
-   if (ret) {
-   dev_dbg(dev, "mtk_crtc %d failed to get 
mediatek,gce-events property\n",
-   drm_crtc_index(&mtk_crtc->base));
-   cmdq_mbox_destroy(mtk_crtc->cmdq_client);
-   mtk_crtc->cmdq_client = NULL;
-   } else {
-   mtk_crtc->cmdq_handle = 
cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
-   if (ret) {
-   dev_dbg(dev, "mtk_crtc %d failed to create cmdq 
packet\n",
-   drm_crtc_index(&mtk_crtc->base));
-   cmdq_mbox_destroy(mtk_crtc->cmdq_client);
-   mtk_crtc->cmdq_client = NULL;
-   }
-   }
+   /* Unconditionally increment mbox_index */
+   priv->mbox_index++;
 
-   /* for sending blocking cmd in crtc disable */
-   init_waitqueue_head(&mtk_crtc->cb_blocking_queue);
-   }
return 0;
 }
-- 
2.40.1



[PATCH 2/3] drm/mediatek: Remove all preprocessor ifs for CONFIG_MTK_CMDQ

2023-06-23 Thread AngeloGioacchino Del Regno
Since this driver was migrated to use the MediaTek CMDQ helpers,
it's not anymore necessary to exclude CMDQ related code with
preprocessor if branches, as CMDQ is optional and the helpers
are providing the necessary inline functions to manage the case
in which CONFIG_MTK_CMDQ is not set.

Clean up all instances of `#if IS_REACHABLE(CONFIG_MTK_CMDQ)`
from all drivers in drm/mediatek.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_aal.c |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c   |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_color.c   |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_merge.c   |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c |  2 --
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c|  2 --
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 22 +++--
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 12 ---
 drivers/gpu/drm/mediatek/mtk_ethdr.c|  6 ++
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c |  3 +--
 11 files changed, 6 insertions(+), 51 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 17a4d4a3b040..3faed081ea10 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -119,11 +119,9 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
if (IS_ERR(priv->regs))
return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap aal\n");
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
 
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 3f4bf7319f17..5a901ded8086 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -174,11 +174,9 @@ static int mtk_disp_ccorr_probe(struct platform_device 
*pdev)
if (IS_ERR(priv->regs))
return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap ccorr\n");
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
 
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c 
b/drivers/gpu/drm/mediatek/mtk_disp_color.c
index b188d3393f99..af866039bc38 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -112,11 +112,9 @@ static int mtk_disp_color_probe(struct platform_device 
*pdev)
if (IS_ERR(priv->regs))
return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap color\n");
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
 
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 1bf709bac0cf..64ba5c5b631f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -278,11 +278,9 @@ static int mtk_disp_gamma_probe(struct platform_device 
*pdev)
if (IS_ERR(priv->regs))
return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap gamma\n");
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
 
priv->data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c 
b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
index 60e0b4e70978..69b6f7229339 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
@@ -269,11 +269,9 @@ static int mtk_disp_merge_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->reset_ctl);
}
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
if (ret)
dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
-#endif
 
priv->fifo_en = of_property_read_bool(dev->of_node,
  "mediatek,merge-fifo-en");
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c 

[PATCH 1/3] drm/mediatek: Dynamically allocate CMDQ and use helper functions

2023-06-23 Thread AngeloGioacchino Del Regno
Instead of stack allocating the cmdq_client and cmdq_handle structures
switch them to pointers, allowing us to migrate this driver to use the
common functions provided by mtk-cmdq-helper.
In order to do this, it was also necessary to add a `priv` pointer to
struct cmdq_client, as that's used to pass (in this case) a mtk_crtc
handle to the ddp_cmdq_cb() mailbox RX callback function.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 107 +++-
 include/linux/soc/mediatek/mtk-cmdq.h   |   1 +
 2 files changed, 32 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 0df62b076f49..b63289ab6787 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -50,8 +50,8 @@ struct mtk_drm_crtc {
boolpending_async_planes;
 
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-   struct cmdq_client  cmdq_client;
-   struct cmdq_pkt cmdq_handle;
+   struct cmdq_client  *cmdq_client;
+   struct cmdq_pkt *cmdq_handle;
u32 cmdq_event;
u32 cmdq_vblank_cnt;
wait_queue_head_t   cb_blocking_queue;
@@ -108,47 +108,6 @@ static void mtk_drm_finish_page_flip(struct mtk_drm_crtc 
*mtk_crtc)
}
 }
 
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
-static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt 
*pkt,
-  size_t size)
-{
-   struct device *dev;
-   dma_addr_t dma_addr;
-
-   pkt->va_base = kzalloc(size, GFP_KERNEL);
-   if (!pkt->va_base) {
-   kfree(pkt);
-   return -ENOMEM;
-   }
-   pkt->buf_size = size;
-   pkt->cl = (void *)client;
-
-   dev = client->chan->mbox->dev;
-   dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
- DMA_TO_DEVICE);
-   if (dma_mapping_error(dev, dma_addr)) {
-   dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
-   kfree(pkt->va_base);
-   kfree(pkt);
-   return -ENOMEM;
-   }
-
-   pkt->pa_base = dma_addr;
-
-   return 0;
-}
-
-static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
-{
-   struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
-
-   dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
-DMA_TO_DEVICE);
-   kfree(pkt->va_base);
-   kfree(pkt);
-}
-#endif
-
 static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
 {
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
@@ -156,12 +115,9 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
 
mtk_mutex_put(mtk_crtc->mutex);
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-   mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
-
-   if (mtk_crtc->cmdq_client.chan) {
-   mbox_free_channel(mtk_crtc->cmdq_client.chan);
-   mtk_crtc->cmdq_client.chan = NULL;
-   }
+   cmdq_pkt_destroy(mtk_crtc->cmdq_handle);
+   cmdq_mbox_destroy(mtk_crtc->cmdq_client);
+   mtk_crtc->cmdq_client = NULL;
 #endif
 
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
@@ -288,7 +244,7 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
 {
struct cmdq_cb_data *data = mssg;
struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, 
client);
-   struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct 
mtk_drm_crtc, cmdq_client);
+   struct mtk_drm_crtc *mtk_crtc = (struct mtk_drm_crtc *)cmdq_cl->priv;
struct mtk_crtc_state *state;
unsigned int i;
 
@@ -546,7 +502,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc 
*mtk_crtc,
   bool needs_vblank)
 {
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-   struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle;
+   struct cmdq_pkt *cmdq_handle = mtk_crtc->cmdq_handle;
 #endif
struct drm_crtc *crtc = &mtk_crtc->base;
struct mtk_drm_private *priv = crtc->dev->dev_private;
@@ -584,14 +540,14 @@ static void mtk_drm_crtc_update_config(struct 
mtk_drm_crtc *mtk_crtc,
mtk_mutex_release(mtk_crtc->mutex);
}
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
-   if (mtk_crtc->cmdq_client.chan) {
-   mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
+   if (mtk_crtc->cmdq_client) {
+   mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
cmdq_handle->cmd_buf_size = 0;
cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);

[PATCH 0/3] MediaTek DRM: Clean up CMDQ support and ifdefs

2023-06-23 Thread AngeloGioacchino Del Regno
This series changes MediaTek CMDQ support to use the mtk-cmdq-helper
functions, removing duplicated cmdq setup code in mtk-drm and also
removing all instances of `#if IS_REACHABLE(CONFIG_MTK_CMDQ)` while
keeping compatibility with both CONFIG_MTK_CMDQ=n and =m/=y.

This applies on top of [1] and [2].

[1]: 
https://lore.kernel.org/lkml/20230524093412.92211-1-angelogioacchino.delre...@collabora.com
[2]: 
https://lore.kernel.org/lkml/20230608084727.74403-1-angelogioacchino.delre...@collabora.com

AngeloGioacchino Del Regno (3):
  drm/mediatek: Dynamically allocate CMDQ and use helper functions
  drm/mediatek: Remove all preprocessor ifs for CONFIG_MTK_CMDQ
  drm/mediatek: Move CMDQ setup to mtk_drm_cmdq_init() function

 drivers/gpu/drm/mediatek/mtk_disp_aal.c |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c   |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_color.c   |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_merge.c   |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c |   2 -
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c|   2 -
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 178 +++-
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  12 --
 drivers/gpu/drm/mediatek/mtk_ethdr.c|   6 +-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c |   3 +-
 include/linux/soc/mediatek/mtk-cmdq.h   |   1 +
 12 files changed, 69 insertions(+), 145 deletions(-)

-- 
2.40.1



Re: [PATCH] drm: mediatek: mtk_dsi: Fix NO_EOT_PACKET settings/handling

2023-06-23 Thread AngeloGioacchino Del Regno

Il 23/05/23 12:42, AngeloGioacchino Del Regno ha scritto:

Due to the initial confusion about MIPI_DSI_MODE_EOT_PACKET, properly
renamed to MIPI_DSI_MODE_NO_EOT_PACKET, reflecting its actual meaning,
both the DSI_TXRX_CON register setting for bit (HSTX_)DIS_EOT and the
later calculation for horizontal sync-active (HSA), back (HBP) and
front (HFP) porches got incorrect due to the logic being inverted.

This means that a number of settings were wrong because:
  - DSI_TXRX_CON register setting: bit (HSTX_)DIS_EOT should be
set in order to disable the End of Transmission packet;
  - Horizontal Sync and Back/Front porches: The delta used to
calculate all of HSA, HBP and HFP should account for the
additional EOT packet.

Before this change...
  - Bit (HSTX_)DIS_EOT was being set when EOT packet was enabled;
  - For HSA/HBP/HFP delta... all three were wrong, as words were
added when EOT disabled, instead of when EOT packet enabled!

Invert the logic around flag MIPI_DSI_MODE_NO_EOT_PACKET in the
MediaTek DSI driver to fix the aforementioned issues.

Fixes: 8b2b99fd7931 ("drm/mediatek: dsi: Fine tune the line time caused by 
EOTp")
Fixes: 2d52bfba09d1 ("drm/mediatek: add non-continuous clock mode and EOT packet 
control")
Signed-off-by: AngeloGioacchino Del Regno 



Gentle ping for an important fix.

Regards,
Angelo


---
  drivers/gpu/drm/mediatek/mtk_dsi.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 7d5250351193..b0ab38e59db9 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -407,7 +407,7 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
tmp_reg |= HSTX_CKLP_EN;
  
-	if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET))

+   if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
tmp_reg |= DIS_EOT;
  
  	writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);

@@ -484,7 +484,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
  timing->da_hs_zero + timing->da_hs_exit + 3;
  
  	delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12;

-   delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 2 : 0;
+   delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 0 : 2;
  
  	horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp;

horizontal_front_back_byte = horizontal_frontporch_byte + 
horizontal_backporch_byte;





Re: [PATCH v2 4/4] drm/mediatek: Fix dereference before null check

2023-06-14 Thread AngeloGioacchino Del Regno

Il 13/06/23 13:32, Jason-JH.Lin ha scritto:

Null-checking state suggests that it may be null, but it has already
been dereferenced on drm_atomic_get_new_plane_state(state, plane).

The parameter state will never be NULL currently, so just remove the
state is NULL flow in this function.

Signed-off-by: Jason-JH.Lin 
Fixes: 5ddb0bd4ddc3 ("drm/atomic: Pass the full state to planes async atomic check 
and update")


Fixes before S-o-b...

Reviewed-by: AngeloGioacchino Del Regno 





Re: [PATCH v2 3/4] drm/mediatek: Add casting before assign

2023-06-14 Thread AngeloGioacchino Del Regno

Il 13/06/23 13:32, Jason-JH.Lin ha scritto:

1. Add casting before assign to avoid the unintentional integer
overflow or unintended sign extension.
2. Add a int varriable for multiplier calculation instead of calculating
different types multiplier with dma_addr_t varriable directly.

Signed-off-by: Jason-JH.Lin 
Fixes: 1a64a7aff8da ("drm/mediatek: Fix cursor plane no update")
---
  drivers/gpu/drm/mediatek/mtk_drm_gem.c   |  2 +-
  drivers/gpu/drm/mediatek/mtk_drm_plane.c | 22 +-
  2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c 
b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index a25b28d3ee90..0c7878bc0b37 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -121,7 +121,7 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, 
struct drm_device *dev,
int ret;
  
  	args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);

-   args->size = args->pitch * args->height;
+   args->size = (__u64)args->pitch * args->height;


We could avoid explicit casting here if you do

args->size = args->pitch;
args->size *= args->height;

  
  	mtk_gem = mtk_drm_gem_create(dev, args->size, false);

if (IS_ERR(mtk_gem))
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c 
b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index 31f9420aff6f..1cd41454d545 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -145,6 +145,7 @@ static void mtk_plane_update_new_state(struct 
drm_plane_state *new_state,
dma_addr_t addr;
dma_addr_t hdr_addr = 0;
unsigned int hdr_pitch = 0;
+   int offset;


...but offset can never be negative, can it?
in that case, this should be unsigned int.

  
  	gem = fb->obj[0];

mtk_gem = to_mtk_gem_obj(gem);
@@ -154,8 +155,10 @@ static void mtk_plane_update_new_state(struct 
drm_plane_state *new_state,
modifier = fb->modifier;
  
  	if (modifier == DRM_FORMAT_MOD_LINEAR) {

-   addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
-   addr += (new_state->src.y1 >> 16) * pitch;
+   offset = (new_state->src.x1 >> 16) * fb->format->cpp[0];
+   addr += offset;
+   offset = (new_state->src.y1 >> 16) * pitch;
+   addr += offset;
} else {
int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH)
  / AFBC_DATA_BLOCK_WIDTH;
@@ -163,21 +166,22 @@ static void mtk_plane_update_new_state(struct 
drm_plane_state *new_state,
   / AFBC_DATA_BLOCK_HEIGHT;
int x_offset_in_blocks = (new_state->src.x1 >> 16) / 
AFBC_DATA_BLOCK_WIDTH;
int y_offset_in_blocks = (new_state->src.y1 >> 16) / 
AFBC_DATA_BLOCK_HEIGHT;
-   int hdr_size;
+   int hdr_size, hdr_offset;
  
  		hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;

pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0];
  
  		hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT);

+   hdr_offset = hdr_pitch * y_offset_in_blocks +
+   AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
+   hdr_addr = addr + hdr_offset;
  
-		hdr_addr = addr + hdr_pitch * y_offset_in_blocks +

-  AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
/* The data plane is offset by 1 additional block. */
-   addr = addr + hdr_size +
-  pitch * y_offset_in_blocks +
-  AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
-  fb->format->cpp[0] * (x_offset_in_blocks + 1);
+   offset = pitch * y_offset_in_blocks +
+AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
+fb->format->cpp[0] * (x_offset_in_blocks + 1);
+   addr = addr + hdr_size + offset;
}
  
  	mtk_plane_state->pending.enable = true;




Re: [PATCH v2 1/4] drm/mediatek: Remove freeing not dynamic allocated memory

2023-06-14 Thread AngeloGioacchino Del Regno

Il 13/06/23 13:32, Jason-JH.Lin ha scritto:

Fixing the coverity issue of:
mtk_drm_cmdq_pkt_destroy frees address of mtk_crtc->cmdq_handle

So remove the free function.

Signed-off-by: Jason-JH.Lin 
Fixes: 7627122fd1c0 ("drm/mediatek: Add cmdq_handle in mtk_crtc")


Fixes tag goes before your S-o-b tag.

Anyway,
Reviewed-by: AngeloGioacchino Del Regno 



---
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 7 ++-
  1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..8d44f3df116f 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -116,10 +116,9 @@ static int mtk_drm_cmdq_pkt_create(struct cmdq_client 
*client, struct cmdq_pkt *
dma_addr_t dma_addr;
  
  	pkt->va_base = kzalloc(size, GFP_KERNEL);

-   if (!pkt->va_base) {
-   kfree(pkt);
+   if (!pkt->va_base)
return -ENOMEM;
-   }
+
pkt->buf_size = size;
pkt->cl = (void *)client;
  
@@ -129,7 +128,6 @@ static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *

if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
kfree(pkt->va_base);
-   kfree(pkt);
return -ENOMEM;
}
  
@@ -145,7 +143,6 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)

dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
 DMA_TO_DEVICE);
kfree(pkt->va_base);
-   kfree(pkt);
  }
  #endif
  





Re: [PATCH v2 2/4] drm/mediatek: Add cnt checking for coverity issue

2023-06-14 Thread AngeloGioacchino Del Regno

Il 13/06/23 13:32, Jason-JH.Lin ha scritto:

CERT-C Characters and Strings (CERT STR31-C)
all_drm_priv[cnt] evaluates to an address that could be at negative
offset of an array.

In mtk_drm_get_all_drm_priv():
Guarantee that storage for strings has sufficient space for character
data and the null terminator.

So change cnt to unsigned int and check its max value.

Signed-off-by: Jason-JH.Lin 
Fixes: 1ef7ed48356c ("drm/mediatek: Modify mediatek-drm for mt8195 multi mmsys 
support")


Fixes tag goes before your S-o-b tag.

Anyway,
Reviewed-by: AngeloGioacchino Del Regno 



---
  drivers/gpu/drm/mediatek/mtk_drm_drv.c | 5 -
  1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c 
b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 6dcb4ba2466c..fc217e0acd45 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -354,7 +354,7 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
const struct of_device_id *of_id;
struct device_node *node;
struct device *drm_dev;
-   int cnt = 0;
+   unsigned int cnt = 0;
int i, j;
  
  	for_each_child_of_node(phandle->parent, node) {

@@ -375,6 +375,9 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
all_drm_priv[cnt] = dev_get_drvdata(drm_dev);
if (all_drm_priv[cnt] && all_drm_priv[cnt]->mtk_drm_bound)
cnt++;
+
+   if (cnt == MAX_CRTC) > + break;
}
  
  	if (drm_priv->data->mmsys_dev_num == cnt) {





Re: [PATCH v6 00/11] MediaTek DDP GAMMA - 12-bit LUT support

2023-06-14 Thread AngeloGioacchino Del Regno

Il 12/06/23 11:01, AngeloGioacchino Del Regno ha scritto:

Changes in v6:
  - Fixed smatch warning in patch 11/11, ref.:
https://lore.kernel.org/all/202306101458.lrxhee0z-...@intel.com/



This series is fully ready. CK, can we get this one and the mtk-dp series [1]
in -next for this cycle please?

Those are the last pieces that would allow enabling display on MT8195 
Chromebooks.

[1]: 
https://lore.kernel.org/lkml/20230404104800.301150-1-angelogioacchino.delre...@collabora.com/


Thanks,
Angelo


Changes in v5:
  - Removed incorrect comment on default LUT size and bits
  - Removed useless check for num_lut_banks
  - Added comment about CMDQ implementation on patch 5
  - Evaluated passing lut size/bits from AAL, idea discarded as
the implementation would be rather tricky while bringing no
benefits.

Changes in v4:
  - Fixed assignment typo appeared in v3

Changes in v3:
  - Fixed issues due to variables renaming during cleanup (oops)
  - This is actually the right series, since v2 was taken from the
wrong kernel tree :-)

Changes in v2:
  - Added explicit inclusion of linux/bitfield.h in patch [06/11]

This series adds support for GAMMA IP requiring and/or supporting
a 12-bits LUT using a slightly different register layout and programming
sequence for multiple LUT banks: this IP version is currently found
on a number of SoCs, not only including the Chromebook/IoT oriented
Kompanio 1200/1380 MT8195/MT8195T, but also Smartphone chips such as
the Dimensity 9200 (MT6985) and others.

This series was tested on MT8195, MT8192, MT8173, MT6795:
  * MT6795, MT8192, MT8173: No regression, works fine.
  * MT8195: Color correction is finally working!

AngeloGioacchino Del Regno (10):
   drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common()
   drm/mediatek: gamma: Support SoC specific LUT size
   drm/mediatek: gamma: Improve and simplify HW LUT calculation
   drm/mediatek: gamma: Enable the Gamma LUT table only after programming
   drm/mediatek: gamma: Use bitfield macros
   drm/mediatek: gamma: Support specifying number of bits per LUT
 component
   drm/mediatek: gamma: Support multi-bank gamma LUT
   drm/mediatek: gamma: Add support for 12-bit LUT and MT8195
   drm/mediatek: gamma: Make sure relay mode is disabled
   drm/mediatek: gamma: Program gamma LUT type for descending or rising

Jason-JH.Lin (1):
   drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters

  drivers/gpu/drm/mediatek/mtk_disp_aal.c |   2 +-
  drivers/gpu/drm/mediatek/mtk_disp_drv.h |   3 +-
  drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 193 
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   4 +-
  drivers/gpu/drm/mediatek/mtk_drm_crtc.h |   1 -
  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   1 +
  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   9 +
  7 files changed, 177 insertions(+), 36 deletions(-)





Re: [PATCH] drm/bridge: ps8640: Drop the ability of ps8640 to fetch the EDID

2023-06-14 Thread AngeloGioacchino Del Regno

Il 13/06/23 01:32, Douglas Anderson ha scritto:

In order to read the EDID from an eDP panel, you not only need to
power on the bridge chip itself but also the panel. In the ps8640
driver, this was made to work by having the bridge chip manually power
the panel on by calling pre_enable() on everything connectorward on
the bridge chain. This worked OK, but...

...when trying to do the same thing on ti-sn65dsi86, feedback was that
this wasn't a great idea. As a result, we designed the "DP AUX"
bus. With the design we ended up with the panel driver itself was in
charge of reading the EDID. The panel driver could power itself on and
the bridge chip was able to power itself on because it implemented the
DP AUX bus.

Despite the fact that we came up with a new scheme, implemented in on
ti-sn65dsi86, and even implemented it on parade-ps8640, we still kept
the old code around. This was because the new scheme required a DT
change. Previously the panel was a simple "platform_device" and in DT
at the top level. With the new design the panel needs to be listed in
DT under the DP controller node. The old code allowed us to properly
fetch EDIDs with ps8640 with the old DTs.

Unfortunately, the old code stopped working as of commit 102e80d1fa2c
("drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs"). There
are cases at bootup where connector->state->state is NULL and the
kernel crashed at:
* drm_atomic_bridge_chain_pre_enable
* drm_atomic_get_old_bridge_state
* drm_atomic_get_old_private_obj_state

A bit of digging was done to see if there was an easy fix but there
was nothing obvious. Instead, the only device using ps8640 the "old"
way had its DT updated so that the panel was no longer a simple
"platform_deice". See commit c2d94f72140a ("arm64: dts: mediatek:
mt8173-elm: Move display to ps8640 auxiliary bus") and commit
113b5cc06f44 ("arm64: dts: mediatek: mt8173-elm: remove panel model
number in DT").

Let's delete the old, crashing code so nobody gets tempted to copy it
or figure out how it works (since it doesn't).

NOTE: from a device tree "purist" point of view, we're supposed to
keep old device trees working and this patch is technically "against
policy". Reasons I'm still proposing it anyway:
1. Officially, old mt8173-elm device trees worked via the "little
white lie" approach. The DT would list an arbitrary/representative
panel that would be used for power sequencing. The mode information
in the panel driver would then be ignored / overridden by the EDID
reading code in ps8640. I don't feel too terrible breaking DTs that
contained the wrong "compatible" string to begin with. NOTE that
any old device trees that _didn't_ lie about their compatible will
still work because the mode information will come from the
hardcoded panels in panel-edp.
2. The only users of the old code were Chromebooks and Chromebooks
don't bake their DTs into the BIOS (they are bundled with the
kernel). Thus we don't need to worry about breaking someone using
an old DT with a new kernel.
3. The old code was crashing anyway. If someone wants to fix the old
code instead of deleting it then they have my blessing, but without
a proper fix the old code isn't useful.

I'll list this as "Fixing" the code that made the old code start
failing. There's not lots of reason to bring this back any further
than that.


Hoping to see removal of non-aux EDID reading code from all drivers that can
support aux-bus is exactly why I moved Elm to the proper... aux-bus.. so...

Yes! Let's go!



Fixes: 102e80d1fa2c ("drm/bridge: ps8640: Use atomic variants of 
drm_bridge_funcs")


...but this Fixes tag will cause this commit to be backported to kernel versions
before my commit moving Elm to aux-bus, and break display on those.

I would suggest to either find a different Fixes tag, or don't add any, since
technically this is a deprecation commit. We could imply that the old technique
is deprecated since kernel version X.Y and get away with it.

Otherwise, if you want it backported *anyway*, the safest way would be to Cc it
to stable and explicitly say which versions should it be backported to.

I really want to give my R-b tag to this one.

Cheers!
Angelo




[PATCH v6 11/11] drm/mediatek: gamma: Program gamma LUT type for descending or rising

2023-06-12 Thread AngeloGioacchino Del Regno
All of the SoCs that don't have dithering control in the gamma IP
have got a GAMMA_LUT_TYPE bit that tells to the IP if the LUT is
"descending" (bit set) or "rising" (bit cleared): make sure to set
it correctly after programming the LUT.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index e9655b661364..020755ae0ec0 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -23,6 +23,7 @@
 #define GAMMA_RELAY_MODE   BIT(0)
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
+#define GAMMA_LUT_TYPE BIT(2)
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
@@ -89,6 +90,16 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
return lut_size;
 }
 
+static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 
lut_size)
+{
+   u64 first, last;
+
+   first = lut[0].red + lut[0].green + lut[0].blue;
+   last = lut[lut_size].red + lut[lut_size].green + lut[lut_size].blue;
+
+   return !!(first > last);
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -178,6 +189,14 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
}
}
 
+   if (gamma && gamma->data && !gamma->data->has_dither) {
+   /* Descending or Rising LUT */
+   if (mtk_gamma_lut_is_descending(lut, lut_size))
+   cfg_val |= FIELD_PREP(GAMMA_LUT_TYPE, 1);
+   else
+   cfg_val &= ~GAMMA_LUT_TYPE;
+   }
+
/* Enable the gamma table */
cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
-- 
2.40.1



[PATCH v6 05/11] drm/mediatek: gamma: Enable the Gamma LUT table only after programming

2023-06-12 Thread AngeloGioacchino Del Regno
Move the write to DISP_GAMMA_CFG to enable the Gamma LUT to after
programming the actual table to avoid potential visual glitches during
table modification.

Note:
GAMMA should get enabled in between vblanks, but this requires many
efforts in order to make this happen, as that requires migrating all
of the writes to make use of CMDQ instead of cpu writes and that's
not trivial. For this reason, this patch only moves the LUT enable.
The CMDQ rework will come at a later time.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 204a1aa7bfc9..b75a77af5205 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -71,12 +71,12 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   unsigned int i, reg;
+   unsigned int i;
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
u16 lut_size;
-   u32 word;
+   u32 cfg_val, word;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -90,9 +90,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
lut_size = LUT_SIZE_DEFAULT;
}
 
-   reg = readl(regs + DISP_GAMMA_CFG);
-   reg = reg | GAMMA_LUT_EN;
-   writel(reg, regs + DISP_GAMMA_CFG);
+   cfg_val = readl(regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
@@ -122,6 +120,11 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
}
writel(word, (lut_base + i * 4));
}
+
+   /* Enable the gamma table */
+   cfg_val = cfg_val | GAMMA_LUT_EN;
+
+   writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
 
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
-- 
2.40.1



[PATCH v6 09/11] drm/mediatek: gamma: Add support for 12-bit LUT and MT8195

2023-06-12 Thread AngeloGioacchino Del Regno
Add support for 12-bit gamma lookup tables and introduce the first
user for it: MT8195.
While at it, also reorder the variables in mtk_gamma_set_common()
and rename `lut_base` to `lut0_base` to improve readability.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 61 ++-
 1 file changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index f1a0b18b6c1a..e0e2d2bdbf59 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -27,12 +27,20 @@
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
 #define DISP_GAMMA_BANK0x0100
 #define DISP_GAMMA_BANK_BANK   GENMASK(1, 0)
+#define DISP_GAMMA_BANK_DATA_MODE  BIT(2)
 #define DISP_GAMMA_LUT 0x0700
+#define DISP_GAMMA_LUT10x0b00
 
+/* For 10 bit LUT layout, R/G/B are in the same register */
 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
 #define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10)
 #define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0)
 
+/* For 12 bit LUT layout, R/G are in LUT, B is in LUT1 */
+#define DISP_GAMMA_LUT_12BIT_R GENMASK(11, 0)
+#define DISP_GAMMA_LUT_12BIT_G GENMASK(23, 12)
+#define DISP_GAMMA_LUT_12BIT_B GENMASK(11, 0)
+
 #define LUT_10BIT_MASK 0x03ff
 #define LUT_BITS_DEFAULT   10
 #define LUT_SIZE_DEFAULT   512
@@ -83,14 +91,15 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   unsigned int i;
+   void __iomem *lut0_base = regs + DISP_GAMMA_LUT;
+   void __iomem *lut1_base = regs + DISP_GAMMA_LUT1;
+   u32 cfg_val, data_mode, lbank_val, word[2];
+   int cur_bank, num_lut_banks;
+   u16 lut_bank_size, lut_size;
struct drm_color_lut *lut;
-   void __iomem *lut_base;
+   unsigned int i;
bool lut_diff;
-   u16 lut_bank_size, lut_size;
u8 lut_bits;
-   u32 cfg_val, lbank_val, word;
-   int cur_bank, num_lut_banks;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -110,14 +119,17 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
num_lut_banks = lut_size / lut_bank_size;
 
cfg_val = readl(regs + DISP_GAMMA_CFG);
-   lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
 
+   /* Switch to 12 bits data mode if supported */
+   data_mode = FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits == 12));
+
for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) {
 
/* Switch gamma bank and set data mode before writing LUT */
if (num_lut_banks > 1) {
lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank);
+   lbank_val |= data_mode;
writel(lbank_val, regs + DISP_GAMMA_BANK);
}
 
@@ -130,9 +142,15 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
hwlut.blue = drm_color_lut_extract(lut[n].blue, 
lut_bits);
 
if (!lut_diff || (i % 2 == 0)) {
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, 
hwlut.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, 
hwlut.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, 
hwlut.blue);
+   if (lut_bits == 12) {
+   word[0] = 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, hwlut.red);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, hwlut.green);
+   word[1] = 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, hwlut.blue);
+   } else {
+   word[0] = 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
+   }
} else {
diff.red = lut[n].red - lut[n - 1].red;
diff.red = drm_color_lut_extract(diff.red, 
lut_bits);
@@ -143,11 +161,19 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
  

[PATCH v6 07/11] drm/mediatek: gamma: Support specifying number of bits per LUT component

2023-06-12 Thread AngeloGioacchino Del Regno
New SoCs, like MT8195, not only may support bigger lookup tables, but
have got a different register layout to support bigger precision:
support specifying the number of `lut_bits` for each SoC and use it
in mtk_gamma_set_common() to perform the right calculation.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index f4bf5b37992c..407fb0264b80 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -39,6 +39,7 @@ struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
u16 lut_size;
+   u8 lut_bits;
 };
 
 /*
@@ -84,6 +85,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
void __iomem *lut_base;
bool lut_diff;
u16 lut_size;
+   u8 lut_bits;
u32 cfg_val, word;
 
/* If there's no gamma lut there's nothing to do here. */
@@ -92,9 +94,11 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
 
if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
+   lut_bits = gamma->data->lut_bits;
lut_size = gamma->data->lut_size;
} else {
lut_diff = false;
+   lut_bits = LUT_BITS_DEFAULT;
lut_size = LUT_SIZE_DEFAULT;
}
 
@@ -104,9 +108,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
for (i = 0; i < lut_size; i++) {
struct drm_color_lut diff, hwlut;
 
-   hwlut.red = drm_color_lut_extract(lut[i].red, LUT_BITS_DEFAULT);
-   hwlut.green = drm_color_lut_extract(lut[i].green, 
LUT_BITS_DEFAULT);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, 
LUT_BITS_DEFAULT);
+   hwlut.red = drm_color_lut_extract(lut[i].red, lut_bits);
+   hwlut.green = drm_color_lut_extract(lut[i].green, lut_bits);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, lut_bits);
 
if (!lut_diff || (i % 2 == 0)) {
word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
@@ -114,13 +118,13 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
} else {
diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, 
LUT_BITS_DEFAULT);
+   diff.red = drm_color_lut_extract(diff.red, lut_bits);
 
diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 
LUT_BITS_DEFAULT);
+   diff.green = drm_color_lut_extract(diff.green, 
lut_bits);
 
diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, 
LUT_BITS_DEFAULT);
+   diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
 
word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
@@ -237,10 +241,12 @@ static int mtk_disp_gamma_remove(struct platform_device 
*pdev)
 
 static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
+   .lut_bits = 10,
.lut_size = 512,
 };
 
 static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = {
+   .lut_bits = 10,
.lut_diff = true,
.lut_size = 512,
 };
-- 
2.40.1



[PATCH v6 02/11] drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common()

2023-06-12 Thread AngeloGioacchino Del Regno
Invert the check for state->gamma_lut and move it at the beginning
of the function to reduce indentation: this prepares the code for
keeping readability on later additions.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 45 ---
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 99be515a941b..ce6f2499b891 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -65,34 +65,35 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
u32 word;
u32 diff[3] = {0};
 
+   /* If there's no gamma lut there's nothing to do here. */
+   if (!state->gamma_lut)
+   return;
+
if (gamma && gamma->data)
lut_diff = gamma->data->lut_diff;
else
lut_diff = false;
 
-   if (state->gamma_lut) {
-   reg = readl(regs + DISP_GAMMA_CFG);
-   reg = reg | GAMMA_LUT_EN;
-   writel(reg, regs + DISP_GAMMA_CFG);
-   lut_base = regs + DISP_GAMMA_LUT;
-   lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < MTK_LUT_SIZE; i++) {
-
-   if (!lut_diff || (i % 2 == 0)) {
-   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 
20) +
-   (((lut[i].green >> 6) & LUT_10BIT_MASK) 
<< 10) +
-   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
-   } else {
-   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red 
>> 6);
-   diff[1] = (lut[i].green >> 6) - (lut[i - 
1].green >> 6);
-   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue 
>> 6);
-
-   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
-   ((diff[1] & LUT_10BIT_MASK) << 10) +
-   (diff[2] & LUT_10BIT_MASK);
-   }
-   writel(word, (lut_base + i * 4));
+   reg = readl(regs + DISP_GAMMA_CFG);
+   reg = reg | GAMMA_LUT_EN;
+   writel(reg, regs + DISP_GAMMA_CFG);
+   lut_base = regs + DISP_GAMMA_LUT;
+   lut = (struct drm_color_lut *)state->gamma_lut->data;
+   for (i = 0; i < MTK_LUT_SIZE; i++) {
+   if (!lut_diff || (i % 2 == 0)) {
+   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
+   (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
+   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+   } else {
+   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6);
+   diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6);
+   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6);
+
+   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
+   ((diff[1] & LUT_10BIT_MASK) << 10) +
+   (diff[2] & LUT_10BIT_MASK);
}
+   writel(word, (lut_base + i * 4));
}
 }
 
-- 
2.40.1



[PATCH v6 06/11] drm/mediatek: gamma: Use bitfield macros

2023-06-12 Thread AngeloGioacchino Del Regno
Make the code more robust and improve readability by using bitfield
macros instead of open coding bit operations.
While at it, also add a definition for LUT_BITS_DEFAULT.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 41 ++-
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index b75a77af5205..f4bf5b37992c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2021 MediaTek Inc.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -22,9 +23,16 @@
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
 #define DISP_GAMMA_SIZE0x0030
+#define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
+#define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
 #define DISP_GAMMA_LUT 0x0700
 
+#define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
+#define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10)
+#define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0)
+
 #define LUT_10BIT_MASK 0x03ff
+#define LUT_BITS_DEFAULT   10
 #define LUT_SIZE_DEFAULT   512
 
 struct mtk_disp_gamma_data {
@@ -96,33 +104,33 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
for (i = 0; i < lut_size; i++) {
struct drm_color_lut diff, hwlut;
 
-   hwlut.red = drm_color_lut_extract(lut[i].red, 10);
-   hwlut.green = drm_color_lut_extract(lut[i].green, 10);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, 10);
+   hwlut.red = drm_color_lut_extract(lut[i].red, LUT_BITS_DEFAULT);
+   hwlut.green = drm_color_lut_extract(lut[i].green, 
LUT_BITS_DEFAULT);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, 
LUT_BITS_DEFAULT);
 
if (!lut_diff || (i % 2 == 0)) {
-   word = hwlut.red << 20 +
-  hwlut.green << 10 +
-  hwlut.red;
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
} else {
diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, 10);
+   diff.red = drm_color_lut_extract(diff.red, 
LUT_BITS_DEFAULT);
 
diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 10);
+   diff.green = drm_color_lut_extract(diff.green, 
LUT_BITS_DEFAULT);
 
diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, 10);
+   diff.blue = drm_color_lut_extract(diff.blue, 
LUT_BITS_DEFAULT);
 
-   word = diff.blue << 20 +
-  diff.green << 10 +
-  diff.red;
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue);
}
writel(word, (lut_base + i * 4));
}
 
/* Enable the gamma table */
-   cfg_val = cfg_val | GAMMA_LUT_EN;
+   cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
@@ -139,9 +147,12 @@ void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+   u32 sz;
+
+   sz = FIELD_PREP(DISP_GAMMA_SIZE_HSIZE, w);
+   sz |= FIELD_PREP(DISP_GAMMA_SIZE_VSIZE, h);
 
-   mtk_ddp_write(cmdq_pkt, h << 16 | w, &gamma->cmdq_reg, gamma->regs,
- DISP_GAMMA_SIZE);
+   mtk_ddp_write(cmdq_pkt, sz, &gamma->cmdq_reg, gamma->regs, 
DISP_GAMMA_SIZE);
if (gamma->data && gamma->data->has_dither)
mtk_dither_set_common(gamma->regs, &gamma->cmdq_reg, bpc,
  DISP_GAMMA_CFG, GAMMA_DITHERING, 
cmdq_pkt);
-- 
2.40.1



[PATCH v6 08/11] drm/mediatek: gamma: Support multi-bank gamma LUT

2023-06-12 Thread AngeloGioacchino Del Regno
Newer Gamma IP have got multiple LUT banks: support specifying the
size of the LUT banks and handle bank-switching before programming
the LUT in mtk_gamma_set_common() in preparation for adding support
for MT8195 and newer SoCs.

Suggested-by: Jason-JH.Lin 
[Angelo: Refactored original commit]
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 74 ++-
 1 file changed, 47 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 407fb0264b80..f1a0b18b6c1a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,6 +25,8 @@
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
+#define DISP_GAMMA_BANK0x0100
+#define DISP_GAMMA_BANK_BANK   GENMASK(1, 0)
 #define DISP_GAMMA_LUT 0x0700
 
 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
@@ -38,6 +40,7 @@
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_bank_size;
u16 lut_size;
u8 lut_bits;
 };
@@ -84,9 +87,10 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
-   u16 lut_size;
+   u16 lut_bank_size, lut_size;
u8 lut_bits;
-   u32 cfg_val, word;
+   u32 cfg_val, lbank_val, word;
+   int cur_bank, num_lut_banks;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -94,43 +98,57 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
 
if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
+   lut_bank_size = gamma->data->lut_bank_size;
lut_bits = gamma->data->lut_bits;
lut_size = gamma->data->lut_size;
} else {
lut_diff = false;
+   lut_bank_size = LUT_SIZE_DEFAULT;
lut_bits = LUT_BITS_DEFAULT;
lut_size = LUT_SIZE_DEFAULT;
}
+   num_lut_banks = lut_size / lut_bank_size;
 
cfg_val = readl(regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < lut_size; i++) {
-   struct drm_color_lut diff, hwlut;
-
-   hwlut.red = drm_color_lut_extract(lut[i].red, lut_bits);
-   hwlut.green = drm_color_lut_extract(lut[i].green, lut_bits);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, lut_bits);
-
-   if (!lut_diff || (i % 2 == 0)) {
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
-   } else {
-   diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, lut_bits);
-
-   diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 
lut_bits);
-
-   diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
-
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue);
+
+   for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) {
+
+   /* Switch gamma bank and set data mode before writing LUT */
+   if (num_lut_banks > 1) {
+   lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank);
+   writel(lbank_val, regs + DISP_GAMMA_BANK);
+   }
+
+   for (i = 0; i < lut_bank_size; i++) {
+   int n = (cur_bank * lut_bank_size) + i;
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits);
+   hwlut.green = drm_color_lut_extract(lut[n].green, 
lut_bits);
+   hwlut.blue = drm_color_lut_extract(lut[n].blue, 
lut_bits);
+
+   if (!lut_diff || (i % 2 == 0)) {
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, 
hwlut.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, 
hwlut.green);
+  

[PATCH v6 03/11] drm/mediatek: gamma: Support SoC specific LUT size

2023-06-12 Thread AngeloGioacchino Del Regno
Newer SoCs support a bigger Gamma LUT table: wire up a callback
to retrieve the correct LUT size for each different Gamma IP.

Co-developed-by: Jason-JH.Lin 
Signed-off-by: Jason-JH.Lin 
[Angelo: Rewritten commit message/description + porting]
Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |  1 +
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 25 ++---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |  4 ++--
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  1 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |  9 
 6 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 75045932353e..e554b19f4830 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -53,6 +53,7 @@ void mtk_gamma_clk_disable(struct device *dev);
 void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int h, unsigned int vrefresh,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_gamma_get_lut_size(struct device *dev);
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state);
 void mtk_gamma_start(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index ce6f2499b891..b25ba209e7a4 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,10 +25,12 @@
 #define DISP_GAMMA_LUT 0x0700
 
 #define LUT_10BIT_MASK 0x03ff
+#define LUT_SIZE_DEFAULT   512
 
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_size;
 };
 
 /*
@@ -55,6 +57,17 @@ void mtk_gamma_clk_disable(struct device *dev)
clk_disable_unprepare(gamma->clk);
 }
 
+unsigned int mtk_gamma_get_lut_size(struct device *dev)
+{
+   struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+   unsigned int lut_size = LUT_SIZE_DEFAULT;
+
+   if (gamma && gamma->data)
+   lut_size = gamma->data->lut_size;
+
+   return lut_size;
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -62,6 +75,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
+   u16 lut_size;
u32 word;
u32 diff[3] = {0};
 
@@ -69,17 +83,20 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
if (!state->gamma_lut)
return;
 
-   if (gamma && gamma->data)
+   if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
-   else
+   lut_size = gamma->data->lut_size;
+   } else {
lut_diff = false;
+   lut_size = LUT_SIZE_DEFAULT;
+   }
 
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
writel(reg, regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < MTK_LUT_SIZE; i++) {
+   for (i = 0; i < lut_size; i++) {
if (!lut_diff || (i % 2 == 0)) {
word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
@@ -196,10 +213,12 @@ static int mtk_disp_gamma_remove(struct platform_device 
*pdev)
 
 static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
+   .lut_size = 512,
 };
 
 static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = {
.lut_diff = true,
+   .lut_size = 512,
 };
 
 static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..0df62b076f49 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -958,8 +958,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
mtk_crtc->ddp_comp[i] = comp;
 
if (comp->funcs) {
-   if (comp->funcs->gamma_set)
-   gamma_lut_size = MTK_LUT_SIZE;
+   if (comp->funcs->gamma_set && 
comp->funcs->gamma_get_lut_size)
+   gamma_lut_size = 
mtk_ddp_gamma_get_lut

[PATCH v6 10/11] drm/mediatek: gamma: Make sure relay mode is disabled

2023-06-12 Thread AngeloGioacchino Del Regno
Disable relay mode at the end of LUT programming to make sure that the
processed image goes through.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index e0e2d2bdbf59..e9655b661364 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -20,6 +20,7 @@
 #define DISP_GAMMA_EN  0x
 #define GAMMA_EN   BIT(0)
 #define DISP_GAMMA_CFG 0x0020
+#define GAMMA_RELAY_MODE   BIT(0)
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
 #define DISP_GAMMA_SIZE0x0030
@@ -180,6 +181,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
/* Enable the gamma table */
cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
+   /* Disable RELAY mode to pass the processed image */
+   cfg_val &= ~GAMMA_RELAY_MODE;
+
writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
 
-- 
2.40.1



[PATCH v6 04/11] drm/mediatek: gamma: Improve and simplify HW LUT calculation

2023-06-12 Thread AngeloGioacchino Del Regno
Use drm_color_lut_extract() to avoid open-coding the bits reduction
calculations for each color channel and use a struct drm_color_lut
to temporarily store the information instead of an array of u32.

Also, slightly improve the precision of the HW LUT calculation in the
LUT DIFF case by performing the subtractions on the 16-bits values and
doing the 10 bits conversion later.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 30 +++
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index b25ba209e7a4..204a1aa7bfc9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -77,7 +77,6 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
bool lut_diff;
u16 lut_size;
u32 word;
-   u32 diff[3] = {0};
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -97,18 +96,29 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[i].red, 10);
+   hwlut.green = drm_color_lut_extract(lut[i].green, 10);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, 10);
+
if (!lut_diff || (i % 2 == 0)) {
-   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
-   (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
-   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+   word = hwlut.red << 20 +
+  hwlut.green << 10 +
+  hwlut.red;
} else {
-   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6);
-   diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6);
-   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6);
+   diff.red = lut[i].red - lut[i - 1].red;
+   diff.red = drm_color_lut_extract(diff.red, 10);
+
+   diff.green = lut[i].green - lut[i - 1].green;
+   diff.green = drm_color_lut_extract(diff.green, 10);
+
+   diff.blue = lut[i].blue - lut[i - 1].blue;
+   diff.blue = drm_color_lut_extract(diff.blue, 10);
 
-   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
-   ((diff[1] & LUT_10BIT_MASK) << 10) +
-   (diff[2] & LUT_10BIT_MASK);
+   word = diff.blue << 20 +
+  diff.green << 10 +
+  diff.red;
}
writel(word, (lut_base + i * 4));
}
-- 
2.40.1



[PATCH v6 01/11] drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters

2023-06-12 Thread AngeloGioacchino Del Regno
From: "Jason-JH.Lin" 

Adjust the parameters in mtk_drm_gamma_set_common()
  - add (struct device *dev) to get lut_diff from gamma's driver data
  - remove (bool lut_diff) and use false as default value in the function

Signed-off-by: Jason-JH.Lin 
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   |  2 +-
 drivers/gpu/drm/mediatek/mtk_disp_drv.h   |  2 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 15 +--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 434e8a9ce8ab..8ddf7a97e583 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -67,7 +67,7 @@ void mtk_aal_gamma_set(struct device *dev, struct 
drm_crtc_state *state)
struct mtk_disp_aal *aal = dev_get_drvdata(dev);
 
if (aal->data && aal->data->has_gamma)
-   mtk_gamma_set_common(aal->regs, state, false);
+   mtk_gamma_set_common(NULL, aal->regs, state);
 }
 
 void mtk_aal_start(struct device *dev)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 2254038519e1..75045932353e 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -54,7 +54,7 @@ void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int h, unsigned int vrefresh,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
-void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, 
bool lut_diff);
+void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state);
 void mtk_gamma_start(struct device *dev);
 void mtk_gamma_stop(struct device *dev);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index c844942603f7..99be515a941b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -55,14 +55,21 @@ void mtk_gamma_clk_disable(struct device *dev)
clk_disable_unprepare(gamma->clk);
 }
 
-void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, 
bool lut_diff)
+void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
+   struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
unsigned int i, reg;
struct drm_color_lut *lut;
void __iomem *lut_base;
+   bool lut_diff;
u32 word;
u32 diff[3] = {0};
 
+   if (gamma && gamma->data)
+   lut_diff = gamma->data->lut_diff;
+   else
+   lut_diff = false;
+
if (state->gamma_lut) {
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
@@ -92,12 +99,8 @@ void mtk_gamma_set_common(void __iomem *regs, struct 
drm_crtc_state *state, bool
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   bool lut_diff = false;
-
-   if (gamma->data)
-   lut_diff = gamma->data->lut_diff;
 
-   mtk_gamma_set_common(gamma->regs, state, lut_diff);
+   mtk_gamma_set_common(dev, gamma->regs, state);
 }
 
 void mtk_gamma_config(struct device *dev, unsigned int w,
-- 
2.40.1



[PATCH v6 00/11] MediaTek DDP GAMMA - 12-bit LUT support

2023-06-12 Thread AngeloGioacchino Del Regno
Changes in v6:
 - Fixed smatch warning in patch 11/11, ref.:
   https://lore.kernel.org/all/202306101458.lrxhee0z-...@intel.com/

Changes in v5:
 - Removed incorrect comment on default LUT size and bits
 - Removed useless check for num_lut_banks
 - Added comment about CMDQ implementation on patch 5
 - Evaluated passing lut size/bits from AAL, idea discarded as
   the implementation would be rather tricky while bringing no
   benefits.

Changes in v4:
 - Fixed assignment typo appeared in v3

Changes in v3:
 - Fixed issues due to variables renaming during cleanup (oops)
 - This is actually the right series, since v2 was taken from the
   wrong kernel tree :-)

Changes in v2:
 - Added explicit inclusion of linux/bitfield.h in patch [06/11]

This series adds support for GAMMA IP requiring and/or supporting
a 12-bits LUT using a slightly different register layout and programming
sequence for multiple LUT banks: this IP version is currently found
on a number of SoCs, not only including the Chromebook/IoT oriented
Kompanio 1200/1380 MT8195/MT8195T, but also Smartphone chips such as
the Dimensity 9200 (MT6985) and others.

This series was tested on MT8195, MT8192, MT8173, MT6795:
 * MT6795, MT8192, MT8173: No regression, works fine.
 * MT8195: Color correction is finally working!

AngeloGioacchino Del Regno (10):
  drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common()
  drm/mediatek: gamma: Support SoC specific LUT size
  drm/mediatek: gamma: Improve and simplify HW LUT calculation
  drm/mediatek: gamma: Enable the Gamma LUT table only after programming
  drm/mediatek: gamma: Use bitfield macros
  drm/mediatek: gamma: Support specifying number of bits per LUT
component
  drm/mediatek: gamma: Support multi-bank gamma LUT
  drm/mediatek: gamma: Add support for 12-bit LUT and MT8195
  drm/mediatek: gamma: Make sure relay mode is disabled
  drm/mediatek: gamma: Program gamma LUT type for descending or rising

Jason-JH.Lin (1):
  drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters

 drivers/gpu/drm/mediatek/mtk_disp_aal.c |   2 +-
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |   3 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 193 
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   4 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |   1 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   9 +
 7 files changed, 177 insertions(+), 36 deletions(-)

-- 
2.40.1



Re: [RESEND 05/15] drm/mediatek/mtk_disp_ccorr: Remove half completed incorrect struct header

2023-06-09 Thread AngeloGioacchino Del Regno

Il 09/06/23 10:17, Lee Jones ha scritto:

Fixes the following W=1 kernel build warning(s):

  drivers/gpu/drm/mediatek/mtk_disp_ccorr.c:47: warning: Function parameter or 
member 'clk' not described in 'mtk_disp_ccorr'
  drivers/gpu/drm/mediatek/mtk_disp_ccorr.c:47: warning: Function parameter or 
member 'regs' not described in 'mtk_disp_ccorr'
  drivers/gpu/drm/mediatek/mtk_disp_ccorr.c:47: warning: Function parameter or 
member 'cmdq_reg' not described in 'mtk_disp_ccorr'
  drivers/gpu/drm/mediatek/mtk_disp_ccorr.c:47: warning: Function parameter or 
member 'data' not described in 'mtk_disp_ccorr'

Cc: Chun-Kuang Hu 
Cc: Philipp Zabel 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: Matthias Brugger 
Cc: AngeloGioacchino Del Regno 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-media...@lists.infradead.org
Cc: linux-arm-ker...@lists.infradead.org
Signed-off-by: Lee Jones 


Reviewed-by: AngeloGioacchino Del Regno 





Re: [RESEND 04/15] drm/mediatek/mtk_disp_aal: Remove half completed incorrect struct header

2023-06-09 Thread AngeloGioacchino Del Regno

Il 09/06/23 10:17, Lee Jones ha scritto:

Fixes the following W=1 kernel build warning(s):

  drivers/gpu/drm/mediatek/mtk_disp_aal.c:39: warning: Function parameter or 
member 'clk' not described in 'mtk_disp_aal'
  drivers/gpu/drm/mediatek/mtk_disp_aal.c:39: warning: Function parameter or 
member 'regs' not described in 'mtk_disp_aal'
  drivers/gpu/drm/mediatek/mtk_disp_aal.c:39: warning: Function parameter or 
member 'cmdq_reg' not described in 'mtk_disp_aal'
  drivers/gpu/drm/mediatek/mtk_disp_aal.c:39: warning: Function parameter or 
member 'data' not described in 'mtk_disp_aal'

Cc: Chun-Kuang Hu 
Cc: Philipp Zabel 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: Matthias Brugger 
Cc: AngeloGioacchino Del Regno 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-media...@lists.infradead.org
Cc: linux-arm-ker...@lists.infradead.org
Signed-off-by: Lee Jones 


Reviewed-by: AngeloGioacchino Del Regno 





[PATCH 3/3] drm/mediatek: Use devm variant for pm_runtime_enable() when possible

2023-06-08 Thread AngeloGioacchino Del Regno
Simplify the error path of return functions and drop the call to
pm_runtime_disable() in remove functions by switching to
devm_pm_runtime_enable() where possible.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c |  9 -
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c| 11 ---
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c | 10 +-
 3 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index 1993b688befa..14e8ad6c78c3 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -519,13 +519,13 @@ static int mtk_disp_ovl_adaptor_probe(struct 
platform_device *pdev)
 
component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, 
match);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_disp_ovl_adaptor_comp_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
 
return 0;
 }
@@ -533,7 +533,6 @@ static int mtk_disp_ovl_adaptor_probe(struct 
platform_device *pdev)
 static int mtk_disp_ovl_adaptor_remove(struct platform_device *pdev)
 {
component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops);
-   pm_runtime_disable(&pdev->dev);
return 0;
 }
 
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 307be35b59fc..5e90b6d593f5 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -361,13 +361,13 @@ static int mtk_disp_rdma_probe(struct platform_device 
*pdev)
 
platform_set_drvdata(pdev, priv);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_disp_rdma_component_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
 
return 0;
 }
@@ -375,9 +375,6 @@ static int mtk_disp_rdma_probe(struct platform_device *pdev)
 static int mtk_disp_rdma_remove(struct platform_device *pdev)
 {
component_del(&pdev->dev, &mtk_disp_rdma_component_ops);
-
-   pm_runtime_disable(&pdev->dev);
-
return 0;
 }
 
diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c 
b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
index ed519b5a3273..93ef05ec9720 100644
--- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
@@ -300,20 +300,20 @@ static int mtk_mdp_rdma_probe(struct platform_device 
*pdev)
 #endif
platform_set_drvdata(pdev, priv);
 
-   pm_runtime_enable(dev);
+   ret = devm_pm_runtime_enable(dev);
+   if (ret)
+   return ret;
 
ret = component_add(dev, &mtk_mdp_rdma_component_ops);
-   if (ret) {
-   pm_runtime_disable(dev);
+   if (ret)
return dev_err_probe(dev, ret, "Failed to add component\n");
-   }
+
return 0;
 }
 
 static int mtk_mdp_rdma_remove(struct platform_device *pdev)
 {
component_del(&pdev->dev, &mtk_mdp_rdma_component_ops);
-   pm_runtime_disable(&pdev->dev);
return 0;
 }
 
-- 
2.40.1



[PATCH 2/3] drm/mediatek: Use dev_err_probe() in probe functions

2023-06-08 Thread AngeloGioacchino Del Regno
Convert all instances of dev_err() -> return to dev_err_probe() and
where it makes sense to, change instances of `return ret` at the end
of probe functions to `return 0`, as errors are returned earlier.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_cec.c| 26 +
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 17 +--
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 16 --
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 25 +++-
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 23 ++-
 .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   |  6 ++--
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 29 +++
 drivers/gpu/drm/mediatek/mtk_dsi.c| 18 +---
 drivers/gpu/drm/mediatek/mtk_ethdr.c  | 18 +---
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 14 +++--
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 12 +++-
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 18 +---
 14 files changed, 96 insertions(+), 158 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c 
b/drivers/gpu/drm/mediatek/mtk_cec.c
index 5136aada9023..f12ee86c2b74 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -196,18 +196,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
spin_lock_init(&cec->lock);
 
cec->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-   if (IS_ERR(cec->regs)) {
-   ret = PTR_ERR(cec->regs);
-   dev_err(dev, "Failed to ioremap cec: %d\n", ret);
-   return ret;
-   }
+   if (IS_ERR(cec->regs))
+   return dev_err_probe(dev, PTR_ERR(cec->regs), "Failed to 
ioremap cec\n");
 
cec->clk = devm_clk_get(dev, NULL);
-   if (IS_ERR(cec->clk)) {
-   ret = PTR_ERR(cec->clk);
-   dev_err(dev, "Failed to get cec clock: %d\n", ret);
-   return ret;
-   }
+   if (IS_ERR(cec->clk))
+   return dev_err_probe(dev, PTR_ERR(cec->clk), "Failed to get cec 
clock\n");
 
cec->irq = platform_get_irq(pdev, 0);
if (cec->irq < 0)
@@ -217,16 +211,12 @@ static int mtk_cec_probe(struct platform_device *pdev)
mtk_cec_htplg_isr_thread,
IRQF_SHARED | IRQF_TRIGGER_LOW |
IRQF_ONESHOT, "hdmi hpd", dev);
-   if (ret) {
-   dev_err(dev, "Failed to register cec irq: %d\n", ret);
-   return ret;
-   }
+   if (ret)
+   return dev_err_probe(dev, ret, "Failed to register cec irq\n");
 
ret = clk_prepare_enable(cec->clk);
-   if (ret) {
-   dev_err(dev, "Failed to enable cec clock: %d\n", ret);
-   return ret;
-   }
+   if (ret)
+   return dev_err_probe(dev, ret, "Failed to enable cec clock\n");
 
mtk_cec_htplg_irq_init(cec);
mtk_cec_htplg_irq_enable(cec);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 68485c09ad8f..17a4d4a3b040 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -112,16 +112,12 @@ static int mtk_disp_aal_probe(struct platform_device 
*pdev)
return -ENOMEM;
 
priv->clk = devm_clk_get(dev, NULL);
-   if (IS_ERR(priv->clk)) {
-   dev_err(dev, "failed to get aal clk\n");
-   return PTR_ERR(priv->clk);
-   }
+   if (IS_ERR(priv->clk))
+   return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to get 
aal clk\n");
 
priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-   if (IS_ERR(priv->regs)) {
-   dev_err(dev, "failed to ioremap aal\n");
-   return PTR_ERR(priv->regs);
-   }
+   if (IS_ERR(priv->regs))
+   return dev_err_probe(dev, PTR_ERR(priv->regs), "failed to 
ioremap aal\n");
 
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
@@ -134,9 +130,9 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
 
ret = component_add(dev, &mtk_disp_aal_component_ops);
if (ret)
-   dev_err(dev, "Failed to add component: %d\n", ret);
+   return dev_err_probe(dev, ret, "Failed to add component\n");
 
-   return ret;
+   return 0;
 }
 
 static int mtk_disp_aal_remove(struct platform_device *pdev)
diff --git a/driv

[PATCH 1/3] drm/mediatek: Use devm_platform_get_and_ioremap_resource()

2023-06-08 Thread AngeloGioacchino Del Regno
Instead of open coding calls to platform_get_resource() followed by
devm_ioremap_resource(), perform a single call to the helper
devm_platform_get_and_ioremap_resource().

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_cec.c| 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 3 +--
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 3 +--
 drivers/gpu/drm/mediatek/mtk_dsi.c| 3 +--
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 3 +--
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 3 +--
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 3 +--
 12 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c 
b/drivers/gpu/drm/mediatek/mtk_cec.c
index b640bc0559e7..5136aada9023 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -195,8 +195,7 @@ static int mtk_cec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cec);
spin_lock_init(&cec->lock);
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   cec->regs = devm_ioremap_resource(dev, res);
+   cec->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(cec->regs)) {
ret = PTR_ERR(cec->regs);
dev_err(dev, "Failed to ioremap cec: %d\n", ret);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 8ddf7a97e583..68485c09ad8f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -117,8 +117,7 @@ static int mtk_disp_aal_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap aal\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c 
b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 1773379b2439..ae243e7db9b2 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -172,8 +172,7 @@ static int mtk_disp_ccorr_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap ccorr\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c 
b/drivers/gpu/drm/mediatek/mtk_disp_color.c
index cac9206079e7..4ec37e20ade9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -110,8 +110,7 @@ static int mtk_disp_color_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap color\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index bd530e603264..cf9262aa4f89 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -276,8 +276,7 @@ static int mtk_disp_gamma_probe(struct platform_device 
*pdev)
return PTR_ERR(priv->clk);
}
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   priv->regs = devm_ioremap_resource(dev, res);
+   priv->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "failed to ioremap gamma\n");
return PTR_ERR(priv->regs);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c 
b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
index 6428b6203ffe..f1dfa6dfd967 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
@@ -250,8 +250,7 @@ static int mtk_disp_merge_probe(struct platform_device 
*pdev)
if (!priv)
return -ENOMEM;
 
-   res = platform_get_resource(pdev, IORESOURCE_

[PATCH 0/3] drm/mediatek: General cleanups

2023-06-08 Thread AngeloGioacchino Del Regno
This series performs some cleanups in drm/mediatek; specifically, changes
it to use devm_platform_get_and_ioremap_resource(), dev_err_probe() and
devm_pm_runtime_enable, hence harmonizing log formats and removing some
unneeded lines of code.

AngeloGioacchino Del Regno (3):
  drm/mediatek: Use devm_platform_get_and_ioremap_resource()
  drm/mediatek: Use dev_err_probe() in probe functions
  drm/mediatek: Use devm variant for pm_runtime_enable() when possible

 drivers/gpu/drm/mediatek/mtk_cec.c| 29 -
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   | 21 -
 drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 19 +++-
 drivers/gpu/drm/mediatek/mtk_disp_color.c | 22 --
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 19 +++-
 drivers/gpu/drm/mediatek/mtk_disp_merge.c | 28 +---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c   | 26 +--
 .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c   | 13 +++---
 drivers/gpu/drm/mediatek/mtk_disp_rdma.c  | 43 +++
 drivers/gpu/drm/mediatek/mtk_dsi.c| 21 -
 drivers/gpu/drm/mediatek/mtk_ethdr.c  | 18 
 drivers/gpu/drm/mediatek/mtk_hdmi.c   | 17 +++-
 drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c   | 15 +++
 drivers/gpu/drm/mediatek/mtk_mdp_rdma.c   | 29 ++---
 14 files changed, 121 insertions(+), 199 deletions(-)

-- 
2.40.1



Re: [PATCH] drm/panel-edp: Add AUO B116XAB01.4 edp panel entry

2023-06-07 Thread AngeloGioacchino Del Regno

Il 07/06/23 12:21, Laura Nao ha scritto:

Add a panel entry for the AUO B116XAB01.4 edp panel, found in the Acer
Chromebook Spin 311 (CP311-3H) laptop.

Signed-off-by: Laura Nao 


Reviewed-by: AngeloGioacchino Del Regno 




[PATCH v5 11/11] drm/mediatek: gamma: Program gamma LUT type for descending or rising

2023-06-01 Thread AngeloGioacchino Del Regno
All of the SoCs that don't have dithering control in the gamma IP
have got a GAMMA_LUT_TYPE bit that tells to the IP if the LUT is
"descending" (bit set) or "rising" (bit cleared): make sure to set
it correctly after programming the LUT.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index e9655b661364..bd530e603264 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -23,6 +23,7 @@
 #define GAMMA_RELAY_MODE   BIT(0)
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
+#define GAMMA_LUT_TYPE BIT(2)
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
@@ -89,6 +90,16 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
return lut_size;
 }
 
+static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 
lut_size)
+{
+   u64 first, last;
+
+   first = lut[0].red + lut[0].green + lut[0].blue;
+   last = lut[lut_size].red + lut[lut_size].green + lut[lut_size].blue;
+
+   return !!(first > last);
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -178,6 +189,14 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
}
}
 
+   if (gamma && !gamma->data->has_dither) {
+   /* Descending or Rising LUT */
+   if (mtk_gamma_lut_is_descending(lut, lut_size))
+   cfg_val |= FIELD_PREP(GAMMA_LUT_TYPE, 1);
+   else
+   cfg_val &= ~GAMMA_LUT_TYPE;
+   }
+
/* Enable the gamma table */
cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
-- 
2.40.1



[PATCH v5 09/11] drm/mediatek: gamma: Add support for 12-bit LUT and MT8195

2023-06-01 Thread AngeloGioacchino Del Regno
Add support for 12-bit gamma lookup tables and introduce the first
user for it: MT8195.
While at it, also reorder the variables in mtk_gamma_set_common()
and rename `lut_base` to `lut0_base` to improve readability.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 61 ++-
 1 file changed, 48 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index f1a0b18b6c1a..e0e2d2bdbf59 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -27,12 +27,20 @@
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
 #define DISP_GAMMA_BANK0x0100
 #define DISP_GAMMA_BANK_BANK   GENMASK(1, 0)
+#define DISP_GAMMA_BANK_DATA_MODE  BIT(2)
 #define DISP_GAMMA_LUT 0x0700
+#define DISP_GAMMA_LUT10x0b00
 
+/* For 10 bit LUT layout, R/G/B are in the same register */
 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
 #define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10)
 #define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0)
 
+/* For 12 bit LUT layout, R/G are in LUT, B is in LUT1 */
+#define DISP_GAMMA_LUT_12BIT_R GENMASK(11, 0)
+#define DISP_GAMMA_LUT_12BIT_G GENMASK(23, 12)
+#define DISP_GAMMA_LUT_12BIT_B GENMASK(11, 0)
+
 #define LUT_10BIT_MASK 0x03ff
 #define LUT_BITS_DEFAULT   10
 #define LUT_SIZE_DEFAULT   512
@@ -83,14 +91,15 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   unsigned int i;
+   void __iomem *lut0_base = regs + DISP_GAMMA_LUT;
+   void __iomem *lut1_base = regs + DISP_GAMMA_LUT1;
+   u32 cfg_val, data_mode, lbank_val, word[2];
+   int cur_bank, num_lut_banks;
+   u16 lut_bank_size, lut_size;
struct drm_color_lut *lut;
-   void __iomem *lut_base;
+   unsigned int i;
bool lut_diff;
-   u16 lut_bank_size, lut_size;
u8 lut_bits;
-   u32 cfg_val, lbank_val, word;
-   int cur_bank, num_lut_banks;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -110,14 +119,17 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
num_lut_banks = lut_size / lut_bank_size;
 
cfg_val = readl(regs + DISP_GAMMA_CFG);
-   lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
 
+   /* Switch to 12 bits data mode if supported */
+   data_mode = FIELD_PREP(DISP_GAMMA_BANK_DATA_MODE, !!(lut_bits == 12));
+
for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) {
 
/* Switch gamma bank and set data mode before writing LUT */
if (num_lut_banks > 1) {
lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank);
+   lbank_val |= data_mode;
writel(lbank_val, regs + DISP_GAMMA_BANK);
}
 
@@ -130,9 +142,15 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
hwlut.blue = drm_color_lut_extract(lut[n].blue, 
lut_bits);
 
if (!lut_diff || (i % 2 == 0)) {
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, 
hwlut.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, 
hwlut.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, 
hwlut.blue);
+   if (lut_bits == 12) {
+   word[0] = 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_R, hwlut.red);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_G, hwlut.green);
+   word[1] = 
FIELD_PREP(DISP_GAMMA_LUT_12BIT_B, hwlut.blue);
+   } else {
+   word[0] = 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
+   word[0] |= 
FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
+   }
} else {
diff.red = lut[n].red - lut[n - 1].red;
diff.red = drm_color_lut_extract(diff.red, 
lut_bits);
@@ -143,11 +161,19 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
  

[PATCH v5 06/11] drm/mediatek: gamma: Use bitfield macros

2023-06-01 Thread AngeloGioacchino Del Regno
Make the code more robust and improve readability by using bitfield
macros instead of open coding bit operations.
While at it, also add a definition for LUT_BITS_DEFAULT.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 41 ++-
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index b75a77af5205..f4bf5b37992c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2021 MediaTek Inc.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -22,9 +23,16 @@
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
 #define DISP_GAMMA_SIZE0x0030
+#define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
+#define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
 #define DISP_GAMMA_LUT 0x0700
 
+#define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
+#define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10)
+#define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0)
+
 #define LUT_10BIT_MASK 0x03ff
+#define LUT_BITS_DEFAULT   10
 #define LUT_SIZE_DEFAULT   512
 
 struct mtk_disp_gamma_data {
@@ -96,33 +104,33 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
for (i = 0; i < lut_size; i++) {
struct drm_color_lut diff, hwlut;
 
-   hwlut.red = drm_color_lut_extract(lut[i].red, 10);
-   hwlut.green = drm_color_lut_extract(lut[i].green, 10);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, 10);
+   hwlut.red = drm_color_lut_extract(lut[i].red, LUT_BITS_DEFAULT);
+   hwlut.green = drm_color_lut_extract(lut[i].green, 
LUT_BITS_DEFAULT);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, 
LUT_BITS_DEFAULT);
 
if (!lut_diff || (i % 2 == 0)) {
-   word = hwlut.red << 20 +
-  hwlut.green << 10 +
-  hwlut.red;
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
} else {
diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, 10);
+   diff.red = drm_color_lut_extract(diff.red, 
LUT_BITS_DEFAULT);
 
diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 10);
+   diff.green = drm_color_lut_extract(diff.green, 
LUT_BITS_DEFAULT);
 
diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, 10);
+   diff.blue = drm_color_lut_extract(diff.blue, 
LUT_BITS_DEFAULT);
 
-   word = diff.blue << 20 +
-  diff.green << 10 +
-  diff.red;
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue);
}
writel(word, (lut_base + i * 4));
}
 
/* Enable the gamma table */
-   cfg_val = cfg_val | GAMMA_LUT_EN;
+   cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
@@ -139,9 +147,12 @@ void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+   u32 sz;
+
+   sz = FIELD_PREP(DISP_GAMMA_SIZE_HSIZE, w);
+   sz |= FIELD_PREP(DISP_GAMMA_SIZE_VSIZE, h);
 
-   mtk_ddp_write(cmdq_pkt, h << 16 | w, &gamma->cmdq_reg, gamma->regs,
- DISP_GAMMA_SIZE);
+   mtk_ddp_write(cmdq_pkt, sz, &gamma->cmdq_reg, gamma->regs, 
DISP_GAMMA_SIZE);
if (gamma->data && gamma->data->has_dither)
mtk_dither_set_common(gamma->regs, &gamma->cmdq_reg, bpc,
  DISP_GAMMA_CFG, GAMMA_DITHERING, 
cmdq_pkt);
-- 
2.40.1



[PATCH v5 10/11] drm/mediatek: gamma: Make sure relay mode is disabled

2023-06-01 Thread AngeloGioacchino Del Regno
Disable relay mode at the end of LUT programming to make sure that the
processed image goes through.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index e0e2d2bdbf59..e9655b661364 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -20,6 +20,7 @@
 #define DISP_GAMMA_EN  0x
 #define GAMMA_EN   BIT(0)
 #define DISP_GAMMA_CFG 0x0020
+#define GAMMA_RELAY_MODE   BIT(0)
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
 #define DISP_GAMMA_SIZE0x0030
@@ -180,6 +181,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
/* Enable the gamma table */
cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
+   /* Disable RELAY mode to pass the processed image */
+   cfg_val &= ~GAMMA_RELAY_MODE;
+
writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
 
-- 
2.40.1



[PATCH v5 08/11] drm/mediatek: gamma: Support multi-bank gamma LUT

2023-06-01 Thread AngeloGioacchino Del Regno
Newer Gamma IP have got multiple LUT banks: support specifying the
size of the LUT banks and handle bank-switching before programming
the LUT in mtk_gamma_set_common() in preparation for adding support
for MT8195 and newer SoCs.

Suggested-by: Jason-JH.Lin 
[Angelo: Refactored original commit]
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 74 ++-
 1 file changed, 47 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 407fb0264b80..f1a0b18b6c1a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,6 +25,8 @@
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
+#define DISP_GAMMA_BANK0x0100
+#define DISP_GAMMA_BANK_BANK   GENMASK(1, 0)
 #define DISP_GAMMA_LUT 0x0700
 
 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
@@ -38,6 +40,7 @@
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_bank_size;
u16 lut_size;
u8 lut_bits;
 };
@@ -84,9 +87,10 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
-   u16 lut_size;
+   u16 lut_bank_size, lut_size;
u8 lut_bits;
-   u32 cfg_val, word;
+   u32 cfg_val, lbank_val, word;
+   int cur_bank, num_lut_banks;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -94,43 +98,57 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
 
if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
+   lut_bank_size = gamma->data->lut_bank_size;
lut_bits = gamma->data->lut_bits;
lut_size = gamma->data->lut_size;
} else {
lut_diff = false;
+   lut_bank_size = LUT_SIZE_DEFAULT;
lut_bits = LUT_BITS_DEFAULT;
lut_size = LUT_SIZE_DEFAULT;
}
+   num_lut_banks = lut_size / lut_bank_size;
 
cfg_val = readl(regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < lut_size; i++) {
-   struct drm_color_lut diff, hwlut;
-
-   hwlut.red = drm_color_lut_extract(lut[i].red, lut_bits);
-   hwlut.green = drm_color_lut_extract(lut[i].green, lut_bits);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, lut_bits);
-
-   if (!lut_diff || (i % 2 == 0)) {
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
-   } else {
-   diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, lut_bits);
-
-   diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 
lut_bits);
-
-   diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
-
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue);
+
+   for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) {
+
+   /* Switch gamma bank and set data mode before writing LUT */
+   if (num_lut_banks > 1) {
+   lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank);
+   writel(lbank_val, regs + DISP_GAMMA_BANK);
+   }
+
+   for (i = 0; i < lut_bank_size; i++) {
+   int n = (cur_bank * lut_bank_size) + i;
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits);
+   hwlut.green = drm_color_lut_extract(lut[n].green, 
lut_bits);
+   hwlut.blue = drm_color_lut_extract(lut[n].blue, 
lut_bits);
+
+   if (!lut_diff || (i % 2 == 0)) {
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, 
hwlut.red);
+   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, 
hwlut.green);
+  

[PATCH v5 05/11] drm/mediatek: gamma: Enable the Gamma LUT table only after programming

2023-06-01 Thread AngeloGioacchino Del Regno
Move the write to DISP_GAMMA_CFG to enable the Gamma LUT to after
programming the actual table to avoid potential visual glitches during
table modification.

Note:
GAMMA should get enabled in between vblanks, but this requires many
efforts in order to make this happen, as that requires migrating all
of the writes to make use of CMDQ instead of cpu writes and that's
not trivial. For this reason, this patch only moves the LUT enable.
The CMDQ rework will come at a later time.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 204a1aa7bfc9..b75a77af5205 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -71,12 +71,12 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   unsigned int i, reg;
+   unsigned int i;
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
u16 lut_size;
-   u32 word;
+   u32 cfg_val, word;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -90,9 +90,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
lut_size = LUT_SIZE_DEFAULT;
}
 
-   reg = readl(regs + DISP_GAMMA_CFG);
-   reg = reg | GAMMA_LUT_EN;
-   writel(reg, regs + DISP_GAMMA_CFG);
+   cfg_val = readl(regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
@@ -122,6 +120,11 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
}
writel(word, (lut_base + i * 4));
}
+
+   /* Enable the gamma table */
+   cfg_val = cfg_val | GAMMA_LUT_EN;
+
+   writel(cfg_val, regs + DISP_GAMMA_CFG);
 }
 
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
-- 
2.40.1



[PATCH v5 01/11] drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters

2023-06-01 Thread AngeloGioacchino Del Regno
From: "Jason-JH.Lin" 

Adjust the parameters in mtk_drm_gamma_set_common()
  - add (struct device *dev) to get lut_diff from gamma's driver data
  - remove (bool lut_diff) and use false as default value in the function

Signed-off-by: Jason-JH.Lin 
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_aal.c   |  2 +-
 drivers/gpu/drm/mediatek/mtk_disp_drv.h   |  2 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 15 +--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c 
b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 434e8a9ce8ab..8ddf7a97e583 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -67,7 +67,7 @@ void mtk_aal_gamma_set(struct device *dev, struct 
drm_crtc_state *state)
struct mtk_disp_aal *aal = dev_get_drvdata(dev);
 
if (aal->data && aal->data->has_gamma)
-   mtk_gamma_set_common(aal->regs, state, false);
+   mtk_gamma_set_common(NULL, aal->regs, state);
 }
 
 void mtk_aal_start(struct device *dev)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 2254038519e1..75045932353e 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -54,7 +54,7 @@ void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int h, unsigned int vrefresh,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
-void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, 
bool lut_diff);
+void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state);
 void mtk_gamma_start(struct device *dev);
 void mtk_gamma_stop(struct device *dev);
 
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index c844942603f7..99be515a941b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -55,14 +55,21 @@ void mtk_gamma_clk_disable(struct device *dev)
clk_disable_unprepare(gamma->clk);
 }
 
-void mtk_gamma_set_common(void __iomem *regs, struct drm_crtc_state *state, 
bool lut_diff)
+void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
+   struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
unsigned int i, reg;
struct drm_color_lut *lut;
void __iomem *lut_base;
+   bool lut_diff;
u32 word;
u32 diff[3] = {0};
 
+   if (gamma && gamma->data)
+   lut_diff = gamma->data->lut_diff;
+   else
+   lut_diff = false;
+
if (state->gamma_lut) {
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
@@ -92,12 +99,8 @@ void mtk_gamma_set_common(void __iomem *regs, struct 
drm_crtc_state *state, bool
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   bool lut_diff = false;
-
-   if (gamma->data)
-   lut_diff = gamma->data->lut_diff;
 
-   mtk_gamma_set_common(gamma->regs, state, lut_diff);
+   mtk_gamma_set_common(dev, gamma->regs, state);
 }
 
 void mtk_gamma_config(struct device *dev, unsigned int w,
-- 
2.40.1



[PATCH v5 07/11] drm/mediatek: gamma: Support specifying number of bits per LUT component

2023-06-01 Thread AngeloGioacchino Del Regno
New SoCs, like MT8195, not only may support bigger lookup tables, but
have got a different register layout to support bigger precision:
support specifying the number of `lut_bits` for each SoC and use it
in mtk_gamma_set_common() to perform the right calculation.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index f4bf5b37992c..407fb0264b80 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -39,6 +39,7 @@ struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
u16 lut_size;
+   u8 lut_bits;
 };
 
 /*
@@ -84,6 +85,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
void __iomem *lut_base;
bool lut_diff;
u16 lut_size;
+   u8 lut_bits;
u32 cfg_val, word;
 
/* If there's no gamma lut there's nothing to do here. */
@@ -92,9 +94,11 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
 
if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
+   lut_bits = gamma->data->lut_bits;
lut_size = gamma->data->lut_size;
} else {
lut_diff = false;
+   lut_bits = LUT_BITS_DEFAULT;
lut_size = LUT_SIZE_DEFAULT;
}
 
@@ -104,9 +108,9 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
for (i = 0; i < lut_size; i++) {
struct drm_color_lut diff, hwlut;
 
-   hwlut.red = drm_color_lut_extract(lut[i].red, LUT_BITS_DEFAULT);
-   hwlut.green = drm_color_lut_extract(lut[i].green, 
LUT_BITS_DEFAULT);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, 
LUT_BITS_DEFAULT);
+   hwlut.red = drm_color_lut_extract(lut[i].red, lut_bits);
+   hwlut.green = drm_color_lut_extract(lut[i].green, lut_bits);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, lut_bits);
 
if (!lut_diff || (i % 2 == 0)) {
word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
@@ -114,13 +118,13 @@ void mtk_gamma_set_common(struct device *dev, void 
__iomem *regs, struct drm_crt
word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
} else {
diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, 
LUT_BITS_DEFAULT);
+   diff.red = drm_color_lut_extract(diff.red, lut_bits);
 
diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 
LUT_BITS_DEFAULT);
+   diff.green = drm_color_lut_extract(diff.green, 
lut_bits);
 
diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, 
LUT_BITS_DEFAULT);
+   diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
 
word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
@@ -237,10 +241,12 @@ static int mtk_disp_gamma_remove(struct platform_device 
*pdev)
 
 static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
+   .lut_bits = 10,
.lut_size = 512,
 };
 
 static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = {
+   .lut_bits = 10,
.lut_diff = true,
.lut_size = 512,
 };
-- 
2.40.1



[PATCH v5 04/11] drm/mediatek: gamma: Improve and simplify HW LUT calculation

2023-06-01 Thread AngeloGioacchino Del Regno
Use drm_color_lut_extract() to avoid open-coding the bits reduction
calculations for each color channel and use a struct drm_color_lut
to temporarily store the information instead of an array of u32.

Also, slightly improve the precision of the HW LUT calculation in the
LUT DIFF case by performing the subtractions on the 16-bits values and
doing the 10 bits conversion later.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 30 +++
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index b25ba209e7a4..204a1aa7bfc9 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -77,7 +77,6 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
bool lut_diff;
u16 lut_size;
u32 word;
-   u32 diff[3] = {0};
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -97,18 +96,29 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[i].red, 10);
+   hwlut.green = drm_color_lut_extract(lut[i].green, 10);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, 10);
+
if (!lut_diff || (i % 2 == 0)) {
-   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
-   (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
-   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+   word = hwlut.red << 20 +
+  hwlut.green << 10 +
+  hwlut.red;
} else {
-   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6);
-   diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6);
-   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6);
+   diff.red = lut[i].red - lut[i - 1].red;
+   diff.red = drm_color_lut_extract(diff.red, 10);
+
+   diff.green = lut[i].green - lut[i - 1].green;
+   diff.green = drm_color_lut_extract(diff.green, 10);
+
+   diff.blue = lut[i].blue - lut[i - 1].blue;
+   diff.blue = drm_color_lut_extract(diff.blue, 10);
 
-   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
-   ((diff[1] & LUT_10BIT_MASK) << 10) +
-   (diff[2] & LUT_10BIT_MASK);
+   word = diff.blue << 20 +
+  diff.green << 10 +
+  diff.red;
}
writel(word, (lut_base + i * 4));
}
-- 
2.40.1



[PATCH v5 03/11] drm/mediatek: gamma: Support SoC specific LUT size

2023-06-01 Thread AngeloGioacchino Del Regno
Newer SoCs support a bigger Gamma LUT table: wire up a callback
to retrieve the correct LUT size for each different Gamma IP.

Co-developed-by: Jason-JH.Lin 
Signed-off-by: Jason-JH.Lin 
[Angelo: Rewritten commit message/description + porting]
Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |  1 +
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 25 ++---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |  4 ++--
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  1 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |  9 
 6 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 75045932353e..e554b19f4830 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -53,6 +53,7 @@ void mtk_gamma_clk_disable(struct device *dev);
 void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int h, unsigned int vrefresh,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_gamma_get_lut_size(struct device *dev);
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state);
 void mtk_gamma_start(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index ce6f2499b891..b25ba209e7a4 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,10 +25,12 @@
 #define DISP_GAMMA_LUT 0x0700
 
 #define LUT_10BIT_MASK 0x03ff
+#define LUT_SIZE_DEFAULT   512
 
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_size;
 };
 
 /*
@@ -55,6 +57,17 @@ void mtk_gamma_clk_disable(struct device *dev)
clk_disable_unprepare(gamma->clk);
 }
 
+unsigned int mtk_gamma_get_lut_size(struct device *dev)
+{
+   struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+   unsigned int lut_size = LUT_SIZE_DEFAULT;
+
+   if (gamma && gamma->data)
+   lut_size = gamma->data->lut_size;
+
+   return lut_size;
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -62,6 +75,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
+   u16 lut_size;
u32 word;
u32 diff[3] = {0};
 
@@ -69,17 +83,20 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
if (!state->gamma_lut)
return;
 
-   if (gamma && gamma->data)
+   if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
-   else
+   lut_size = gamma->data->lut_size;
+   } else {
lut_diff = false;
+   lut_size = LUT_SIZE_DEFAULT;
+   }
 
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
writel(reg, regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < MTK_LUT_SIZE; i++) {
+   for (i = 0; i < lut_size; i++) {
if (!lut_diff || (i % 2 == 0)) {
word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
@@ -196,10 +213,12 @@ static int mtk_disp_gamma_remove(struct platform_device 
*pdev)
 
 static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
+   .lut_size = 512,
 };
 
 static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = {
.lut_diff = true,
+   .lut_size = 512,
 };
 
 static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..0df62b076f49 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -958,8 +958,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
mtk_crtc->ddp_comp[i] = comp;
 
if (comp->funcs) {
-   if (comp->funcs->gamma_set)
-   gamma_lut_size = MTK_LUT_SIZE;
+   if (comp->funcs->gamma_set && 
comp->funcs->gamma_get_lut_size)
+   gamma_lut_size = 
mtk_ddp_gamma_get_lut

[PATCH v5 02/11] drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common()

2023-06-01 Thread AngeloGioacchino Del Regno
Invert the check for state->gamma_lut and move it at the beginning
of the function to reduce indentation: this prepares the code for
keeping readability on later additions.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 45 ---
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 99be515a941b..ce6f2499b891 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -65,34 +65,35 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
u32 word;
u32 diff[3] = {0};
 
+   /* If there's no gamma lut there's nothing to do here. */
+   if (!state->gamma_lut)
+   return;
+
if (gamma && gamma->data)
lut_diff = gamma->data->lut_diff;
else
lut_diff = false;
 
-   if (state->gamma_lut) {
-   reg = readl(regs + DISP_GAMMA_CFG);
-   reg = reg | GAMMA_LUT_EN;
-   writel(reg, regs + DISP_GAMMA_CFG);
-   lut_base = regs + DISP_GAMMA_LUT;
-   lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < MTK_LUT_SIZE; i++) {
-
-   if (!lut_diff || (i % 2 == 0)) {
-   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 
20) +
-   (((lut[i].green >> 6) & LUT_10BIT_MASK) 
<< 10) +
-   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
-   } else {
-   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red 
>> 6);
-   diff[1] = (lut[i].green >> 6) - (lut[i - 
1].green >> 6);
-   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue 
>> 6);
-
-   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
-   ((diff[1] & LUT_10BIT_MASK) << 10) +
-   (diff[2] & LUT_10BIT_MASK);
-   }
-   writel(word, (lut_base + i * 4));
+   reg = readl(regs + DISP_GAMMA_CFG);
+   reg = reg | GAMMA_LUT_EN;
+   writel(reg, regs + DISP_GAMMA_CFG);
+   lut_base = regs + DISP_GAMMA_LUT;
+   lut = (struct drm_color_lut *)state->gamma_lut->data;
+   for (i = 0; i < MTK_LUT_SIZE; i++) {
+   if (!lut_diff || (i % 2 == 0)) {
+   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
+   (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
+   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+   } else {
+   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6);
+   diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6);
+   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6);
+
+   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
+   ((diff[1] & LUT_10BIT_MASK) << 10) +
+   (diff[2] & LUT_10BIT_MASK);
}
+   writel(word, (lut_base + i * 4));
}
 }
 
-- 
2.40.1



[PATCH v5 00/11] MediaTek DDP GAMMA - 12-bit LUT support

2023-06-01 Thread AngeloGioacchino Del Regno
Changes in v5:
 - Removed incorrect comment on default LUT size and bits
 - Removed useless check for num_lut_banks
 - Added comment about CMDQ implementation on patch 5
 - Evaluated passing lut size/bits from AAL, idea discarded as
   the implementation would be rather tricky while bringing no
   benefits.

Changes in v4:
 - Fixed assignment typo appeared in v3

Changes in v3:
 - Fixed issues due to variables renaming during cleanup (oops)
 - This is actually the right series, since v2 was taken from the
   wrong kernel tree :-)

Changes in v2:
 - Added explicit inclusion of linux/bitfield.h in patch [06/11]

This series adds support for GAMMA IP requiring and/or supporting
a 12-bits LUT using a slightly different register layout and programming
sequence for multiple LUT banks: this IP version is currently found
on a number of SoCs, not only including the Chromebook/IoT oriented
Kompanio 1200/1380 MT8195/MT8195T, but also Smartphone chips such as
the Dimensity 9200 (MT6985) and others.

This series was tested on MT8195, MT8192, MT8173, MT6795:
 * MT6795, MT8192, MT8173: No regression, works fine.
 * MT8195: Color correction is finally working!

AngeloGioacchino Del Regno (10):
  drm/mediatek: gamma: Reduce indentation in mtk_gamma_set_common()
  drm/mediatek: gamma: Support SoC specific LUT size
  drm/mediatek: gamma: Improve and simplify HW LUT calculation
  drm/mediatek: gamma: Enable the Gamma LUT table only after programming
  drm/mediatek: gamma: Use bitfield macros
  drm/mediatek: gamma: Support specifying number of bits per LUT
component
  drm/mediatek: gamma: Support multi-bank gamma LUT
  drm/mediatek: gamma: Add support for 12-bit LUT and MT8195
  drm/mediatek: gamma: Make sure relay mode is disabled
  drm/mediatek: gamma: Program gamma LUT type for descending or rising

Jason-JH.Lin (1):
  drm/mediatek: gamma: Adjust mtk_drm_gamma_set_common parameters

 drivers/gpu/drm/mediatek/mtk_disp_aal.c |   2 +-
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |   3 +-
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 193 
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |   4 +-
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |   1 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |   1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |   9 +
 7 files changed, 177 insertions(+), 36 deletions(-)

-- 
2.40.1



Re: RFC: DSI host capabilities (was: [PATCH RFC 03/10] drm/panel: Add LGD panel driver for Sony Xperia XZ3)

2023-05-31 Thread AngeloGioacchino Del Regno

Il 30/05/23 17:44, Neil Armstrong ha scritto:

On 30/05/2023 14:36, Dmitry Baryshkov wrote:

On 30/05/2023 15:15, AngeloGioacchino Del Regno wrote:

Il 30/05/23 13:44, Dmitry Baryshkov ha scritto:

On Tue, 30 May 2023 at 10:24, Neil Armstrong  wrote:


Hi Marijn, Dmitry, Caleb, Jessica,

On 29/05/2023 23:11, Marijn Suijten wrote:

On 2023-05-22 04:16:20, Dmitry Baryshkov wrote:


+   if (ctx->dsi->dsc) {


dsi->dsc is always set, thus this condition can be dropped.


I want to leave room for possibly running the panel without DSC (at a
lower resolution/refresh rate, or at higher power consumption if there
is enough BW) by not assigning the pointer, if we get access to panel
documentation: probably one of the magic commands sent in this driver
controls it but we don't know which.


I'd like to investigate if DSC should perhaps only be enabled if we
run non certain platforms/socs ?

I mean, we don't know if the controller supports DSC and those particular
DSC parameters so we should probably start adding something like :

static drm_dsc_config dsc_params_qcom = {}

static const struct of_device_id panel_of_dsc_params[] = {
 { .compatible = "qcom,sm8150", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8250", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8350", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8450", , .data = &dsc_params_qcom },
};


I think this would damage the reusability of the drivers. The panel
driver does not actually care if the SoC is SM8350, sunxi-something or
RCar.
Instead it cares about host capabilities.

I think instead we should extend mipi_dsi_host:

#define MIPI_DSI_HOST_MODE_VIDEO BIT(0)


I assume all DSI controller supports Video mode, so it should be a negative here
if for a reason it's not the case.


Either all positive or all negative... and yes I agree that all DSI controllers
support video mode nowadays, but:
 - Will that be true for future controllers? (likely yes, but you never know)
 - Is there any controller driver not implementing video mode?
   - Will there be one in the future?



There should also be a flag to tell if sending LP commands sending while
in HS Video mode is supported.



+1. This is the case for both qcom and mtk.


#define MIPI_DSI_HOST_MODE_CMD  BIT(1)
#define MIPI_DSI_HOST_VIDEO_SUPPORTS_COMMANDS BIT(2)
// FIXME: do we need to provide additional caps here ?

#define MIPI_DSI_DSC_1_1 BIT(0)
#define MIPI_DSI_DSC_1_2 BIT(1)
#define MIPI_DSI_DSC_NATIVE_422 BIT(2)
#define MIPI_DSI_DSC_NATIVE_420 BIT(3)
#define MIPI_DSI_DSC_FRAC_BPP BIT(4)
// etc.

struct mipi_dsi_host {
  // new fields only
   unsigned long mode_flags;
   unsigned long dsc_flags;
};

Then the panel driver can adapt itself to the host capabilities and
(possibly) select one of the internally supported DSC profiles.



I completely agree about extending mipi_dsi_host, other SoCs could reuse that 
and
support for DSC panels would become a lot cleaner.


Sounds good. I will wait for one or two more days (to get the possible feedback 
on fields/flags/etc) and post an RFC patch to dri-devel.


Good, I was waiting until a DSC panel appears on the list (and I failed to be the 
first), it's now the case.


For VTRD6130, the panel is capable of the 4 modes:
- video mode
- command mode
- video mode & DSC
- command mode & DSC

So it would need such info to enable one of the mode in some order to determine.



Dynamically determining is not trivial, as that depends on multiple variables:
 - Availability of the modes (obviously)
 - Available lanes
   - Available bandwidth per lane
 - Available total bandwidth
 - Power consumption considerations (DSC IP may be using more or less power
   depending on the actual SoC//controller)
   - Thermal management: DSC may make no thermal sense as in, more heat output
 vs thermal envelope (laptop vs embedded vs handset)
 - Others

Hence, the implementation should also provide a way of choosing a preferred mode
on a per-controller basis (DSC or no compression).

Just a few considerations that came to mind with a good sleep.

Cheers!


Thanks,
Neil




For example, on MediaTek DRM there's some support for DSC, more or less the same
for SPRD DRM and some DSI bridge drivers... having a clean infrastructure would
definitely help.

I'm sad I cannot offer testing in that case because despite being sure that 
there
are MTK smartphones around with DSI panels using DSC, I have none... and all of 
the
Chromebooks are not using DSC anyway (but using DisplayPort compression, which 
is
obviously an entirely different beast).



...
static int sony_akatsuki_lgd_probe(struct mipi_dsi_device *dsi)
...
 const struct of_device_id *match;

...
 match = of_match_node(panel_of_dsc_params, of_root);
 if (match && match->data) {
 dsi->dsc = devm_k

Re: RFC: DSI host capabilities (was: [PATCH RFC 03/10] drm/panel: Add LGD panel driver for Sony Xperia XZ3)

2023-05-30 Thread AngeloGioacchino Del Regno

Il 30/05/23 13:44, Dmitry Baryshkov ha scritto:

On Tue, 30 May 2023 at 10:24, Neil Armstrong  wrote:


Hi Marijn, Dmitry, Caleb, Jessica,

On 29/05/2023 23:11, Marijn Suijten wrote:

On 2023-05-22 04:16:20, Dmitry Baryshkov wrote:


+   if (ctx->dsi->dsc) {


dsi->dsc is always set, thus this condition can be dropped.


I want to leave room for possibly running the panel without DSC (at a
lower resolution/refresh rate, or at higher power consumption if there
is enough BW) by not assigning the pointer, if we get access to panel
documentation: probably one of the magic commands sent in this driver
controls it but we don't know which.


I'd like to investigate if DSC should perhaps only be enabled if we
run non certain platforms/socs ?

I mean, we don't know if the controller supports DSC and those particular
DSC parameters so we should probably start adding something like :

static drm_dsc_config dsc_params_qcom = {}

static const struct of_device_id panel_of_dsc_params[] = {
 { .compatible = "qcom,sm8150", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8250", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8350", , .data = &dsc_params_qcom },
 { .compatible = "qcom,sm8450", , .data = &dsc_params_qcom },
};


I think this would damage the reusability of the drivers. The panel
driver does not actually care if the SoC is SM8350, sunxi-something or
RCar.
Instead it cares about host capabilities.

I think instead we should extend mipi_dsi_host:

#define MIPI_DSI_HOST_MODE_VIDEO BIT(0)
#define MIPI_DSI_HOST_MODE_CMD  BIT(1)
#define MIPI_DSI_HOST_VIDEO_SUPPORTS_COMMANDS BIT(2)
// FIXME: do we need to provide additional caps here ?

#define MIPI_DSI_DSC_1_1 BIT(0)
#define MIPI_DSI_DSC_1_2 BIT(1)
#define MIPI_DSI_DSC_NATIVE_422 BIT(2)
#define MIPI_DSI_DSC_NATIVE_420 BIT(3)
#define MIPI_DSI_DSC_FRAC_BPP BIT(4)
// etc.

struct mipi_dsi_host {
  // new fields only
   unsigned long mode_flags;
   unsigned long dsc_flags;
};

Then the panel driver can adapt itself to the host capabilities and
(possibly) select one of the internally supported DSC profiles.



I completely agree about extending mipi_dsi_host, other SoCs could reuse that 
and
support for DSC panels would become a lot cleaner.

For example, on MediaTek DRM there's some support for DSC, more or less the same
for SPRD DRM and some DSI bridge drivers... having a clean infrastructure would
definitely help.

I'm sad I cannot offer testing in that case because despite being sure that 
there
are MTK smartphones around with DSI panels using DSC, I have none... and all of 
the
Chromebooks are not using DSC anyway (but using DisplayPort compression, which 
is
obviously an entirely different beast).



...
static int sony_akatsuki_lgd_probe(struct mipi_dsi_device *dsi)
...
 const struct of_device_id *match;

...
 match = of_match_node(panel_of_dsc_params, of_root);
 if (match && match->data) {
 dsi->dsc = devm_kzalloc(&dsi->dev, sizeof(*dsc), GFP_KERNEL);
 memcpy(dsi->dsc, match->data, sizeof(*dsc));
 } else {
 dev_warn(&dsi->dev, "DSI controller is not marked as supporting 
DSC\n");
 }
...
}

and probably bail out if it's a DSC only panel.



Usually DDICs support both DSC and non-DSC modes, depending on the initial
programming (read: init commands)... but the usual issue is that many DDICs
are not publicly documented for reasons, so yes, bailing out if DSC is not
supported would be the only option, and would be fine at this point.

Cheers,
Angelo


We could alternatively match on the DSI controller's dsi->host->dev instead of 
the SoC root compatible.

Neil






Re: [PATCH] phy: mediatek: hdmi: mt8195: fix prediv bad upper limit test

2023-05-30 Thread AngeloGioacchino Del Regno

Il 30/05/23 10:43, Guillaume Ranquet ha scritto:

The pll prediv calculus searchs for the smallest prediv that gets
the ns_hdmipll_ck in the range of 5 GHz to 12 GHz.

A typo in the upper bound test was testing for 5Ghz to 1Ghz

Fixes: 45810d486bb44 ("phy: mediatek: add support for phy-mtk-hdmi-mt8195")
Signed-off-by: Guillaume Ranquet 


Reviewed-by: AngeloGioacchino Del Regno 





Re: [PATCH v3 0/9] MediaTek DisplayPort: support eDP and aux-bus

2023-05-29 Thread AngeloGioacchino Del Regno

Il 04/04/23 12:47, AngeloGioacchino Del Regno ha scritto:

Hello CK,

Gentle ping for this series.

Thanks,
Angelo


Changes in v3:
  - Added DPTX AUX block initialization before trying to communicate
to stop relying on the bootloader keeping it initialized before
booting Linux.
  - Fixed commit description for patch [09/09] and removed commented
out code (that slipped from dev phase.. sorry!).

This series adds "real" support for eDP in the mtk-dp DisplayPort driver.

Explaining the "real":
Before this change, the DisplayPort driver did support eDP to some
extent, but it was treating it entirely like a regular DP interface
which is partially fine, after all, embedded DisplayPort *is* actually
DisplayPort, but there might be some differences to account for... and
this is for both small performance improvements and, more importantly,
for correct functionality in some systems.

Functionality first:

One of the common differences found in various boards implementing eDP
and machines using an eDP panel is that many times the HPD line is not
connected. This *must* be accounted for: at startup, this specific IP
will raise a HPD interrupt (which should maybe be ignored... as it does
not appear to be a "real" event...) that will make the eDP panel to be
detected and to actually work but, after a suspend-resume cycle, there
will be no HPD interrupt (as there's no HPD line in my case!) producing
a functionality issue - specifically, the DP Link Training fails because
the panel doesn't get powered up, then it stays black and won't work
until rebooting the machine (or removing and reinserting the module I
think, but I haven't tried that).

Now for.. both:
eDP panels are *e*DP because they are *not* removable (in the sense that
you can't unplug the cable without disassembling the machine, in which
case, the machine shall be powered down..!): this (correct) assumption
makes us able to solve some issues and to also gain a little performance
during PM operations.

What was done here is:
  - Caching the EDID if the panel is eDP: we're always going to read the
same data everytime, so we can just cache that (as it's small enough)
shortening PM resume times for the eDP driver instance;
  - Always return connector_status_connected if it's eDP: non-removable
means connector_status_disconnected can't happen during runtime...
this also saves us some time and even power, as we won't have to
perform yet another power cycle of the HW;
  - Added aux-bus support!
This makes us able to rely on panel autodetection from the EDID,
avoiding to add more and more panel timings to panel-edp and, even
better, allowing to use one panel node in devicetrees for multiple
variants of the same machine since, at that point, it's not important
to "preventively know" what panel we have (eh, it's autodetected...!).

This was tested on a MT8195 Cherry Tomato Chromebook (panel-edp on aux-bus)


P.S.: For your own testing commodity, here's a reference devicetree:
&edp_tx {
status = "okay";

pinctrl-names = "default";
pinctrl-0 = <&edptx_pins_default>;

ports {
#address-cells = <1>;
#size-cells = <0>;

port@0 {
reg = <0>;
edp_in: endpoint {
remote-endpoint = <&dp_intf0_out>;
};
};

port@1 {
reg = <1>;
edp_out: endpoint {
data-lanes = <0 1 2 3>;
remote-endpoint = <&panel_in>;
};
};
};

aux-bus {
panel: panel {
compatible = "edp-panel";
power-supply = <&pp3300_disp_x>;
backlight = <&backlight_lcd0>;
port {
        panel_in: endpoint {
remote-endpoint = <&edp_out>;
};
};
};
};
};

AngeloGioacchino Del Regno (9):
   drm/mediatek: dp: Cache EDID for eDP panel
   drm/mediatek: dp: Move AUX and panel poweron/off sequence to function
   drm/mediatek: dp: Always return connected status for eDP in .detect()
   drm/mediatek: dp: Always set cable_plugged_in at resume for eDP panel
   drm/mediatek: dp: Change logging to dev for mtk_dp_aux_transfer()
   drm/mediatek: dp: Enable event interrupt only when bridge attached
   drm/mediatek: dp: Use devm variant of drm_bridge_add()
   drm/mediatek: dp: Move AUX_P0 setting to
 mtk_dp_initialize_aux_settings()
   drm/mediatek: dp: Add support for embedded DisplayPort aux-bus

  drivers/gpu/drm/mediatek/mtk_dp.c | 186 +++---
  1 file changed, 116 insertions(+), 70 deletions(-)





Re: [PATCH 3/3] dw-hdmi: remove dead code and fix indentation

2023-05-29 Thread AngeloGioacchino Del Regno

Il 28/05/23 16:00, Adrián Larumbe ha scritto:

I agree that the title almost says it all, but please add a commit description.

Regards,
Angelo


Signed-off-by: Adrián Larumbe 
---
  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 22 --
  1 file changed, 4 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c 
b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 1afb8f2603a0..0accfb51509c 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -49,20 +49,6 @@
  
  #define HDMI14_MAX_TMDSCLK	34000
  
-enum hdmi_datamap {

-   RGB444_8B = 0x01,
-   RGB444_10B = 0x03,
-   RGB444_12B = 0x05,
-   RGB444_16B = 0x07,
-   YCbCr444_8B = 0x09,
-   YCbCr444_10B = 0x0B,
-   YCbCr444_12B = 0x0D,
-   YCbCr444_16B = 0x0F,
-   YCbCr422_8B = 0x16,
-   YCbCr422_10B = 0x14,
-   YCbCr422_12B = 0x12,
-};
-
  static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x, 0x, 0x },
{ 0x, 0x2000, 0x, 0x },
@@ -856,10 +842,10 @@ static void dw_hdmi_gp_audio_enable(struct dw_hdmi *hdmi)
  
  	if (pdata->enable_audio)

pdata->enable_audio(hdmi,
-   hdmi->channels,
-   hdmi->sample_width,
-   hdmi->sample_rate,
-   hdmi->sample_non_pcm);
+   hdmi->channels,
+   hdmi->sample_width,
+   hdmi->sample_rate,
+   hdmi->sample_non_pcm);
  }
  
  static void dw_hdmi_gp_audio_disable(struct dw_hdmi *hdmi)




Re: [PATCH] arm64: dts: mediatek: mt8173-elm: remove panel model number in DT

2023-05-29 Thread AngeloGioacchino Del Regno

Il 26/05/23 16:24, Doug Anderson ha scritto:

Hi,

On Fri, May 26, 2023 at 3:09 AM Icenowy Zheng  wrote:


Currently a specific panel number is used in the Elm DTSI, which is
corresponded to a 12" panel. However, according to the official Chrome
OS devices document, Elm refers to Acer Chromebook R13, which, as the
name specifies, uses a 13.3" panel, which comes with EDID information.

As the kernel currently prioritizes the hardcoded timing parameters
matched with the panel number compatible, a wrong timing will be applied
to the 13.3" panel on Acer Chromebook R13, which leads to blank display.

Because the Elm DTSI is shared with Hana board, and Hana corresponds to
multiple devices from 11" to 14", a certain panel model number shouldn't
be present, and driving the panel according to its EDID information is
necessary.

Signed-off-by: Icenowy Zheng 
---
  arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)


We went through a bunch of back-and-forth here but in the end in the
ChromeOS tree we have "edp-panel" as the "compatible" here in the
ChromeOS 5.15 tree and this makes sense.

Reviewed-by: Douglas Anderson 

...in theory one would wish for a "Fixes" tag, but I think in previous
discussions it was decided that it was too complicated. Hardcoding the
other compatible string has always been technically wrong, but I guess
it worked at some point in time. The more correct way (as you're doing
here) needs the DP AUX bus support and the generic eDP panels, both of
which are significantly newer than the elm dts. So I guess leaving no
"Fixes" tag is OK, or perhaps you could do the somewhat weak:

Fixes: c2d94f72140a ("arm64: dts: mediatek: mt8173-elm: Move display
to ps8640 auxiliary bus")


I remember I didn't change the compatible to panel-edp because it didn't
work at that time, but it does now... I'm not sure what actually fixed that
and if the commit(s) was/were backported to that suggested point, so I
would leave the Fixes tag out, as that may break older kernels.

Anyway, for this commit:

Reviewed-by: AngeloGioacchino Del Regno 



Re: [PATCH v4 03/11] drm/mediatek: gamma: Support SoC specific LUT size

2023-05-26 Thread AngeloGioacchino Del Regno

Il 26/05/23 07:20, CK Hu (胡俊光) ha scritto:

Hi, Angelo:

On Thu, 2023-05-18 at 12:48 +0200, AngeloGioacchino Del Regno wrote:

External email : Please do not click links or open attachments until
you have verified the sender or the content.


Newer SoCs support a bigger Gamma LUT table: wire up a callback
to retrieve the correct LUT size for each different Gamma IP.

Co-developed-by: Jason-JH.Lin 
Signed-off-by: Jason-JH.Lin 
[Angelo: Rewritten commit message/description + porting]
Signed-off-by: AngeloGioacchino Del Regno <
angelogioacchino.delre...@collabora.com>
Reviewed-by: Jason-JH.Lin 
---
  drivers/gpu/drm/mediatek/mtk_disp_drv.h |  1 +
  drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 25 ++-
--
  drivers/gpu/drm/mediatek/mtk_drm_crtc.c |  4 ++--
  drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  1 -
  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  1 +
  drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |  9 
  6 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 75045932353e..e554b19f4830 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -53,6 +53,7 @@ void mtk_gamma_clk_disable(struct device *dev);
  void mtk_gamma_config(struct device *dev, unsigned int w,
   unsigned int h, unsigned int vrefresh,
   unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_gamma_get_lut_size(struct device *dev);
  void mtk_gamma_set(struct device *dev, struct drm_crtc_state
*state);
  void mtk_gamma_set_common(struct device *dev, void __iomem *regs,
struct drm_crtc_state *state);
  void mtk_gamma_start(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index ce6f2499b891..d194d9bc2e2b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,10 +25,12 @@
  #define DISP_GAMMA_LUT 0x0700

  #define LUT_10BIT_MASK 0x03ff
+#define LUT_SIZE_DEFAULT   512 /* for setting
gamma lut from AAL */


I would like to place AAL definition in AAL driver and pass it to gamma
driver.



This is not only for AAL, actually; I should remove that comment as it
may actually be misleading.

The default LUT size (512) is relevant for both the AAL case and the
older SoCs, where the LUT size is 512 and no multi-register.

I'll remove that comment in the next version

Regards,
Angelo



Re: [PATCH v4 06/11] drm/mediatek: gamma: Use bitfield macros

2023-05-26 Thread AngeloGioacchino Del Regno

Il 26/05/23 07:32, CK Hu (胡俊光) ha scritto:

Hi, Angelo:

On Thu, 2023-05-18 at 12:48 +0200, AngeloGioacchino Del Regno wrote:

External email : Please do not click links or open attachments until
you have verified the sender or the content.


Make the code more robust and improve readability by using bitfield
macros instead of open coding bit operations.
While at it, also add a definition for LUT_BITS_DEFAULT.

Signed-off-by: AngeloGioacchino Del Regno <
angelogioacchino.delre...@collabora.com>
Reviewed-by: Jason-JH.Lin 
---
  drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 41 ++---
--
  1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 1592614b6de7..ed2aa1fb0171 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -3,6 +3,7 @@
   * Copyright (c) 2021 MediaTek Inc.
   */

+#include 
  #include 
  #include 
  #include 
@@ -22,9 +23,16 @@
  #define GAMMA_LUT_EN   BIT(1)
  #define
GAMMA_DITHERINGBIT(2)
  #define DISP_GAMMA_SIZE0x0030
+#define DISP_GAMMA_SIZE_HSIZE  GENMASK(28,
16)
+#define DISP_GAMMA_SIZE_VSIZE  GENMASK(12,
0)
  #define DISP_GAMMA_LUT 0x0700

+#define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
+#define DISP_GAMMA_LUT_10BIT_G GENMASK(19, 10)
+#define DISP_GAMMA_LUT_10BIT_B GENMASK(9, 0)
+
  #define LUT_10BIT_MASK 0x03ff
+#define LUT_BITS_DEFAULT   10


This is used only for AAL after patch "drm/mediatek: gamma: Support
specifying number of bits per LUT component", so I would like move AAL
definition to AAL driver and pass it to gamma driver.



Like LUT_SIZE_DEFAULT, this definition is not only for AAL but also for
the older gamma lut register layout.

In any case, I'll check if there's any clean way to pass AAL's gamma
size to this driver... it's a different "component", so this may get
complicated.

Let's see what I can come up with in v5...

Thanks,
Angelo



[PATCH 3/3] phy: mediatek: mipi-dsi: Compress of_device_id match entries

2023-05-25 Thread AngeloGioacchino Del Regno
All of the entries do fit in a maximum of 82 columns, which is
acceptable. While at it, also remove the useless comma on the
last entry and add the usual sentinel comment.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c 
b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
index 4e75c34c819b..065ea626093a 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
@@ -180,13 +180,10 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id mtk_mipi_tx_match[] = {
-   { .compatible = "mediatek,mt2701-mipi-tx",
- .data = &mt2701_mipitx_data },
-   { .compatible = "mediatek,mt8173-mipi-tx",
- .data = &mt8173_mipitx_data },
-   { .compatible = "mediatek,mt8183-mipi-tx",
- .data = &mt8183_mipitx_data },
-   { },
+   { .compatible = "mediatek,mt2701-mipi-tx", .data = &mt2701_mipitx_data 
},
+   { .compatible = "mediatek,mt8173-mipi-tx", .data = &mt8173_mipitx_data 
},
+   { .compatible = "mediatek,mt8183-mipi-tx", .data = &mt8183_mipitx_data 
},
+   { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match);
 
-- 
2.40.1



[PATCH 2/3] phy: mediatek: mipi-dsi: Use devm variant for of_clk_add_hw_provider()

2023-05-25 Thread AngeloGioacchino Del Regno
Switch to devm_of_clk_add_hw_provider() in the probe function: this
also allows to entirely remove the .remove_new() callback, as its
only task was to unregister the clock provider.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 8 +---
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c 
b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
index 362145198ff5..4e75c34c819b 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
@@ -176,12 +176,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 
mtk_mipi_tx_get_calibration_datal(mipi_tx);
 
-   return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, 
&mipi_tx->pll_hw);
-}
-
-static void mtk_mipi_tx_remove(struct platform_device *pdev)
-{
-   of_clk_del_provider(pdev->dev.of_node);
+   return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, 
&mipi_tx->pll_hw);
 }
 
 static const struct of_device_id mtk_mipi_tx_match[] = {
@@ -197,7 +192,6 @@ MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match);
 
 static struct platform_driver mtk_mipi_tx_driver = {
.probe = mtk_mipi_tx_probe,
-   .remove_new = mtk_mipi_tx_remove,
.driver = {
.name = "mediatek-mipi-tx",
.of_match_table = mtk_mipi_tx_match,
-- 
2.40.1



[PATCH 0/3] MediaTek MIPI-DSI PHY: Cleanups

2023-05-25 Thread AngeloGioacchino Del Regno
This series performs some cleanups to the MediaTek mipi-dsi PHY, used in
various MediaTek SoCs; in particular, it's migrating this driver to
register its clock as clk_hw provider instead and makes use of the devm
function for the same, allowing to remove a pointer to struct clk and
the whole .remove_new() callback, as it's not needed anymore.
This also cleans up the of_device_id table.

Tested on MT8173, MT8192 Chromebooks, MT6795 Xperia M5 smartphone.

AngeloGioacchino Del Regno (3):
  phy: mediatek: mipi-dsi: Convert to register clk_hw
  phy: mediatek: mipi-dsi: Use devm variant for of_clk_add_hw_provider()
  phy: mediatek: mipi-dsi: Compress of_device_id match entries

 drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 30 +
 drivers/phy/mediatek/phy-mtk-mipi-dsi.h |  1 -
 2 files changed, 10 insertions(+), 21 deletions(-)

-- 
2.40.1



[PATCH 1/3] phy: mediatek: mipi-dsi: Convert to register clk_hw

2023-05-25 Thread AngeloGioacchino Del Regno
Instead of registering a struct clk, directly register clk_hw: this
allows us to cleanup a pointer to struct clk from struct mtk_mipi_tx.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 13 ++---
 drivers/phy/mediatek/phy-mtk-mipi-dsi.h |  1 -
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c 
b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
index 526c05a4af5e..362145198ff5 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
@@ -36,7 +36,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy)
int ret;
 
/* Power up core and enable PLL */
-   ret = clk_prepare_enable(mipi_tx->pll);
+   ret = clk_prepare_enable(mipi_tx->pll_hw.clk);
if (ret < 0)
return ret;
 
@@ -53,7 +53,7 @@ static int mtk_mipi_tx_power_off(struct phy *phy)
mipi_tx->driver_data->mipi_tx_disable_signal(phy);
 
/* Disable PLL and power down core */
-   clk_disable_unprepare(mipi_tx->pll);
+   clk_disable_unprepare(mipi_tx->pll_hw.clk);
 
return 0;
 }
@@ -158,9 +158,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
clk_init.ops = mipi_tx->driver_data->mipi_tx_clk_ops;
 
mipi_tx->pll_hw.init = &clk_init;
-   mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw);
-   if (IS_ERR(mipi_tx->pll))
-   return dev_err_probe(dev, PTR_ERR(mipi_tx->pll), "Failed to 
register PLL\n");
+   ret = devm_clk_hw_register(dev, &mipi_tx->pll_hw);
+   if (ret)
+   return dev_err_probe(dev, ret, "Failed to register PLL\n");
 
phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops);
if (IS_ERR(phy))
@@ -176,8 +176,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
 
mtk_mipi_tx_get_calibration_datal(mipi_tx);
 
-   return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
-  mipi_tx->pll);
+   return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, 
&mipi_tx->pll_hw);
 }
 
 static void mtk_mipi_tx_remove(struct platform_device *pdev)
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h 
b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
index 47b60b1a7226..0250c4a454e7 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h
@@ -32,7 +32,6 @@ struct mtk_mipi_tx {
u32 rt_code[5];
const struct mtk_mipitx_data *driver_data;
struct clk_hw pll_hw;
-   struct clk *pll;
 };
 
 struct mtk_mipi_tx *mtk_mipi_tx_from_clk_hw(struct clk_hw *hw);
-- 
2.40.1



Re: [PATCH v3 1/3] dt-bindings: phy: add PHY_TYPE_CDPHY definition

2023-05-24 Thread AngeloGioacchino Del Regno

Il 24/05/23 10:30, Julien Stephan ha scritto:

Add definition for CDPHY phy type that can be configured in either D-PHY
mode or C-PHY mode

Signed-off-by: Julien Stephan 


Reviewed-by: AngeloGioacchino Del Regno 



---
  include/dt-bindings/phy/phy.h | 1 +
  1 file changed, 1 insertion(+)

diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6b901b342348..a19d85dbbf16 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -23,5 +23,6 @@
  #define PHY_TYPE_DPHY 10
  #define PHY_TYPE_CPHY 11
  #define PHY_TYPE_USXGMII  12
+#define PHY_TYPE_CDPHY 13
  
  #endif /* _DT_BINDINGS_PHY */




Re: [PATCH v3 2/3] dt-bindings: phy: add mediatek MIPI CD-PHY module v0.5

2023-05-24 Thread AngeloGioacchino Del Regno

Il 24/05/23 10:30, Julien Stephan ha scritto:

From: Florian Sylvestre 

This adds the bindings, for the MIPI CD-PHY module v0.5 embedded in
some Mediatek soc, such as the mt8365

Signed-off-by: Florian Sylvestre 
Signed-off-by: Julien Stephan 
---
  .../bindings/phy/mediatek,mt8365-csi-rx.yaml  | 67 +++
  MAINTAINERS   |  6 ++
  2 files changed, 73 insertions(+)
  create mode 100644 
Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml

diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml 
b/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml
new file mode 100644
index ..a1bd96a98051
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/mediatek,mt8365-csi-rx.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2023 MediaTek, BayLibre
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/mediatek,mt8365-csi-rx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek Sensor Interface MIPI CSI CD-PHY
+
+maintainers:
+  - Julien Stephan 
+  - Andy Hsieh 
+
+description:
+  The SENINF CD-PHY is a set of CD-PHY connected to the SENINF CSI-2
+  receivers. The number of PHYs depends on the SoC model.
+  Depending on the SoC model, each PHYs can be either CD-PHY or D-PHY only
+  capable.
+
+properties:
+  compatible:
+enum:
+  - mediatek,mt8365-csi-rx
+
+  reg:
+maxItems: 1
+
+  '#phy-cells':
+const: 0
+
+  mediatek,phy-type:


Instead of declaring a phy-type here like this, can't we instead declare that in
the phy cells, like we're doing with MTK TPHY and like other non-MediaTek PHYs 
are
already doing?

device {
...
phys = <&csi0_rx PHY_TYPE_CDPHY>;
...
}

Regards,
Angelo




[PATCH v1 2/4] drm/mediatek: dsi: Cleanup functions mtk_dsi_ps_control{_vact}()

2023-05-24 Thread AngeloGioacchino Del Regno
Function mtk_dsi_ps_control() is a subset of mtk_dsi_ps_control_vact():
merge the two in one mtk_dsi_ps_control() function by adding one
function parameter `config_vact` which, when true, writes the VACT
related registers.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 76 +-
 1 file changed, 23 insertions(+), 53 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 246a3a338c1e..97d5b3083057 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -350,40 +350,6 @@ static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN);
 }
 
-static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi)
-{
-   struct videomode *vm = &dsi->vm;
-   u32 dsi_buf_bpp, ps_wc;
-   u32 ps_bpp_mode;
-
-   if (dsi->format == MIPI_DSI_FMT_RGB565)
-   dsi_buf_bpp = 2;
-   else
-   dsi_buf_bpp = 3;
-
-   ps_wc = vm->hactive * dsi_buf_bpp;
-   ps_bpp_mode = ps_wc;
-
-   switch (dsi->format) {
-   case MIPI_DSI_FMT_RGB888:
-   ps_bpp_mode |= PACKED_PS_24BIT_RGB888;
-   break;
-   case MIPI_DSI_FMT_RGB666:
-   ps_bpp_mode |= PACKED_PS_18BIT_RGB666;
-   break;
-   case MIPI_DSI_FMT_RGB666_PACKED:
-   ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666;
-   break;
-   case MIPI_DSI_FMT_RGB565:
-   ps_bpp_mode |= PACKED_PS_16BIT_RGB565;
-   break;
-   }
-
-   writel(vm->vactive, dsi->regs + DSI_VACT_NL);
-   writel(ps_bpp_mode, dsi->regs + DSI_PSCTRL);
-   writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
-}
-
 static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
 {
u32 tmp_reg;
@@ -415,36 +381,40 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
 }
 
-static void mtk_dsi_ps_control(struct mtk_dsi *dsi)
+static void mtk_dsi_ps_control(struct mtk_dsi *dsi, bool config_vact)
 {
-   u32 dsi_tmp_buf_bpp;
-   u32 tmp_reg;
+   struct videomode *vm = &dsi->vm;
+   u32 dsi_buf_bpp, ps_wc;
+   u32 ps_bpp_mode;
+
+   if (dsi->format == MIPI_DSI_FMT_RGB565)
+   dsi_buf_bpp = 2;
+   else
+   dsi_buf_bpp = 3;
+
+   ps_wc = vm->hactive * dsi_buf_bpp;
+   ps_bpp_mode = ps_wc;
 
switch (dsi->format) {
case MIPI_DSI_FMT_RGB888:
-   tmp_reg = PACKED_PS_24BIT_RGB888;
-   dsi_tmp_buf_bpp = 3;
+   ps_bpp_mode |= PACKED_PS_24BIT_RGB888;
break;
case MIPI_DSI_FMT_RGB666:
-   tmp_reg = LOOSELY_PS_18BIT_RGB666;
-   dsi_tmp_buf_bpp = 3;
+   ps_bpp_mode |= PACKED_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
-   tmp_reg = PACKED_PS_18BIT_RGB666;
-   dsi_tmp_buf_bpp = 3;
+   ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB565:
-   tmp_reg = PACKED_PS_16BIT_RGB565;
-   dsi_tmp_buf_bpp = 2;
-   break;
-   default:
-   tmp_reg = PACKED_PS_24BIT_RGB888;
-   dsi_tmp_buf_bpp = 3;
+   ps_bpp_mode |= PACKED_PS_16BIT_RGB565;
break;
}
 
-   tmp_reg += dsi->vm.hactive * dsi_tmp_buf_bpp & DSI_PS_WC;
-   writel(tmp_reg, dsi->regs + DSI_PSCTRL);
+   if (config_vact) {
+   writel(vm->vactive, dsi->regs + DSI_VACT_NL);
+   writel(ps_wc, dsi->regs + DSI_HSTX_CKL_WC);
+   }
+   writel(ps_bpp_mode, dsi->regs + DSI_PSCTRL);
 }
 
 static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
@@ -520,7 +490,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
writel(horizontal_backporch_byte, dsi->regs + DSI_HBP_WC);
writel(horizontal_frontporch_byte, dsi->regs + DSI_HFP_WC);
 
-   mtk_dsi_ps_control(dsi);
+   mtk_dsi_ps_control(dsi, false);
 }
 
 static void mtk_dsi_start(struct mtk_dsi *dsi)
@@ -665,7 +635,7 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
mtk_dsi_reset_engine(dsi);
mtk_dsi_phy_timconfig(dsi);
 
-   mtk_dsi_ps_control_vact(dsi);
+   mtk_dsi_ps_control(dsi, true);
mtk_dsi_set_vm_cmd(dsi);
mtk_dsi_config_vdo_timing(dsi);
mtk_dsi_set_interrupt_enable(dsi);
-- 
2.40.1



[PATCH v1 3/4] drm/mediatek: dsi: Use bitfield macros where useful

2023-05-24 Thread AngeloGioacchino Del Regno
Instead of open coding bitshifting for various register fields,
use the bitfield macro FIELD_PREP(): this allows to enhance the
human readability, decrease likeliness of mistakes (and register
field overflowing) and also to simplify the code.
The latter is especially seen in mtk_dsi_rxtx_control(), where
it was possible to change a switch to a short for loop and to
also remove the need to check for maximum DSI lanes == 4 thanks
to the FIELD_PREP macro masking the value.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 95 --
 1 file changed, 50 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 97d5b3083057..fbf1c232107d 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -70,16 +70,19 @@
 #define DSI_PSCTRL 0x1c
 #define DSI_PS_WC  GENMASK(14, 0)
 #define DSI_PS_SEL GENMASK(19, 16)
-#define PACKED_PS_16BIT_RGB565 (0 << 16)
-#define LOOSELY_PS_18BIT_RGB666(1 << 16)
-#define PACKED_PS_18BIT_RGB666 (2 << 16)
-#define PACKED_PS_24BIT_RGB888 (3 << 16)
+#define PACKED_PS_16BIT_RGB565 0
+#define LOOSELY_PS_18BIT_RGB6661
+#define PACKED_PS_18BIT_RGB666 2
+#define PACKED_PS_24BIT_RGB888 3
 
 #define DSI_VSA_NL 0x20
 #define DSI_VBP_NL 0x24
 #define DSI_VFP_NL 0x28
 #define DSI_VACT_NL0x2C
+#define VACT_NLGENMASK(14, 0)
 #define DSI_SIZE_CON   0x38
+#define DSI_HEIGHT GENMASK(30, 16)
+#define DSI_WIDTH  GENMASK(14, 0)
 #define DSI_HSA_WC 0x50
 #define DSI_HBP_WC 0x54
 #define DSI_HFP_WC 0x58
@@ -252,14 +255,23 @@ static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
timing->clk_hs_zero = timing->clk_hs_trail * 4;
timing->clk_hs_exit = 2 * timing->clk_hs_trail;
 
-   timcon0 = timing->lpx | timing->da_hs_prepare << 8 |
- timing->da_hs_zero << 16 | timing->da_hs_trail << 24;
-   timcon1 = timing->ta_go | timing->ta_sure << 8 |
- timing->ta_get << 16 | timing->da_hs_exit << 24;
-   timcon2 = 1 << 8 | timing->clk_hs_zero << 16 |
- timing->clk_hs_trail << 24;
-   timcon3 = timing->clk_hs_prepare | timing->clk_hs_post << 8 |
- timing->clk_hs_exit << 16;
+   timcon0 = FIELD_PREP(LPX, timing->lpx) |
+ FIELD_PREP(HS_PREP, timing->da_hs_prepare) |
+ FIELD_PREP(HS_ZERO, timing->da_hs_zero) |
+ FIELD_PREP(HS_TRAIL, timing->da_hs_trail);
+
+   timcon1 = FIELD_PREP(TA_GO, timing->ta_go) |
+ FIELD_PREP(TA_SURE, timing->ta_sure) |
+ FIELD_PREP(TA_GET, timing->ta_get) |
+ FIELD_PREP(DA_HS_EXIT, timing->da_hs_exit);
+
+   timcon2 = FIELD_PREP(DA_HS_SYNC, 1) |
+ FIELD_PREP(CLK_ZERO, timing->clk_hs_zero) |
+ FIELD_PREP(CLK_TRAIL, timing->clk_hs_trail);
+
+   timcon3 = FIELD_PREP(CLK_HS_PREP, timing->clk_hs_prepare) |
+ FIELD_PREP(CLK_HS_POST, timing->clk_hs_post) |
+ FIELD_PREP(CLK_HS_EXIT, timing->clk_hs_exit);
 
writel(timcon0, dsi->regs + DSI_PHY_TIMECON0);
writel(timcon1, dsi->regs + DSI_PHY_TIMECON1);
@@ -352,69 +364,61 @@ static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi)
 
 static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
 {
-   u32 tmp_reg;
+   u32 regval, tmp_reg = 0;
+   u8 i;
 
-   switch (dsi->lanes) {
-   case 1:
-   tmp_reg = 1 << 2;
-   break;
-   case 2:
-   tmp_reg = 3 << 2;
-   break;
-   case 3:
-   tmp_reg = 7 << 2;
-   break;
-   case 4:
-   tmp_reg = 0xf << 2;
-   break;
-   default:
-   tmp_reg = 0xf << 2;
-   break;
-   }
+   /* Number of DSI lanes (max 4 lanes), each bit enables one DSI lane. */
+   for (i = 0; i < dsi->lanes; i++)
+   tmp_reg |= BIT(i);
+
+   regval = FIELD_PREP(LANE_NUM, tmp_reg);
 
if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
-   tmp_reg |= HSTX_CKLP_EN;
+   regval |= HSTX_CKLP_EN;
 
if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
-   tmp_reg |= DIS_EOT;
+   regval |= DIS_EOT;
 
-   writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
+   writel(regval, dsi->regs + DSI_TXRX_CTRL);
 }
 
 static void mtk_dsi_ps_

[PATCH v1 0/4] MediaTek DRM - DSI driver cleanups

2023-05-24 Thread AngeloGioacchino Del Regno
This series performs some cleanups for mtk_dsi, enhancing human
readability, using kernel provided macros where possible and
also reducing code size.

Tested on MT8173 and MT8192 Chromebooks (using a DSI<->DP bridge)
and on MT6795 Sony Xperia M5 (DSI video mode panel).

Please note:
This series depends and can be applied only on top of [1].

[1]: 
https://lore.kernel.org/lkml/20230523104234.7849-1-angelogioacchino.delre...@collabora.com/

AngeloGioacchino Del Regno (4):
  drm/mediatek: dsi: Use GENMASK() for register mask definitions
  drm/mediatek: dsi: Cleanup functions mtk_dsi_ps_control{_vact}()
  drm/mediatek: dsi: Use bitfield macros where useful
  drm/mediatek: dsi: Replace open-coded instance of HZ_PER_MHZ

 drivers/gpu/drm/mediatek/mtk_dsi.c | 198 +
 1 file changed, 88 insertions(+), 110 deletions(-)

-- 
2.40.1



[PATCH v1 4/4] drm/mediatek: dsi: Replace open-coded instance of HZ_PER_MHZ

2023-05-24 Thread AngeloGioacchino Del Regno
In mtk_dsi_phy_timconfig(), we're dividing the `data_rate` variable,
expressed in Hz to retrieve a value in MHz: instead of open-coding,
use the HZ_PER_MHZ definition, available in linux/units.h.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index fbf1c232107d..19e2b042c9d5 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -235,7 +236,7 @@ static void mtk_dsi_mask(struct mtk_dsi *dsi, u32 offset, 
u32 mask, u32 data)
 static void mtk_dsi_phy_timconfig(struct mtk_dsi *dsi)
 {
u32 timcon0, timcon1, timcon2, timcon3;
-   u32 data_rate_mhz = DIV_ROUND_UP(dsi->data_rate, 100);
+   u32 data_rate_mhz = DIV_ROUND_UP(dsi->data_rate, HZ_PER_MHZ);
struct mtk_phy_timing *timing = &dsi->phy_timing;
 
timing->lpx = (60 * data_rate_mhz / (8 * 1000)) + 1;
-- 
2.40.1



[PATCH v1 1/4] drm/mediatek: dsi: Use GENMASK() for register mask definitions

2023-05-24 Thread AngeloGioacchino Del Regno
Change magic numerical masks with usage of the GENMASK() macro
to improve readability.

This commit brings no functional changes.

Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 46 --
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index b0ab38e59db9..246a3a338c1e 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -58,18 +58,18 @@
 
 #define DSI_TXRX_CTRL  0x18
 #define VC_NUM BIT(1)
-#define LANE_NUM   (0xf << 2)
+#define LANE_NUM   GENMASK(5, 2)
 #define DIS_EOTBIT(6)
 #define NULL_ENBIT(7)
 #define TE_FREERUN BIT(8)
 #define EXT_TE_EN  BIT(9)
 #define EXT_TE_EDGEBIT(10)
-#define MAX_RTN_SIZE   (0xf << 12)
+#define MAX_RTN_SIZE   GENMASK(15, 12)
 #define HSTX_CKLP_EN   BIT(16)
 
 #define DSI_PSCTRL 0x1c
-#define DSI_PS_WC  0x3fff
-#define DSI_PS_SEL (3 << 16)
+#define DSI_PS_WC  GENMASK(14, 0)
+#define DSI_PS_SEL GENMASK(19, 16)
 #define PACKED_PS_16BIT_RGB565 (0 << 16)
 #define LOOSELY_PS_18BIT_RGB666(1 << 16)
 #define PACKED_PS_18BIT_RGB666 (2 << 16)
@@ -108,26 +108,27 @@
 #define LD0_WAKEUP_EN  BIT(2)
 
 #define DSI_PHY_TIMECON0   0x110
-#define LPX(0xff << 0)
-#define HS_PREP(0xff << 8)
-#define HS_ZERO(0xff << 16)
-#define HS_TRAIL   (0xff << 24)
+#define LPXGENMASK(7, 0)
+#define HS_PREPGENMASK(15, 8)
+#define HS_ZEROGENMASK(23, 16)
+#define HS_TRAIL   GENMASK(31, 24)
 
 #define DSI_PHY_TIMECON1   0x114
-#define TA_GO  (0xff << 0)
-#define TA_SURE(0xff << 8)
-#define TA_GET (0xff << 16)
-#define DA_HS_EXIT (0xff << 24)
+#define TA_GO  GENMASK(7, 0)
+#define TA_SUREGENMASK(15, 8)
+#define TA_GET GENMASK(23, 16)
+#define DA_HS_EXIT GENMASK(31, 24)
 
 #define DSI_PHY_TIMECON2   0x118
-#define CONT_DET   (0xff << 0)
-#define CLK_ZERO   (0xff << 16)
-#define CLK_TRAIL  (0xff << 24)
+#define CONT_DET   GENMASK(7, 0)
+#define DA_HS_SYNC GENMASK(15, 8)
+#define CLK_ZERO   GENMASK(23, 16)
+#define CLK_TRAIL  GENMASK(31, 24)
 
 #define DSI_PHY_TIMECON3   0x11c
-#define CLK_HS_PREP(0xff << 0)
-#define CLK_HS_POST(0xff << 8)
-#define CLK_HS_EXIT(0xff << 16)
+#define CLK_HS_PREPGENMASK(7, 0)
+#define CLK_HS_POSTGENMASK(15, 8)
+#define CLK_HS_EXITGENMASK(23, 16)
 
 #define DSI_VM_CMD_CON 0x130
 #define VM_CMD_EN  BIT(0)
@@ -137,13 +138,14 @@
 #define FORCE_COMMIT   BIT(0)
 #define BYPASS_SHADOW  BIT(1)
 
-#define CONFIG (0xff << 0)
+/* CMDQ related bits */
+#define CONFIG GENMASK(7, 0)
 #define SHORT_PACKET   0
 #define LONG_PACKET2
 #define BTABIT(2)
-#define DATA_ID(0xff << 8)
-#define DATA_0 (0xff << 16)
-#define DATA_1 (0xff << 24)
+#define DATA_IDGENMASK(15, 8)
+#define DATA_0 GENMASK(23, 16)
+#define DATA_1 GENMASK(31, 24)
 
 #define NS_TO_CYCLE(n, c)((n) / (c) + (((n) % (c)) ? 1 : 0))
 
-- 
2.40.1



[PATCH] drm: mediatek: mtk_dsi: Fix NO_EOT_PACKET settings/handling

2023-05-23 Thread AngeloGioacchino Del Regno
Due to the initial confusion about MIPI_DSI_MODE_EOT_PACKET, properly
renamed to MIPI_DSI_MODE_NO_EOT_PACKET, reflecting its actual meaning,
both the DSI_TXRX_CON register setting for bit (HSTX_)DIS_EOT and the
later calculation for horizontal sync-active (HSA), back (HBP) and
front (HFP) porches got incorrect due to the logic being inverted.

This means that a number of settings were wrong because:
 - DSI_TXRX_CON register setting: bit (HSTX_)DIS_EOT should be
   set in order to disable the End of Transmission packet;
 - Horizontal Sync and Back/Front porches: The delta used to
   calculate all of HSA, HBP and HFP should account for the
   additional EOT packet.

Before this change...
 - Bit (HSTX_)DIS_EOT was being set when EOT packet was enabled;
 - For HSA/HBP/HFP delta... all three were wrong, as words were
   added when EOT disabled, instead of when EOT packet enabled!

Invert the logic around flag MIPI_DSI_MODE_NO_EOT_PACKET in the
MediaTek DSI driver to fix the aforementioned issues.

Fixes: 8b2b99fd7931 ("drm/mediatek: dsi: Fine tune the line time caused by 
EOTp")
Fixes: 2d52bfba09d1 ("drm/mediatek: add non-continuous clock mode and EOT 
packet control")
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_dsi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c 
b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 7d5250351193..b0ab38e59db9 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -407,7 +407,7 @@ static void mtk_dsi_rxtx_control(struct mtk_dsi *dsi)
if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
tmp_reg |= HSTX_CKLP_EN;
 
-   if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET))
+   if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
tmp_reg |= DIS_EOT;
 
writel(tmp_reg, dsi->regs + DSI_TXRX_CTRL);
@@ -484,7 +484,7 @@ static void mtk_dsi_config_vdo_timing(struct mtk_dsi *dsi)
  timing->da_hs_zero + timing->da_hs_exit + 3;
 
delta = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? 18 : 12;
-   delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 2 : 0;
+   delta += dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET ? 0 : 2;
 
horizontal_frontporch_byte = vm->hfront_porch * dsi_tmp_buf_bpp;
horizontal_front_back_byte = horizontal_frontporch_byte + 
horizontal_backporch_byte;
-- 
2.40.1



Re: [PATCH v4 05/11] drm/mediatek: gamma: Enable the Gamma LUT table only after programming

2023-05-22 Thread AngeloGioacchino Del Regno

Il 22/05/23 12:00, CK Hu (胡俊光) ha scritto:

Hi, Angelo:

On Thu, 2023-05-18 at 12:48 +0200, AngeloGioacchino Del Regno wrote:

External email : Please do not click links or open attachments until
you have verified the sender or the content.


Move the write to DISP_GAMMA_CFG to enable the Gamma LUT to after
programming the actual table to avoid potential visual glitches
during
table modification.


I think user could update the lut table frequently, so when do you
disable the gamma function before next update? In addition, if we
really care the glitches, update the register in vblank period which
should use cmdq to update the register. But now, I think we do not care
the glitches. You may skip this patch, or fix the problem I mention.



If you disable the GAMMA function (either set RELAY mode or disable the
GAMMA_LUT_EN bit in GAMMA_CFG), there will be glitches during setting via
the GNOME Night Mode color temperature slider.

This commit prevents a glitch in the case in which the GAMMA LUT registers
are not zeroed before setting the expected LUT, for which reason I disagree
about skipping this patch.

Please note that, while I agree about updating the GAMMA LUT through CMDQ
setting and between vblanks, this requires a lot more effort to implement
and it's out of scope for this specific series; depending on my bandwidth,
this may come later and it would in any case require this patch to move
the LUT enablement to after LUT registers setting. Besides, I have already
tried to enable this through CMDQ, but didn't work as expected and since I
had no time to dig further, I deemed this to be essential for at least an
initial functionality implementation for MT8195, and a cleanup of this
driver.
Obviously, the *only* way to fix *all* of the corner cases of the problem
that you mentioned is to use CMDQ and trying to implement this purely with
cpu writes will in any case be prone to at least some glitches.

In any case, while your concern is valid, I'm sure that you agree with me
on the fact that enabling the LUT before actually programming it is something
that should not happen in principle. For this reason, and for the others that
I've just mentioned, I think that this patch is totally valid.

Regards,
Angelo


Regards,
CK



Signed-off-by: AngeloGioacchino Del Regno <
angelogioacchino.delre...@collabora.com>
Reviewed-by: Jason-JH.Lin 
---
  drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 13 -
  1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 60ccea8c1e1a..1592614b6de7 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -71,12 +71,12 @@ unsigned int mtk_gamma_get_lut_size(struct device
*dev)
  void mtk_gamma_set_common(struct device *dev, void __iomem *regs,
struct drm_crtc_state *state)
  {
 struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
-   unsigned int i, reg;
+   unsigned int i;
 struct drm_color_lut *lut;
 void __iomem *lut_base;
 bool lut_diff;
 u16 lut_size;
-   u32 word;
+   u32 cfg_val, word;

 /* If there's no gamma lut there's nothing to do here. */
 if (!state->gamma_lut)
@@ -90,9 +90,7 @@ void mtk_gamma_set_common(struct device *dev, void
__iomem *regs, struct drm_crt
 lut_size = LUT_SIZE_DEFAULT;
 }

-   reg = readl(regs + DISP_GAMMA_CFG);
-   reg = reg | GAMMA_LUT_EN;
-   writel(reg, regs + DISP_GAMMA_CFG);
+   cfg_val = readl(regs + DISP_GAMMA_CFG);
 lut_base = regs + DISP_GAMMA_LUT;
 lut = (struct drm_color_lut *)state->gamma_lut->data;
 for (i = 0; i < lut_size; i++) {
@@ -122,6 +120,11 @@ void mtk_gamma_set_common(struct device *dev,
void __iomem *regs, struct drm_crt
 }
 writel(word, (lut_base + i * 4));
 }
+
+   /* Enable the gamma table */
+   cfg_val = cfg_val | GAMMA_LUT_EN;
+
+   writel(cfg_val, regs + DISP_GAMMA_CFG);
  }

  void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
--
2.40.1





[PATCH v4 03/11] drm/mediatek: gamma: Support SoC specific LUT size

2023-05-18 Thread AngeloGioacchino Del Regno
Newer SoCs support a bigger Gamma LUT table: wire up a callback
to retrieve the correct LUT size for each different Gamma IP.

Co-developed-by: Jason-JH.Lin 
Signed-off-by: Jason-JH.Lin 
[Angelo: Rewritten commit message/description + porting]
Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_drv.h |  1 +
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c   | 25 ++---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c |  4 ++--
 drivers/gpu/drm/mediatek/mtk_drm_crtc.h |  1 -
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c |  1 +
 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h |  9 
 6 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h 
b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 75045932353e..e554b19f4830 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -53,6 +53,7 @@ void mtk_gamma_clk_disable(struct device *dev);
 void mtk_gamma_config(struct device *dev, unsigned int w,
  unsigned int h, unsigned int vrefresh,
  unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_gamma_get_lut_size(struct device *dev);
 void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state);
 void mtk_gamma_start(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index ce6f2499b891..d194d9bc2e2b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,10 +25,12 @@
 #define DISP_GAMMA_LUT 0x0700
 
 #define LUT_10BIT_MASK 0x03ff
+#define LUT_SIZE_DEFAULT   512 /* for setting gamma lut 
from AAL */
 
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_size;
 };
 
 /*
@@ -55,6 +57,17 @@ void mtk_gamma_clk_disable(struct device *dev)
clk_disable_unprepare(gamma->clk);
 }
 
+unsigned int mtk_gamma_get_lut_size(struct device *dev)
+{
+   struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+   unsigned int lut_size = LUT_SIZE_DEFAULT;
+
+   if (gamma && gamma->data)
+   lut_size = gamma->data->lut_size;
+
+   return lut_size;
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -62,6 +75,7 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
+   u16 lut_size;
u32 word;
u32 diff[3] = {0};
 
@@ -69,17 +83,20 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
if (!state->gamma_lut)
return;
 
-   if (gamma && gamma->data)
+   if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
-   else
+   lut_size = gamma->data->lut_size;
+   } else {
lut_diff = false;
+   lut_size = LUT_SIZE_DEFAULT;
+   }
 
reg = readl(regs + DISP_GAMMA_CFG);
reg = reg | GAMMA_LUT_EN;
writel(reg, regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < MTK_LUT_SIZE; i++) {
+   for (i = 0; i < lut_size; i++) {
if (!lut_diff || (i % 2 == 0)) {
word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
(((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
@@ -196,10 +213,12 @@ static int mtk_disp_gamma_remove(struct platform_device 
*pdev)
 
 static const struct mtk_disp_gamma_data mt8173_gamma_driver_data = {
.has_dither = true,
+   .lut_size = 512,
 };
 
 static const struct mtk_disp_gamma_data mt8183_gamma_driver_data = {
.lut_diff = true,
+   .lut_size = 512,
 };
 
 static const struct of_device_id mtk_disp_gamma_driver_dt_match[] = {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index d40142842f85..0df62b076f49 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -958,8 +958,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
mtk_crtc->ddp_comp[i] = comp;
 
if (comp->funcs) {
-   if (comp->funcs->gamma_set)
-   gamma_lut_size = MTK_LUT_SIZE;
+   if (comp->funcs->gamma_set && 
comp->funcs->gamma_get_lut_size)
+

[PATCH v4 08/11] drm/mediatek: gamma: Support multi-bank gamma LUT

2023-05-18 Thread AngeloGioacchino Del Regno
Newer Gamma IP have got multiple LUT banks: support specifying the
size of the LUT banks and handle bank-switching before programming
the LUT in mtk_gamma_set_common() in preparation for adding support
for MT8195 and newer SoCs.

Suggested-by: Jason-JH.Lin 
[Angelo: Refactored original commit]
Signed-off-by: AngeloGioacchino Del Regno 

---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 78 +++
 1 file changed, 51 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 62e1e50d2671..a05c445367ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -25,6 +25,8 @@
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
+#define DISP_GAMMA_BANK0x0100
+#define DISP_GAMMA_BANK_BANK   GENMASK(1, 0)
 #define DISP_GAMMA_LUT 0x0700
 
 #define DISP_GAMMA_LUT_10BIT_R GENMASK(29, 20)
@@ -38,6 +40,7 @@
 struct mtk_disp_gamma_data {
bool has_dither;
bool lut_diff;
+   u16 lut_bank_size;
u16 lut_size;
u8 lut_bits;
 };
@@ -84,9 +87,10 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
struct drm_color_lut *lut;
void __iomem *lut_base;
bool lut_diff;
-   u16 lut_size;
+   u16 lut_bank_size, lut_size;
u8 lut_bits;
-   u32 cfg_val, word;
+   u32 cfg_val, lbank_val, word;
+   int cur_bank, num_lut_banks;
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -94,43 +98,61 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
 
if (gamma && gamma->data) {
lut_diff = gamma->data->lut_diff;
+   lut_bank_size = gamma->data->lut_bank_size;
lut_bits = gamma->data->lut_bits;
lut_size = gamma->data->lut_size;
} else {
lut_diff = false;
+   lut_bank_size = LUT_SIZE_DEFAULT;
lut_bits = LUT_BITS_DEFAULT;
lut_size = LUT_SIZE_DEFAULT;
}
 
+   if (lut_bank_size)
+   num_lut_banks = lut_size / lut_bank_size;
+   else
+   num_lut_banks = 1;
+
cfg_val = readl(regs + DISP_GAMMA_CFG);
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
-   for (i = 0; i < lut_size; i++) {
-   struct drm_color_lut diff, hwlut;
-
-   hwlut.red = drm_color_lut_extract(lut[i].red, lut_bits);
-   hwlut.green = drm_color_lut_extract(lut[i].green, lut_bits);
-   hwlut.blue = drm_color_lut_extract(lut[i].blue, lut_bits);
-
-   if (!lut_diff || (i % 2 == 0)) {
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, hwlut.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, hwlut.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, hwlut.blue);
-   } else {
-   diff.red = lut[i].red - lut[i - 1].red;
-   diff.red = drm_color_lut_extract(diff.red, lut_bits);
-
-   diff.green = lut[i].green - lut[i - 1].green;
-   diff.green = drm_color_lut_extract(diff.green, 
lut_bits);
-
-   diff.blue = lut[i].blue - lut[i - 1].blue;
-   diff.blue = drm_color_lut_extract(diff.blue, lut_bits);
-
-   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, diff.red);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_G, diff.green);
-   word |= FIELD_PREP(DISP_GAMMA_LUT_10BIT_B, diff.blue);
+
+   for (cur_bank = 0; cur_bank < num_lut_banks; cur_bank++) {
+
+   /* Switch gamma bank and set data mode before writing LUT */
+   if (num_lut_banks > 1) {
+   lbank_val = FIELD_PREP(DISP_GAMMA_BANK_BANK, cur_bank);
+   writel(lbank_val, regs + DISP_GAMMA_BANK);
+   }
+
+   for (i = 0; i < lut_bank_size; i++) {
+   int n = (cur_bank * lut_bank_size) + i;
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[n].red, lut_bits);
+   hwlut.green = drm_color_lut_extract(lut[n].green, 
lut_bits);
+   hwlut.blue = drm_color_lut_extract(lut[n].blue, 
lut_bits);
+
+   if (!lut_diff || (i % 2 == 0)) {
+   word = FIELD_PREP(DISP_GAMMA_LUT_10BIT_R, 
hwlut.red);
+

[PATCH v4 11/11] drm/mediatek: gamma: Program gamma LUT type for descending or rising

2023-05-18 Thread AngeloGioacchino Del Regno
All of the SoCs that don't have dithering control in the gamma IP
have got a GAMMA_LUT_TYPE bit that tells to the IP if the LUT is
"descending" (bit set) or "rising" (bit cleared): make sure to set
it correctly after programming the LUT.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index ba8a0f93f184..d7c7c6ca2e97 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -23,6 +23,7 @@
 #define GAMMA_RELAY_MODE   BIT(0)
 #define GAMMA_LUT_EN   BIT(1)
 #define GAMMA_DITHERINGBIT(2)
+#define GAMMA_LUT_TYPE BIT(2)
 #define DISP_GAMMA_SIZE0x0030
 #define DISP_GAMMA_SIZE_HSIZE  GENMASK(28, 16)
 #define DISP_GAMMA_SIZE_VSIZE  GENMASK(12, 0)
@@ -89,6 +90,16 @@ unsigned int mtk_gamma_get_lut_size(struct device *dev)
return lut_size;
 }
 
+static bool mtk_gamma_lut_is_descending(struct drm_color_lut *lut, u32 
lut_size)
+{
+   u64 first, last;
+
+   first = lut[0].red + lut[0].green + lut[0].blue;
+   last = lut[lut_size].red + lut[lut_size].green + lut[lut_size].blue;
+
+   return !!(first > last);
+}
+
 void mtk_gamma_set_common(struct device *dev, void __iomem *regs, struct 
drm_crtc_state *state)
 {
struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
@@ -182,6 +193,14 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
}
}
 
+   if (gamma && !gamma->data->has_dither) {
+   /* Descending or Rising LUT */
+   if (mtk_gamma_lut_is_descending(lut, lut_size))
+   cfg_val |= FIELD_PREP(GAMMA_LUT_TYPE, 1);
+   else
+   cfg_val &= ~GAMMA_LUT_TYPE;
+   }
+
/* Enable the gamma table */
cfg_val |= FIELD_PREP(GAMMA_LUT_EN, 1);
 
-- 
2.40.1



[PATCH v4 04/11] drm/mediatek: gamma: Improve and simplify HW LUT calculation

2023-05-18 Thread AngeloGioacchino Del Regno
Use drm_color_lut_extract() to avoid open-coding the bits reduction
calculations for each color channel and use a struct drm_color_lut
to temporarily store the information instead of an array of u32.

Also, slightly improve the precision of the HW LUT calculation in the
LUT DIFF case by performing the subtractions on the 16-bits values and
doing the 10 bits conversion later.

Signed-off-by: AngeloGioacchino Del Regno 

Reviewed-by: Jason-JH.Lin 
---
 drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 30 +++
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c 
b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index d194d9bc2e2b..60ccea8c1e1a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -77,7 +77,6 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
bool lut_diff;
u16 lut_size;
u32 word;
-   u32 diff[3] = {0};
 
/* If there's no gamma lut there's nothing to do here. */
if (!state->gamma_lut)
@@ -97,18 +96,29 @@ void mtk_gamma_set_common(struct device *dev, void __iomem 
*regs, struct drm_crt
lut_base = regs + DISP_GAMMA_LUT;
lut = (struct drm_color_lut *)state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
+   struct drm_color_lut diff, hwlut;
+
+   hwlut.red = drm_color_lut_extract(lut[i].red, 10);
+   hwlut.green = drm_color_lut_extract(lut[i].green, 10);
+   hwlut.blue = drm_color_lut_extract(lut[i].blue, 10);
+
if (!lut_diff || (i % 2 == 0)) {
-   word = (((lut[i].red >> 6) & LUT_10BIT_MASK) << 20) +
-   (((lut[i].green >> 6) & LUT_10BIT_MASK) << 10) +
-   ((lut[i].blue >> 6) & LUT_10BIT_MASK);
+   word = hwlut.red << 20 +
+  hwlut.green << 10 +
+  hwlut.red;
} else {
-   diff[0] = (lut[i].red >> 6) - (lut[i - 1].red >> 6);
-   diff[1] = (lut[i].green >> 6) - (lut[i - 1].green >> 6);
-   diff[2] = (lut[i].blue >> 6) - (lut[i - 1].blue >> 6);
+   diff.red = lut[i].red - lut[i - 1].red;
+   diff.red = drm_color_lut_extract(diff.red, 10);
+
+   diff.green = lut[i].green - lut[i - 1].green;
+   diff.green = drm_color_lut_extract(diff.green, 10);
+
+   diff.blue = lut[i].blue - lut[i - 1].blue;
+   diff.blue = drm_color_lut_extract(diff.blue, 10);
 
-   word = ((diff[0] & LUT_10BIT_MASK) << 20) +
-   ((diff[1] & LUT_10BIT_MASK) << 10) +
-   (diff[2] & LUT_10BIT_MASK);
+   word = diff.blue << 20 +
+  diff.green << 10 +
+  diff.red;
}
writel(word, (lut_base + i * 4));
}
-- 
2.40.1



<    3   4   5   6   7   8   9   10   11   12   >