mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Remove some RPI patches
This commit is contained in:
parent
b87d96fd00
commit
6ce0551118
89 changed files with 0 additions and 11207 deletions
|
@ -1,77 +0,0 @@
|
|||
From 4b7a4389846c44ff6a3590027d25aefd796b50f4 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:16 +0200
|
||||
Subject: [PATCH 001/634] clk: bcm-2835: Remove rounding up the dividers
|
||||
|
||||
The driver, once it found a divider, tries to round it up by increasing
|
||||
the least significant bit of the fractional part by one when the
|
||||
round_up argument is set and there's a remainder.
|
||||
|
||||
However, since it increases the divider it will actually reduce the
|
||||
clock rate below what we were asking for, leading to issues with
|
||||
clk_set_min_rate() that will complain that our rounded clock rate is
|
||||
below the minimum of the rate.
|
||||
|
||||
Since the dividers are fairly precise already, let's remove that part so
|
||||
that we can have clk_set_min_rate() working.
|
||||
|
||||
This is effectively a revert of 9c95b32ca093 ("clk: bcm2835: add a round
|
||||
up ability to the clock divisor").
|
||||
|
||||
Fixes: 9c95b32ca093 ("clk: bcm2835: add a round up ability to the clock divisor")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Acked-by: Stephen Boyd <sboyd@kernel.org>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org> # boot and basic functionality
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-3-maxime@cerno.tech
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 11 +++--------
|
||||
1 file changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index bf97b2b2a63f..3667b4d731e7 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -932,8 +932,7 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
|
||||
|
||||
static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
- unsigned long parent_rate,
|
||||
- bool round_up)
|
||||
+ unsigned long parent_rate)
|
||||
{
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
const struct bcm2835_clock_data *data = clock->data;
|
||||
@@ -945,10 +944,6 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
|
||||
|
||||
rem = do_div(temp, rate);
|
||||
div = temp;
|
||||
-
|
||||
- /* Round up and mask off the unused bits */
|
||||
- if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
|
||||
- div += unused_frac_mask + 1;
|
||||
div &= ~unused_frac_mask;
|
||||
|
||||
/* different clamping limits apply for a mash clock */
|
||||
@@ -1079,7 +1074,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
struct bcm2835_cprman *cprman = clock->cprman;
|
||||
const struct bcm2835_clock_data *data = clock->data;
|
||||
- u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
|
||||
+ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
|
||||
u32 ctl;
|
||||
|
||||
spin_lock(&cprman->regs_lock);
|
||||
@@ -1130,7 +1125,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
|
||||
|
||||
if (!(BIT(parent_idx) & data->set_rate_parent)) {
|
||||
*prate = clk_hw_get_rate(parent);
|
||||
- *div = bcm2835_clock_choose_div(hw, rate, *prate, true);
|
||||
+ *div = bcm2835_clock_choose_div(hw, rate, *prate);
|
||||
|
||||
*avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
From b6b62f912d8aa4bd47780b3de56dc35ee820aad9 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:17 +0200
|
||||
Subject: [PATCH 002/634] drm/vc4: hdmi: Set a default HSM rate
|
||||
|
||||
When the firmware doesn't setup the HSM rate (such as when booting
|
||||
without an HDMI cable plugged in), its rate is 0 and thus any register
|
||||
access results in a CPU stall, even though HSM is enabled.
|
||||
|
||||
Let's enforce a minimum rate at boot to avoid this issue.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-4-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index ed8a4b7f8b6e..623a4699bd21 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -94,6 +94,7 @@
|
||||
# define VC4_HD_M_SW_RST BIT(2)
|
||||
# define VC4_HD_M_ENABLE BIT(0)
|
||||
|
||||
+#define HSM_MIN_CLOCK_FREQ 120000000
|
||||
#define CEC_CLOCK_FREQ 40000
|
||||
|
||||
#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
|
||||
@@ -2161,6 +2162,19 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi->disable_4kp60 = true;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * If we boot without any cable connected to the HDMI connector,
|
||||
+ * the firmware will skip the HSM initialization and leave it
|
||||
+ * with a rate of 0, resulting in a bus lockup when we're
|
||||
+ * accessing the registers even if it's enabled.
|
||||
+ *
|
||||
+ * Let's put a sensible default at runtime_resume so that we
|
||||
+ * don't end up in this situation.
|
||||
+ */
|
||||
+ ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
|
||||
+ if (ret)
|
||||
+ goto err_put_ddc;
|
||||
+
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
From bfb78996b5fb1fb937541a17f58afdcbf7e6a8a5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:18 +0200
|
||||
Subject: [PATCH 003/634] drm/vc4: hdmi: Move the HSM clock enable to
|
||||
runtime_pm
|
||||
|
||||
In order to access the HDMI controller, we need to make sure the HSM
|
||||
clock is enabled. If we were to access it with the clock disabled, the
|
||||
CPU would completely hang, resulting in an hard crash.
|
||||
|
||||
Since we have different code path that would require it, let's move that
|
||||
clock enable / disable to runtime_pm that will take care of the
|
||||
reference counting for us.
|
||||
|
||||
Since we also want to change the HSM clock rate and it's only valid
|
||||
while the clock is disabled, we need to move the clk_set_min_rate() call
|
||||
on the HSM clock above pm_runtime_get_and_sync().
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-5-maxime@cerno.tech
|
||||
Link: https://lore.kernel.org/linux-arm-kernel/20210924152334.1342630-1-maxime@cerno.tech/
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 70 +++++++++++++++++++++-------------
|
||||
1 file changed, 44 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 623a4699bd21..6b0700d0b408 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -628,7 +628,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
vc4_hdmi->variant->phy_disable(vc4_hdmi);
|
||||
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
|
||||
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
@@ -894,28 +893,10 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
conn_state_to_vc4_hdmi_conn_state(conn_state);
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
- unsigned long bvb_rate, pixel_rate, hsm_rate;
|
||||
+ unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
+ unsigned long bvb_rate, hsm_rate;
|
||||
int ret;
|
||||
|
||||
- ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
- if (ret < 0) {
|
||||
- DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- pixel_rate = vc4_conn_state->pixel_rate;
|
||||
- ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
- if (ret) {
|
||||
- DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
- if (ret) {
|
||||
- DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
||||
* be faster than pixel clock, infinitesimally faster, tested in
|
||||
@@ -939,10 +920,21 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret < 0) {
|
||||
+ DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
if (ret) {
|
||||
- DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
+ DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
+ if (ret) {
|
||||
+ DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -958,7 +950,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
return;
|
||||
}
|
||||
@@ -966,7 +957,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
return;
|
||||
}
|
||||
@@ -2099,6 +2089,27 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int __maybe_unused vc4_hdmi_runtime_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+
|
||||
+ clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vc4_hdmi_runtime_resume(struct device *dev)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
|
||||
@@ -2366,11 +2377,18 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
+static const struct dev_pm_ops vc4_hdmi_pm_ops = {
|
||||
+ SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
|
||||
+ vc4_hdmi_runtime_resume,
|
||||
+ NULL)
|
||||
+};
|
||||
+
|
||||
struct platform_driver vc4_hdmi_driver = {
|
||||
.probe = vc4_hdmi_dev_probe,
|
||||
.remove = vc4_hdmi_dev_remove,
|
||||
.driver = {
|
||||
.name = "vc4_hdmi",
|
||||
.of_match_table = vc4_hdmi_dt_match,
|
||||
+ .pm = &vc4_hdmi_pm_ops,
|
||||
},
|
||||
};
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
From 4bfb738710a3ea66e51eefbc8cd8e8673c84a5b3 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:19 +0200
|
||||
Subject: [PATCH 004/634] drm/vc4: hdmi: Make sure the controller is powered in
|
||||
detect
|
||||
|
||||
If the HPD GPIO is not available and drm_probe_ddc fails, we end up
|
||||
reading the HDMI_HOTPLUG register, but the controller might be powered
|
||||
off resulting in a CPU hang. Make sure we have the power domain and the
|
||||
HSM clock powered during the detect cycle to prevent the hang from
|
||||
happening.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-6-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 6b0700d0b408..21510ae31a9e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -168,6 +168,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
|
||||
bool connected = false;
|
||||
|
||||
+ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
+
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
connected = true;
|
||||
@@ -188,10 +190,12 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
From 977d70a849d52a89e8b9fd949b0339ff8e5c88f8 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:27 +0200
|
||||
Subject: [PATCH 005/634] drm/vc4: hdmi: Make sure the controller is powered up
|
||||
during bind
|
||||
|
||||
In the bind hook, we actually need the device to have the HSM clock
|
||||
running during the final part of the display initialisation where we
|
||||
reset the controller and initialise the CEC component.
|
||||
|
||||
Failing to do so will result in a complete, silent, hang of the CPU.
|
||||
|
||||
Fixes: 411efa18e4b0 ("drm/vc4: hdmi: Move the HSM clock enable to runtime_pm")
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-3-maxime@cerno.tech
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 21510ae31a9e..2087717f1cce 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -2190,6 +2190,18 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
if (ret)
|
||||
goto err_put_ddc;
|
||||
|
||||
+ /*
|
||||
+ * We need to have the device powered up at this point to call
|
||||
+ * our reset hook and for the CEC init.
|
||||
+ */
|
||||
+ ret = vc4_hdmi_runtime_resume(dev);
|
||||
+ if (ret)
|
||||
+ goto err_put_ddc;
|
||||
+
|
||||
+ pm_runtime_get_noresume(dev);
|
||||
+ pm_runtime_set_active(dev);
|
||||
+ pm_runtime_enable(dev);
|
||||
+
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
@@ -2201,8 +2213,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
}
|
||||
|
||||
- pm_runtime_enable(dev);
|
||||
-
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
|
||||
|
||||
@@ -2226,6 +2236,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi_debugfs_regs,
|
||||
vc4_hdmi);
|
||||
|
||||
+ pm_runtime_put_sync(dev);
|
||||
+
|
||||
return 0;
|
||||
|
||||
err_free_cec:
|
||||
@@ -2236,6 +2248,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
|
||||
err_destroy_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
+ pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
err_put_ddc:
|
||||
put_device(&vc4_hdmi->ddc->dev);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
From 98fa097e699cf1f9aeab523e109b06465b2e456a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:28 +0200
|
||||
Subject: [PATCH 006/634] drm/vc4: hdmi: Rework the pre_crtc_configure error
|
||||
handling
|
||||
|
||||
Since our pre_crtc_configure hook returned void, we didn't implement a
|
||||
goto-based error path handling, leading to errors like failing to put
|
||||
back the device in pm_runtime in all the error paths, but also failing
|
||||
to disable the pixel clock if clk_set_min_rate on the HSM clock fails.
|
||||
|
||||
Move to a goto-based implementation to have an easier consitency.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-4-maxime@cerno.tech
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 2087717f1cce..49944644a9b3 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -933,15 +933,16 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
- return;
|
||||
+ goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
- return;
|
||||
+ goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
+
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
if (pixel_rate > 297000000)
|
||||
@@ -954,15 +955,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
- return;
|
||||
+ goto err_disable_pixel_clock;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
- return;
|
||||
+ goto err_disable_pixel_clock;
|
||||
}
|
||||
|
||||
if (vc4_hdmi->variant->phy_init)
|
||||
@@ -975,6 +974,15 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_disable_pixel_clock:
|
||||
+ clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
+err_put_runtime_pm:
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+
|
||||
+ return;
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
From 9ae0103555f84dce8bf29859fb3f5820da07e34a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:29 +0200
|
||||
Subject: [PATCH 007/634] drm/vc4: hdmi: Split the CEC disable / enable
|
||||
functions in two
|
||||
|
||||
In order to ease further additions to the CEC enable and disable, let's
|
||||
split the function into two functions, one to enable and the other to
|
||||
disable.
|
||||
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-5-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 75 ++++++++++++++++++++--------------
|
||||
1 file changed, 45 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 49944644a9b3..9b3c0009b2ed 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1727,7 +1727,7 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
+static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
@@ -1740,38 +1740,53 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
val |= ((4700 / usecs) << VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT) |
|
||||
((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
|
||||
|
||||
- if (enable) {
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
- VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_2,
|
||||
- ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
|
||||
- ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
|
||||
- ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
|
||||
- ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
|
||||
- ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_3,
|
||||
- ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
|
||||
- ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
|
||||
- ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
|
||||
- ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_4,
|
||||
- ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
|
||||
- ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
|
||||
- ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
|
||||
- ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
|
||||
-
|
||||
- if (!vc4_hdmi->variant->external_irq_controller)
|
||||
- HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
- } else {
|
||||
- if (!vc4_hdmi->variant->external_irq_controller)
|
||||
- HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
- VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
- }
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
+ VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_2,
|
||||
+ ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
|
||||
+ ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
|
||||
+ ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
|
||||
+ ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
|
||||
+ ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_3,
|
||||
+ ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
|
||||
+ ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
|
||||
+ ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
|
||||
+ ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_4,
|
||||
+ ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
|
||||
+ ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
|
||||
+ ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
|
||||
+ ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
|
||||
+
|
||||
+ if (!vc4_hdmi->variant->external_irq_controller)
|
||||
+ HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+
|
||||
+ if (!vc4_hdmi->variant->external_irq_controller)
|
||||
+ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
+
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
+ VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
+{
|
||||
+ if (enable)
|
||||
+ return vc4_hdmi_cec_enable(adap);
|
||||
+ else
|
||||
+ return vc4_hdmi_cec_disable(adap);
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
From 086555e0bcbdf8e2e6e9f9306323cb4bf84fb807 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:30 +0200
|
||||
Subject: [PATCH 008/634] drm/vc4: hdmi: Make sure the device is powered with
|
||||
CEC
|
||||
|
||||
Similarly to what we encountered with the detect hook with DRM, nothing
|
||||
actually prevents any of the CEC callback from being run while the HDMI
|
||||
output is disabled.
|
||||
|
||||
However, this is an issue since any register access to the controller
|
||||
when it's powered down will result in a silent hang.
|
||||
|
||||
Let's make sure we run the runtime_pm hooks when the CEC adapter is
|
||||
opened and closed by the userspace to avoid that issue.
|
||||
|
||||
Fixes: 15b4511a4af6 ("drm/vc4: add HDMI CEC support")
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-6-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 9b3c0009b2ed..70101e09b245 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1732,8 +1732,14 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
|
||||
- u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
+ val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
|
||||
VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
|
||||
VC4_HDMI_CEC_CNT_TO_4500_US_MASK);
|
||||
@@ -1776,6 +1782,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
From 54a0fd6b5fd8c0eeef7f3666ef1bbc2ce00cd779 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:31 +0200
|
||||
Subject: [PATCH 009/634] drm/vc4: hdmi: Warn if we access the controller while
|
||||
disabled
|
||||
|
||||
We've had many silent hangs where the kernel would look like it just
|
||||
stalled due to the access to one of the HDMI registers while the
|
||||
controller was disabled.
|
||||
|
||||
Add a warning if we're about to do that so that it's at least not silent
|
||||
anymore.
|
||||
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-7-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
index 19d2fdc446bc..99dde6e06a37 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef _VC4_HDMI_REGS_H_
|
||||
#define _VC4_HDMI_REGS_H_
|
||||
|
||||
+#include <linux/pm_runtime.h>
|
||||
+
|
||||
#include "vc4_hdmi.h"
|
||||
|
||||
#define VC4_HDMI_PACKET_STRIDE 0x24
|
||||
@@ -412,6 +414,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
+
|
||||
if (reg >= variant->num_registers) {
|
||||
dev_warn(&hdmi->pdev->dev,
|
||||
"Invalid register ID %u\n", reg);
|
||||
@@ -438,6 +442,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
+
|
||||
if (reg >= variant->num_registers) {
|
||||
dev_warn(&hdmi->pdev->dev,
|
||||
"Invalid register ID %u\n", reg);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
From 7d9e3fd5588ff325e87844e3bcb0d167a9456e78 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 23 Sep 2021 20:50:13 +0200
|
||||
Subject: [PATCH 010/634] drm/vc4: crtc: Make sure the HDMI controller is
|
||||
powered when disabling
|
||||
|
||||
Since commit 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot
|
||||
time"), during the initial setup of the driver we call into the VC4 HDMI
|
||||
controller hooks to make sure the controller is properly disabled.
|
||||
|
||||
However, we were never making sure that the device was properly powered
|
||||
while doing so. This never resulted in any (reported) issue in practice,
|
||||
but since the introduction of commit 4209f03fcb8e ("drm/vc4: hdmi: Warn
|
||||
if we access the controller while disabled") we get a loud complaint
|
||||
when we do that kind of access.
|
||||
|
||||
Let's make sure we have the HDMI controller properly powered while
|
||||
disabling it.
|
||||
|
||||
Fixes: 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot time")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210923185013.826679-1-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 18f5009ce90e..c0df11e5fcf2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_device.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
@@ -42,6 +43,7 @@
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "vc4_drv.h"
|
||||
+#include "vc4_hdmi.h"
|
||||
#include "vc4_regs.h"
|
||||
|
||||
#define HVS_FIFO_LATENCY_PIX 6
|
||||
@@ -496,8 +498,10 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
|
||||
enum vc4_encoder_type encoder_type;
|
||||
const struct vc4_pv_data *pv_data;
|
||||
struct drm_encoder *encoder;
|
||||
+ struct vc4_hdmi *vc4_hdmi;
|
||||
unsigned encoder_sel;
|
||||
int channel;
|
||||
+ int ret;
|
||||
|
||||
if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
|
||||
"brcm,bcm2711-pixelvalve2") ||
|
||||
@@ -525,7 +529,20 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
|
||||
if (WARN_ON(!encoder))
|
||||
return 0;
|
||||
|
||||
- return vc4_crtc_disable(crtc, encoder, NULL, channel);
|
||||
+ vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_crtc_disable(crtc, encoder, NULL, channel);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
From 8dab6a99245dd443527dce15f99707b889c21248 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 18 Oct 2021 15:19:30 +0200
|
||||
Subject: [PATCH 011/634] drm/vc4: crtc: Drop feed_txp from state
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
In VC4, a number of users of that pointers have crept in over the years,
|
||||
the first one being whether or not the downstream controller of the
|
||||
pixelvalve is our writeback controller.
|
||||
|
||||
Fortunately for us, Since commit 39fcb2808376 ("drm/vc4: txp: Turn the
|
||||
TXP into a CRTC of its own") this is no longer something that can change
|
||||
from one commit to the other and is hardcoded.
|
||||
|
||||
Let's set this flag in struct vc4_crtc if we happen to be the TXP, and
|
||||
drop the flag from our private state structure.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 008095e065a8 ("drm/vc4: Add support for the transposer block")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 3 +--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 6 +++++-
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++----
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
|
||||
drivers/gpu/drm/vc4/vc4_txp.c | 3 +--
|
||||
5 files changed, 12 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index c0df11e5fcf2..b90187d2c819 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -715,7 +715,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (vc4_crtc->event &&
|
||||
(vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
- vc4_state->feed_txp)) {
|
||||
+ vc4_crtc->feeds_txp)) {
|
||||
drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
|
||||
vc4_crtc->event = NULL;
|
||||
drm_crtc_vblank_put(crtc);
|
||||
@@ -893,7 +893,6 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
return NULL;
|
||||
|
||||
old_vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
- vc4_state->feed_txp = old_vc4_state->feed_txp;
|
||||
vc4_state->margins = old_vc4_state->margins;
|
||||
vc4_state->assigned_channel = old_vc4_state->assigned_channel;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index ef73e0aaf726..3c69b89363cb 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -495,6 +495,11 @@ struct vc4_crtc {
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
struct debugfs_regset32 regset;
|
||||
+
|
||||
+ /**
|
||||
+ * @feeds_txp: True if the CRTC feeds our writeback controller.
|
||||
+ */
|
||||
+ bool feeds_txp;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
@@ -521,7 +526,6 @@ struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
/* Dlist area for this CRTC configuration. */
|
||||
struct drm_mm_node mm;
|
||||
- bool feed_txp;
|
||||
bool txp_armed;
|
||||
unsigned int assigned_channel;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index c239045e05d6..9ddaee6b368d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -375,7 +375,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
||||
- if (!vc4_state->feed_txp || vc4_state->txp_armed) {
|
||||
+ if (!vc4_crtc->feeds_txp || vc4_state->txp_armed) {
|
||||
vc4_crtc->event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
@@ -395,10 +395,9 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state);
|
||||
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
- bool oneshot = vc4_state->feed_txp;
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ bool oneshot = vc4_crtc->feeds_txp;
|
||||
|
||||
vc4_hvs_update_dlist(crtc);
|
||||
vc4_hvs_init_channel(vc4, crtc, mode, oneshot);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index f0b3e4cf5bce..028f19f7a5f8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -233,6 +233,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
|
||||
unsigned int i;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
u32 dispctrl;
|
||||
u32 dsp3_mux;
|
||||
@@ -253,7 +254,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
|
||||
* TXP IP, and we need to disable the FIFO2 -> pixelvalve1
|
||||
* route.
|
||||
*/
|
||||
- if (vc4_state->feed_txp)
|
||||
+ if (vc4_crtc->feeds_txp)
|
||||
dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
|
||||
else
|
||||
dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
index 2fc7f4b5fa09..26eda7542f74 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
@@ -391,7 +391,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc,
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
|
||||
crtc);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
int ret;
|
||||
|
||||
ret = vc4_hvs_atomic_check(crtc, state);
|
||||
@@ -399,7 +398,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc,
|
||||
return ret;
|
||||
|
||||
crtc_state->no_vblank = true;
|
||||
- vc4_state->feed_txp = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -482,6 +480,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
|
||||
|
||||
vc4_crtc->pdev = pdev;
|
||||
vc4_crtc->data = &vc4_txp_crtc_data;
|
||||
+ vc4_crtc->feeds_txp = true;
|
||||
|
||||
txp->pdev = pdev;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
From 7c65e42492d48ed03ce6b7e2346d5f969e30a62a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 10 Jun 2021 17:48:28 +0200
|
||||
Subject: [PATCH 012/634] drm/vc4: Fix non-blocking commit getting stuck
|
||||
forever
|
||||
|
||||
In some situation, we can end up being stuck on a non-blocking that went
|
||||
through properly.
|
||||
|
||||
The situation that seems to trigger it reliably is to first start a
|
||||
non-blocking commit, and then right after, and before we had any vblank
|
||||
interrupt), start a blocking commit.
|
||||
|
||||
This will lead to the first commit workqueue to be scheduled, setup the
|
||||
display, while the second commit is waiting for the first one to be
|
||||
completed.
|
||||
|
||||
The vblank interrupt will then be raised, vc4_crtc_handle_vblank() will
|
||||
run and will compare the active dlist in the HVS channel to the one
|
||||
associated with the crtc->state.
|
||||
|
||||
However, at that point, the second commit is waiting using
|
||||
drm_atomic_helper_wait_for_dependencies that occurs after
|
||||
drm_atomic_helper_swap_state has been called, so crtc->state points to
|
||||
the second commit state. vc4_crtc_handle_vblank() will compare the two
|
||||
dlist addresses and since they don't match will ignore the interrupt.
|
||||
|
||||
The vblank event will never be reported, and the first and second commit
|
||||
will wait for the first commit completion until they timeout.
|
||||
|
||||
The underlying reason is that it was never safe to do so. Indeed,
|
||||
accessing the ->state pointer access synchronization is based on
|
||||
ownership guarantees that can only occur within the functions and hooks
|
||||
defined as part of the KMS framework, and obviously the irq handler
|
||||
isn't one of them. The rework to move to generic helpers only uncovered
|
||||
the underlying issue.
|
||||
|
||||
However, since the code path between
|
||||
drm_atomic_helper_wait_for_dependencies() and
|
||||
drm_atomic_helper_wait_for_vblanks() is serialised and we can't get two
|
||||
commits in that path at the same time, we can work around this issue by
|
||||
setting a variable associated to struct drm_crtc to the dlist we expect,
|
||||
and then using it from the vc4_crtc_handle_vblank() function.
|
||||
|
||||
Since that state is shared with the modesetting path, we also need to
|
||||
introduce a spinlock to protect the code shared between the interrupt
|
||||
handler and the modesetting path, protecting only our new variable for
|
||||
now.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 56d1fe0979dc ("drm/vc4: Make pageflip completion handling more robust.")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 5 ++++-
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 14 ++++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++++--
|
||||
3 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index b90187d2c819..98de8b265220 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -713,8 +713,9 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
+ spin_lock(&vc4_crtc->irq_lock);
|
||||
if (vc4_crtc->event &&
|
||||
- (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
+ (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
vc4_crtc->feeds_txp)) {
|
||||
drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
|
||||
vc4_crtc->event = NULL;
|
||||
@@ -728,6 +729,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
*/
|
||||
vc4_hvs_unmask_underrun(dev, chan);
|
||||
}
|
||||
+ spin_unlock(&vc4_crtc->irq_lock);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
@@ -1127,6 +1129,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
|
||||
return PTR_ERR(primary_plane);
|
||||
}
|
||||
|
||||
+ spin_lock_init(&vc4_crtc->irq_lock);
|
||||
drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
|
||||
crtc_funcs, NULL);
|
||||
drm_crtc_helper_add(crtc, crtc_helper_funcs);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 3c69b89363cb..6d2480abcf08 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -500,6 +500,20 @@ struct vc4_crtc {
|
||||
* @feeds_txp: True if the CRTC feeds our writeback controller.
|
||||
*/
|
||||
bool feeds_txp;
|
||||
+
|
||||
+ /**
|
||||
+ * @irq_lock: Spinlock protecting the resources shared between
|
||||
+ * the atomic code and our vblank handler.
|
||||
+ */
|
||||
+ spinlock_t irq_lock;
|
||||
+
|
||||
+ /**
|
||||
+ * @current_dlist: Start offset of the display list currently
|
||||
+ * set in the HVS for that CRTC. Protected by @irq_lock, and
|
||||
+ * copied in vc4_hvs_update_dlist() for the CRTC interrupt
|
||||
+ * handler to have access to that value.
|
||||
+ */
|
||||
+ unsigned int current_dlist;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 9ddaee6b368d..f8ed0f6a57e0 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -365,10 +365,9 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (crtc->state->event) {
|
||||
- unsigned long flags;
|
||||
-
|
||||
crtc->state->event->pipe = drm_crtc_index(crtc);
|
||||
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
@@ -388,6 +387,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
|
||||
vc4_state->mm.start);
|
||||
}
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags);
|
||||
+ vc4_crtc->current_dlist = vc4_state->mm.start;
|
||||
+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
From ed2955f9cdaf873fd2b470febe3da024e3aa3f11 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 18 Oct 2021 15:56:44 +0200
|
||||
Subject: [PATCH 013/634] drm/vc4: crtc: Copy assigned channel to the CRTC
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
In VC4, a number of users of that pointers have crept in over the years,
|
||||
and the previous commits removed them all but the HVS channel a CRTC has
|
||||
been assigned.
|
||||
|
||||
Let's move this channel in struct vc4_crtc at atomic_begin() time, drop
|
||||
it from our private state structure, and remove our use of crtc->state
|
||||
from our vblank handler entirely.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 87ebcd42fb7b ("drm/vc4: crtc: Assign output to channel automatically")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 9 +++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 12 ++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_txp.c | 1 +
|
||||
4 files changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 98de8b265220..e3ed52d96f42 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -708,8 +708,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
struct drm_crtc *crtc = &vc4_crtc->base;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
- u32 chan = vc4_state->assigned_channel;
|
||||
+ u32 chan = vc4_crtc->current_hvs_channel;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
@@ -955,6 +954,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
|
||||
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
.mode_valid = vc4_crtc_mode_valid,
|
||||
.atomic_check = vc4_crtc_atomic_check,
|
||||
+ .atomic_begin = vc4_hvs_atomic_begin,
|
||||
.atomic_flush = vc4_hvs_atomic_flush,
|
||||
.atomic_enable = vc4_crtc_atomic_enable,
|
||||
.atomic_disable = vc4_crtc_atomic_disable,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 6d2480abcf08..4b550ebd9572 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -514,6 +514,14 @@ struct vc4_crtc {
|
||||
* handler to have access to that value.
|
||||
*/
|
||||
unsigned int current_dlist;
|
||||
+
|
||||
+ /**
|
||||
+ * @current_hvs_channel: HVS channel currently assigned to the
|
||||
+ * CRTC. Protected by @irq_lock, and copied in
|
||||
+ * vc4_hvs_atomic_begin() for the CRTC interrupt handler to have
|
||||
+ * access to that value.
|
||||
+ */
|
||||
+ unsigned int current_hvs_channel;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
@@ -926,6 +934,7 @@ extern struct platform_driver vc4_hvs_driver;
|
||||
void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
|
||||
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
|
||||
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
+void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index f8ed0f6a57e0..604933e20e6a 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -393,6 +393,18 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
+void vc4_hvs_atomic_begin(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags);
|
||||
+ vc4_crtc->current_hvs_channel = vc4_state->assigned_channel;
|
||||
+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
+}
|
||||
+
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
index 26eda7542f74..9809ca3e2945 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
@@ -435,6 +435,7 @@ static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
|
||||
|
||||
static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
|
||||
.atomic_check = vc4_txp_atomic_check,
|
||||
+ .atomic_begin = vc4_hvs_atomic_begin,
|
||||
.atomic_flush = vc4_hvs_atomic_flush,
|
||||
.atomic_enable = vc4_txp_atomic_enable,
|
||||
.atomic_disable = vc4_txp_atomic_disable,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,916 +0,0 @@
|
|||
From a17ad9dc735724a186d8618c56e27467dbb1451b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 12:25:17 +0200
|
||||
Subject: [PATCH 014/634] drm/vc4: hdmi: Add a spinlock to protect register
|
||||
access
|
||||
|
||||
The vc4 HDMI driver has multiple path shared between the CEC, ALSA and
|
||||
KMS frameworks, plus two interrupt handlers (CEC and hotplug) that will
|
||||
read and modify a number of registers.
|
||||
|
||||
Even though not bug has been reported so far, it's definitely unsafe, so
|
||||
let's just add a spinlock to protect the register access of the HDMI
|
||||
controller.
|
||||
|
||||
Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 202 ++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 5 +
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 +++++
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 +
|
||||
4 files changed, 236 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 70101e09b245..6a9d5d423cf8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -118,6 +118,10 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
|
||||
|
||||
static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
|
||||
udelay(1);
|
||||
HDMI_WRITE(HDMI_M_CTL, 0);
|
||||
@@ -129,24 +133,36 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
VC4_HDMI_SW_RESET_FORMAT_DETECT);
|
||||
|
||||
HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
reset_control_reset(vc4_hdmi->reset);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_DVP_CTL, 0);
|
||||
|
||||
HDMI_WRITE(HDMI_CLOCK_STOP,
|
||||
HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock);
|
||||
+ unsigned long flags;
|
||||
u16 clk_cnt;
|
||||
u32 value;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
|
||||
|
||||
@@ -154,9 +170,11 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
* Set the clock divider: the hsm_clock rate and this divider
|
||||
* setting will give a 40 kHz CEC clock.
|
||||
*/
|
||||
- clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
|
||||
+ clk_cnt = cec_rate / CEC_CLOCK_FREQ;
|
||||
value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
#else
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
||||
@@ -175,8 +193,16 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
connected = true;
|
||||
} else if (drm_probe_ddc(vc4_hdmi->ddc)) {
|
||||
connected = true;
|
||||
- } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
|
||||
- connected = true;
|
||||
+ } else {
|
||||
+ unsigned long flags;
|
||||
+ u32 hotplug;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+ hotplug = HDMI_READ(HDMI_HOTPLUG);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
+ if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED)
|
||||
+ connected = true;
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
@@ -369,9 +395,12 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
u32 packet_id = type - 0x80;
|
||||
+ unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!poll)
|
||||
return 0;
|
||||
@@ -391,6 +420,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
|
||||
ram_packet_start->reg);
|
||||
uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
|
||||
+ unsigned long flags;
|
||||
ssize_t len, i;
|
||||
int ret;
|
||||
|
||||
@@ -408,6 +438,8 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
for (i = 0; i < len; i += 7) {
|
||||
writel(buffer[i + 0] << 0 |
|
||||
buffer[i + 1] << 8 |
|
||||
@@ -425,6 +457,9 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
|
||||
BIT(packet_id)), 100);
|
||||
if (ret)
|
||||
@@ -544,6 +579,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (!vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
@@ -554,8 +590,10 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
|
||||
drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
|
||||
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
|
||||
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
|
||||
@@ -565,6 +603,7 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
+ unsigned long flags;
|
||||
|
||||
/*
|
||||
* At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
@@ -580,8 +619,10 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
|
||||
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
|
||||
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
|
||||
@@ -607,15 +648,23 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
|
||||
|
||||
HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
mdelay(1);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc4_hdmi_disable_scrambling(encoder);
|
||||
}
|
||||
|
||||
@@ -623,10 +672,13 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (vc4_hdmi->variant->phy_disable)
|
||||
vc4_hdmi->variant->phy_disable(vc4_hdmi);
|
||||
@@ -645,8 +697,11 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
|
||||
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 csc_ctl;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
||||
VC4_HD_CSC_CTL_ORDER);
|
||||
|
||||
@@ -676,14 +731,19 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
|
||||
/* The RGB order applies even when CSC is disabled. */
|
||||
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 csc_ctl;
|
||||
|
||||
csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (enable) {
|
||||
/* CEA VICs other than #1 requre limited range RGB
|
||||
* output unless overridden by an AVI infoframe.
|
||||
@@ -715,6 +775,8 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
}
|
||||
|
||||
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
@@ -738,6 +800,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
mode->crtc_vsync_end -
|
||||
interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_HORZA,
|
||||
(vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
|
||||
@@ -761,6 +826,8 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
|
||||
HDMI_WRITE(HDMI_VERTB0, vertb_even);
|
||||
HDMI_WRITE(HDMI_VERTB1, vertb);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
@@ -784,10 +851,13 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
mode->crtc_vsync_end -
|
||||
interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
+ unsigned long flags;
|
||||
unsigned char gcp;
|
||||
bool gcp_en;
|
||||
u32 reg;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
|
||||
HDMI_WRITE(HDMI_HORZA,
|
||||
(vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
|
||||
@@ -846,13 +916,18 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
HDMI_WRITE(HDMI_GCP_CONFIG, reg);
|
||||
|
||||
HDMI_WRITE(HDMI_CLOCK_STOP, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 drift;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
drift = HDMI_READ(HDMI_FIFO_CTL);
|
||||
drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
|
||||
|
||||
@@ -860,12 +935,20 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
||||
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
usleep_range(1000, 1100);
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
|
||||
VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -899,6 +982,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
unsigned long bvb_rate, hsm_rate;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -967,11 +1051,15 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
if (vc4_hdmi->variant->phy_init)
|
||||
vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
|
||||
@@ -991,6 +1079,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (vc4_encoder->hdmi_monitor &&
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
|
||||
@@ -1005,7 +1094,9 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
vc4_encoder->limited_rgb_range = false;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
@@ -1016,8 +1107,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
||||
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
VC4_HD_VID_CTL_ENABLE |
|
||||
VC4_HD_VID_CTL_CLRRGB |
|
||||
@@ -1034,6 +1128,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -1046,6 +1142,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -1053,6 +1151,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
if (vc4_encoder->hdmi_monitor) {
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
|
||||
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
||||
@@ -1062,6 +1162,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
VC4_HDMI_RAM_PACKET_ENABLE);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc4_hdmi_set_infoframes(encoder);
|
||||
}
|
||||
|
||||
@@ -1183,6 +1285,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
unsigned int samplerate)
|
||||
{
|
||||
u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
|
||||
+ unsigned long flags;
|
||||
unsigned long n, m;
|
||||
|
||||
rational_best_approximation(hsm_clock, samplerate,
|
||||
@@ -1192,9 +1295,11 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
VC4_HD_MAI_SMP_M_SHIFT) + 1,
|
||||
&n, &m);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_SMP,
|
||||
VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
|
||||
VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
|
||||
@@ -1205,6 +1310,8 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
n = 128 * samplerate / 1000;
|
||||
tmp = (u64)(mode->clock * 1000) * n;
|
||||
do_div(tmp, 128 * samplerate);
|
||||
@@ -1234,6 +1341,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
+ unsigned long flags;
|
||||
|
||||
/*
|
||||
* If the HDMI encoder hasn't probed, or the encoder is
|
||||
@@ -1245,12 +1353,14 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
|
||||
vc4_hdmi->audio.streaming = true;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_HD_MAI_CTL_RESET |
|
||||
VC4_HD_MAI_CTL_FLUSH |
|
||||
VC4_HD_MAI_CTL_DLATE |
|
||||
VC4_HD_MAI_CTL_ERRORE |
|
||||
VC4_HD_MAI_CTL_ERRORF);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (vc4_hdmi->variant->phy_rng_enable)
|
||||
vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
|
||||
@@ -1262,6 +1372,7 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
struct device *dev = &vc4_hdmi->pdev->dev;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
@@ -1269,20 +1380,29 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_HD_MAI_CTL_DLATE |
|
||||
VC4_HD_MAI_CTL_ERRORE |
|
||||
VC4_HD_MAI_CTL_ERRORF);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (vc4_hdmi->variant->phy_rng_disable)
|
||||
vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
|
||||
|
||||
@@ -1337,6 +1457,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned int sample_rate = params->sample_rate;
|
||||
unsigned int channels = params->channels;
|
||||
+ unsigned long flags;
|
||||
u32 audio_packet_config, channel_mask;
|
||||
u32 channel_map;
|
||||
u32 mai_audio_format;
|
||||
@@ -1345,14 +1466,15 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
|
||||
sample_rate, params->sample_width, channels);
|
||||
|
||||
+ vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) |
|
||||
VC4_HD_MAI_CTL_WHOLSMP |
|
||||
VC4_HD_MAI_CTL_CHALIGN |
|
||||
VC4_HD_MAI_CTL_ENABLE);
|
||||
|
||||
- vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
-
|
||||
mai_sample_rate = sample_rate_to_mai_fmt(sample_rate);
|
||||
if (params->iec.status[0] & IEC958_AES0_NONAUDIO &&
|
||||
params->channels == 8)
|
||||
@@ -1390,8 +1512,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
|
||||
HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
|
||||
HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
|
||||
+
|
||||
vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea));
|
||||
vc4_hdmi_set_audio_infoframe(encoder);
|
||||
|
||||
@@ -1658,6 +1783,8 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
|
||||
unsigned int i;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
|
||||
VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
|
||||
|
||||
@@ -1676,11 +1803,12 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
}
|
||||
}
|
||||
|
||||
-static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
+static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
- struct vc4_hdmi *vc4_hdmi = priv;
|
||||
u32 cntrl1;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
|
||||
cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
@@ -1689,11 +1817,24 @@ static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
-static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
+static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
+ irqreturn_t ret;
|
||||
+
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
||||
+{
|
||||
u32 cntrl1;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
vc4_hdmi->cec_rx_msg.len = 0;
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_cec_read_msg(vc4_hdmi, cntrl1);
|
||||
@@ -1706,6 +1847,18 @@ static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
+static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = priv;
|
||||
+ irqreturn_t ret;
|
||||
+
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
@@ -1716,14 +1869,17 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
if (!(stat & VC4_HDMI_CPU_CEC))
|
||||
return IRQ_NONE;
|
||||
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
|
||||
if (vc4_hdmi->cec_irq_was_rx)
|
||||
- ret = vc4_cec_irq_handler_rx_bare(irq, priv);
|
||||
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
||||
else
|
||||
- ret = vc4_cec_irq_handler_tx_bare(irq, priv);
|
||||
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1732,6 +1888,7 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
|
||||
+ unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
@@ -1739,6 +1896,8 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
|
||||
VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
|
||||
@@ -1769,12 +1928,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
@@ -1782,6 +1946,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1798,10 +1964,14 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+ unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1,
|
||||
(HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
|
||||
(log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1810,6 +1980,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
+ unsigned long flags;
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
@@ -1818,6 +1989,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
for (i = 0; i < msg->len; i += 4)
|
||||
HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2),
|
||||
(msg->msg[i]) |
|
||||
@@ -1833,6 +2006,9 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1847,6 +2023,7 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
struct cec_connector_info conn_info;
|
||||
struct platform_device *pdev = vc4_hdmi->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
+ unsigned long flags;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
@@ -1866,10 +2043,12 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
|
||||
cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
/* Set the logical address to Unregistered */
|
||||
value |= VC4_HDMI_CEC_ADDR_MASK;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
@@ -1888,7 +2067,9 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
if (ret)
|
||||
goto err_remove_cec_rx_handler;
|
||||
} else {
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
ret = request_threaded_irq(platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
@@ -2158,6 +2339,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
|
||||
if (!vc4_hdmi)
|
||||
return -ENOMEM;
|
||||
+ spin_lock_init(&vc4_hdmi->hw_lock);
|
||||
INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
|
||||
|
||||
dev_set_drvdata(dev, vc4_hdmi);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 33e9f665ab8e..006142fe8d4e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -178,6 +178,11 @@ struct vc4_hdmi {
|
||||
|
||||
struct debugfs_regset32 hdmi_regset;
|
||||
struct debugfs_regset32 hd_regset;
|
||||
+
|
||||
+ /**
|
||||
+ * @hw_lock: Spinlock protecting device register access.
|
||||
+ */
|
||||
+ spinlock_t hw_lock;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
index 36535480f8e2..62148f0dc284 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
@@ -130,31 +130,49 @@
|
||||
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
struct vc4_hdmi_connector_state *conn_state)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
/* PHY should be in reset, like
|
||||
* vc4_hdmi_encoder_disable() does.
|
||||
*/
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
||||
HDMI_READ(HDMI_TX_PHY_CTL_0) &
|
||||
~VC4_HDMI_TX_PHY_RNG_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
||||
HDMI_READ(HDMI_TX_PHY_CTL_0) |
|
||||
VC4_HDMI_TX_PHY_RNG_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
@@ -336,6 +354,8 @@ phy_get_channel_settings(enum vc4_hdmi_phy_channel chan,
|
||||
|
||||
static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10));
|
||||
}
|
||||
@@ -348,10 +368,13 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
unsigned long long pixel_freq = conn_state->pixel_rate;
|
||||
unsigned long long vco_freq;
|
||||
unsigned char word_sel;
|
||||
+ unsigned long flags;
|
||||
u8 vco_sel, vco_div;
|
||||
|
||||
vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc5_hdmi_reset_phy(vc4_hdmi);
|
||||
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
@@ -501,23 +524,37 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
HDMI_READ(HDMI_TX_PHY_RESET_CTL) |
|
||||
VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
|
||||
VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
vc5_hdmi_reset_phy(vc4_hdmi);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) &
|
||||
~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) |
|
||||
VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
index 99dde6e06a37..fc971506bd4f 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
@@ -442,6 +442,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ lockdep_assert_held(&hdmi->hw_lock);
|
||||
+
|
||||
WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
|
||||
if (reg >= variant->num_registers) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,449 +0,0 @@
|
|||
From a2cadb4575045b8503169302f3b18011c7e09c77 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 14:19:04 +0200
|
||||
Subject: [PATCH 015/634] drm/vc4: hdmi: Use a mutex to prevent concurrent
|
||||
framework access
|
||||
|
||||
The vc4 HDMI controller registers into the KMS, CEC and ALSA
|
||||
frameworks.
|
||||
|
||||
However, no particular care is done to prevent the concurrent execution
|
||||
of different framework hooks from happening at the same time.
|
||||
|
||||
In order to protect against that scenario, let's introduce a mutex that
|
||||
relevant ALSA and KMS hooks will need to take to prevent concurrent
|
||||
execution.
|
||||
|
||||
CEC is left out at the moment though, since the .get_modes and .detect
|
||||
KMS hooks, when running cec_s_phys_addr_from_edid, can end up calling
|
||||
CEC's .adap_enable hook. This introduces some reentrancy that isn't easy
|
||||
to deal with properly.
|
||||
|
||||
The CEC hooks also don't share much state with the rest of the driver:
|
||||
the registers are entirely separate, we don't share any variable, the
|
||||
only thing that can conflict is the CEC clock divider setup that can be
|
||||
affected by a mode set.
|
||||
|
||||
However, after discussing it, it looks like CEC should be able to
|
||||
recover from this if it was to happen.
|
||||
|
||||
Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 118 +++++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 14 ++++
|
||||
2 files changed, 126 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 6a9d5d423cf8..a3f25efe60e9 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -186,6 +186,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
|
||||
bool connected = false;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
@@ -217,11 +219,13 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
@@ -238,10 +242,14 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
int ret = 0;
|
||||
struct edid *edid;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
edid = drm_get_edid(connector, vc4_hdmi->ddc);
|
||||
cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
|
||||
- if (!edid)
|
||||
- return -ENODEV;
|
||||
+ if (!edid) {
|
||||
+ ret = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
|
||||
@@ -261,6 +269,9 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
}
|
||||
}
|
||||
|
||||
+out:
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -477,6 +488,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
connector, mode);
|
||||
if (ret < 0) {
|
||||
@@ -528,6 +541,8 @@ static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
|
||||
struct drm_connector_state *conn_state = connector->state;
|
||||
union hdmi_infoframe frame;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_hdmi->variant->supports_hdr)
|
||||
return;
|
||||
|
||||
@@ -544,6 +559,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi_set_avi_infoframe(encoder);
|
||||
vc4_hdmi_set_spd_infoframe(encoder);
|
||||
/*
|
||||
@@ -563,6 +580,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_encoder->hdmi_monitor)
|
||||
return false;
|
||||
|
||||
@@ -581,6 +600,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
|
||||
@@ -650,6 +671,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
|
||||
@@ -666,6 +689,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
vc4_hdmi_disable_scrambling(encoder);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
@@ -675,6 +700,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
|
||||
@@ -689,6 +716,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
if (ret < 0)
|
||||
DRM_ERROR("Failed to release power domain: %d\n", ret);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
@@ -985,6 +1014,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
||||
* be faster than pixel clock, infinitesimally faster, tested in
|
||||
@@ -1005,13 +1036,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
@@ -1063,13 +1094,16 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return;
|
||||
|
||||
err_disable_pixel_clock:
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
err_put_runtime_pm:
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
-
|
||||
+out:
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1081,6 +1115,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (vc4_encoder->hdmi_monitor &&
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
|
||||
if (vc4_hdmi->variant->csc_setup)
|
||||
@@ -1097,6 +1133,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
@@ -1110,6 +1148,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
@@ -1169,6 +1209,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
|
||||
vc4_hdmi_recenter_fifo(vc4_hdmi);
|
||||
vc4_hdmi_enable_scrambling(encoder);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
@@ -1310,6 +1352,7 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
|
||||
n = 128 * samplerate / 1000;
|
||||
@@ -1343,13 +1386,17 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* If the HDMI encoder hasn't probed, or the encoder is
|
||||
* currently in DVI mode, treat the codec dai as missing.
|
||||
*/
|
||||
if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
|
||||
- VC4_HDMI_RAM_PACKET_ENABLE))
|
||||
+ VC4_HDMI_RAM_PACKET_ENABLE)) {
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return -ENODEV;
|
||||
+ }
|
||||
|
||||
vc4_hdmi->audio.streaming = true;
|
||||
|
||||
@@ -1365,6 +1412,8 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
if (vc4_hdmi->variant->phy_rng_enable)
|
||||
vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1375,6 +1424,8 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false);
|
||||
if (ret)
|
||||
@@ -1394,6 +1445,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
@@ -1408,6 +1461,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
vc4_hdmi_audio_reset(vc4_hdmi);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static int sample_rate_to_mai_fmt(int samplerate)
|
||||
@@ -1466,6 +1521,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
|
||||
sample_rate, params->sample_width, channels);
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
@@ -1520,6 +1577,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea));
|
||||
vc4_hdmi_set_audio_infoframe(encoder);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1562,7 +1621,9 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data,
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1892,6 +1953,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1938,6 +2010,17 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
unsigned long flags;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
@@ -1966,6 +2049,17 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
unsigned long flags;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1,
|
||||
(HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
|
||||
@@ -1984,6 +2078,17 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
if (msg->len > 16) {
|
||||
drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len);
|
||||
return -ENOMEM;
|
||||
@@ -2339,6 +2444,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
|
||||
if (!vc4_hdmi)
|
||||
return -ENOMEM;
|
||||
+ mutex_init(&vc4_hdmi->mutex);
|
||||
spin_lock_init(&vc4_hdmi->hw_lock);
|
||||
INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 006142fe8d4e..cf9bb21a8ef7 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -183,6 +183,20 @@ struct vc4_hdmi {
|
||||
* @hw_lock: Spinlock protecting device register access.
|
||||
*/
|
||||
spinlock_t hw_lock;
|
||||
+
|
||||
+ /**
|
||||
+ * @mutex: Mutex protecting the driver access across multiple
|
||||
+ * frameworks (KMS, ALSA).
|
||||
+ *
|
||||
+ * NOTE: While supported, CEC has been left out since
|
||||
+ * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a
|
||||
+ * reentrancy issue between .get_modes (or .detect) and .adap_enable.
|
||||
+ * Since we don't share any state between the CEC hooks and KMS', it's
|
||||
+ * not a big deal. The only trouble might come from updating the CEC
|
||||
+ * clock divider which might be affected by a modeset, but CEC should
|
||||
+ * be resilient to that.
|
||||
+ */
|
||||
+ struct mutex mutex;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
From d51fcb1a3d1b478c76935b01a8788ff546727149 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 14:19:29 +0200
|
||||
Subject: [PATCH 016/634] drm/vc4: hdmi: Prevent access to crtc->state outside
|
||||
of KMS
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
However, in the vc4 HDMI driver we do use that pointer in the ALSA code
|
||||
path, and potentially in the hotplug interrupt handler path.
|
||||
|
||||
These paths both need access to the CRTC adjusted mode in order for the
|
||||
proper dividers to be set for ALSA, and the scrambler state to be
|
||||
reinstated properly for hotplug.
|
||||
|
||||
Let's copy this mode into our private encoder structure and reference it
|
||||
from there when needed. Since that part is shared between KMS and other
|
||||
paths, we need to protect it using our mutex.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 38 +++++++++++++++++++++++-----------
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 32 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index a3f25efe60e9..355f85418862 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -483,8 +483,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
struct drm_connector_state *cstate = connector->state;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
- const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
|
||||
@@ -596,8 +595,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
@@ -623,18 +622,21 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
unsigned long flags;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
* state of the scrambler and in order to avoid any
|
||||
* inconsistency, let's disable it all the time.
|
||||
*/
|
||||
- if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
|
||||
+ if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
|
||||
- if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
|
||||
+ if (crtc && !vc4_hdmi_mode_needs_scrambling(mode))
|
||||
return;
|
||||
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
@@ -1007,8 +1009,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
vc4_hdmi_encoder_get_connector_state(encoder, state);
|
||||
struct vc4_hdmi_connector_state *vc4_conn_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(conn_state);
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
unsigned long bvb_rate, hsm_rate;
|
||||
unsigned long flags;
|
||||
@@ -1110,9 +1112,9 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
@@ -1140,8 +1142,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
||||
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
||||
@@ -1217,6 +1219,19 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
+static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ memcpy(&vc4_hdmi->saved_adjusted_mode,
|
||||
+ &crtc_state->adjusted_mode,
|
||||
+ sizeof(vc4_hdmi->saved_adjusted_mode));
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+}
|
||||
+
|
||||
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
|
||||
#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
|
||||
|
||||
@@ -1293,6 +1308,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
|
||||
static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
|
||||
.atomic_check = vc4_hdmi_encoder_atomic_check,
|
||||
+ .atomic_mode_set = vc4_hdmi_encoder_atomic_mode_set,
|
||||
.mode_valid = vc4_hdmi_encoder_mode_valid,
|
||||
.disable = vc4_hdmi_encoder_disable,
|
||||
.enable = vc4_hdmi_encoder_enable,
|
||||
@@ -1346,9 +1362,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
|
||||
static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
|
||||
{
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
- const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index cf9bb21a8ef7..a43cc5614d19 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -197,6 +197,12 @@ struct vc4_hdmi {
|
||||
* be resilient to that.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
+
|
||||
+ /**
|
||||
+ * @saved_adjusted_mode: Copy of @drm_crtc_state.adjusted_mode
|
||||
+ * for use by ALSA hooks and interrupt handlers. Protected by @mutex.
|
||||
+ */
|
||||
+ struct drm_display_mode saved_adjusted_mode;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
From d78e135b703cd511621d2b396c03e8a8faa0b1a7 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 24 Sep 2021 14:27:38 +0200
|
||||
Subject: [PATCH 017/634] drm/vc4: hdmi: Check the device state in prepare()
|
||||
|
||||
Even though we already check that the encoder->crtc pointer is there
|
||||
during in startup(), which is part of the open() path in ASoC, nothing
|
||||
guarantees that our encoder state won't change between the time when we
|
||||
open the device and the time we prepare it.
|
||||
|
||||
Move the sanity checks we do in startup() to a helper and call it from
|
||||
prepare().
|
||||
|
||||
Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 35 +++++++++++++++++++++++++++-------
|
||||
1 file changed, 28 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 355f85418862..8ea2291fe784 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1394,20 +1394,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
|
||||
return snd_soc_card_get_drvdata(card);
|
||||
}
|
||||
|
||||
+static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
|
||||
+{
|
||||
+ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
+
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
+ /*
|
||||
+ * The encoder doesn't have a CRTC until the first modeset.
|
||||
+ */
|
||||
+ if (!encoder->crtc)
|
||||
+ return false;
|
||||
+
|
||||
+ /*
|
||||
+ * If the encoder is currently in DVI mode, treat the codec DAI
|
||||
+ * as missing.
|
||||
+ */
|
||||
+ if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
|
||||
- /*
|
||||
- * If the HDMI encoder hasn't probed, or the encoder is
|
||||
- * currently in DVI mode, treat the codec dai as missing.
|
||||
- */
|
||||
- if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
|
||||
- VC4_HDMI_RAM_PACKET_ENABLE)) {
|
||||
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
|
||||
mutex_unlock(&vc4_hdmi->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1537,6 +1553,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
|
||||
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
From b3fa147e2b8ec4b9acf242a589e464ed49b54ffe Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 17:31:58 +0200
|
||||
Subject: [PATCH 018/634] drm/vc4: hdmi: Introduce an output_enabled flag
|
||||
|
||||
We currently poke at encoder->crtc in the ALSA code path to determine
|
||||
whether the HDMI output is enabled or not, and thus whether we should
|
||||
allow the audio output.
|
||||
|
||||
However, that pointer is deprecated and shouldn't really be used by
|
||||
atomic drivers anymore. Since we have the infrastructure in place now,
|
||||
let's just create a flag that we toggle to report whether the controller
|
||||
is currently enabled and use that instead of encoder->crtc in ALSA.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++++++++++----
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 8ea2291fe784..d31fd7e1fb17 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -724,6 +724,11 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ vc4_hdmi->output_enabled = false;
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
@@ -1217,6 +1222,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ vc4_hdmi->output_enabled = true;
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
@@ -1396,14 +1406,12 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
|
||||
|
||||
static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
-
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
|
||||
/*
|
||||
- * The encoder doesn't have a CRTC until the first modeset.
|
||||
+ * If the controller is disabled, prevent any ALSA output.
|
||||
*/
|
||||
- if (!encoder->crtc)
|
||||
+ if (!vc4_hdmi->output_enabled)
|
||||
return false;
|
||||
|
||||
/*
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index a43cc5614d19..5d3e97703e8d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -203,6 +203,12 @@ struct vc4_hdmi {
|
||||
* for use by ALSA hooks and interrupt handlers. Protected by @mutex.
|
||||
*/
|
||||
struct drm_display_mode saved_adjusted_mode;
|
||||
+
|
||||
+ /**
|
||||
+ * @output_enabled: Is the HDMI controller currently active?
|
||||
+ * Protected by @mutex.
|
||||
+ */
|
||||
+ bool output_enabled;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
From 9aa26a91fcad0b72ff20dbc5dbce2a39eaf73d41 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 19:13:46 +0200
|
||||
Subject: [PATCH 019/634] drm/vc4: hdmi: Introduce a scdc_enabled flag
|
||||
|
||||
We currently rely on two functions, vc4_hdmi_supports_scrambling() and
|
||||
vc4_hdmi_mode_needs_scrambling() to determine if we should enable and
|
||||
disable the scrambler for any given mode.
|
||||
|
||||
Since we might need to disable the controller at boot, we also always
|
||||
run vc4_hdmi_disable_scrambling() and thus call those functions without
|
||||
a mode yet, which in turns need to make some special casing in order for
|
||||
it to work.
|
||||
|
||||
Instead of duplicating the check for whether or not we need to take care
|
||||
of the scrambler in both vc4_hdmi_enable_scrambling() and
|
||||
vc4_hdmi_disable_scrambling(), we can do that check only when we enable
|
||||
it and store whether or not it's been enabled in our private structure.
|
||||
|
||||
We also need to initialize that flag at true to make sure we disable the
|
||||
scrambler at boot since we can't really know its state yet.
|
||||
|
||||
This allows to simplify a bit that part of the driver, and removes one
|
||||
user of our copy of the CRTC adjusted mode outside of KMS (since
|
||||
vc4_hdmi_disable_scrambling() might be called from the hotplug interrupt
|
||||
handler).
|
||||
|
||||
It also removes our last user of the legacy encoder->crtc pointer.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 22 ++++++++++++----------
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 18 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index d31fd7e1fb17..5cca1dacc933 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -615,6 +615,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
+ vc4_hdmi->scdc_enabled = true;
|
||||
+
|
||||
queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
|
||||
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
|
||||
}
|
||||
@@ -622,22 +624,14 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
- struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
|
||||
- /*
|
||||
- * At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
- * state of the scrambler and in order to avoid any
|
||||
- * inconsistency, let's disable it all the time.
|
||||
- */
|
||||
- if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
+ if (!vc4_hdmi->scdc_enabled)
|
||||
return;
|
||||
|
||||
- if (crtc && !vc4_hdmi_mode_needs_scrambling(mode))
|
||||
- return;
|
||||
+ vc4_hdmi->scdc_enabled = false;
|
||||
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
|
||||
@@ -2502,6 +2496,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi->pdev = pdev;
|
||||
vc4_hdmi->variant = variant;
|
||||
|
||||
+ /*
|
||||
+ * Since we don't know the state of the controller and its
|
||||
+ * display (if any), let's assume it's always enabled.
|
||||
+ * vc4_hdmi_disable_scrambling() will thus run at boot, make
|
||||
+ * sure it's disabled, and avoid any inconsistency.
|
||||
+ */
|
||||
+ vc4_hdmi->scdc_enabled = true;
|
||||
+
|
||||
ret = variant->init_resources(vc4_hdmi);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 5d3e97703e8d..36c0b082a43b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -209,6 +209,12 @@ struct vc4_hdmi {
|
||||
* Protected by @mutex.
|
||||
*/
|
||||
bool output_enabled;
|
||||
+
|
||||
+ /**
|
||||
+ * @scdc_enabled: Is the HDMI controller currently running with
|
||||
+ * the scrambler on? Protected by @mutex.
|
||||
+ */
|
||||
+ bool scdc_enabled;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From 46ea9d1cd67819a8ecdd75893290cbb259f7a71f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 11 May 2021 17:05:11 +0200
|
||||
Subject: [PATCH 020/634] drm/vc4: hdmi: Remove the DDC probing for status
|
||||
detection
|
||||
|
||||
Commit 9d44abbbb8d5 ("drm/vc4: Fall back to using an EDID probe in the
|
||||
absence of a GPIO.") added some code to read the EDID through DDC in the
|
||||
HDMI driver detect hook since the Pi3 had no HPD GPIO back then.
|
||||
However, commit b1b8f45b3130 ("ARM: dts: bcm2837: Add missing GPIOs of
|
||||
Expander") changed that a couple of years later.
|
||||
|
||||
This causes an issue though since some TV (like the LG 55C8) when it
|
||||
comes out of standy will deassert the HPD line, but the EDID will
|
||||
remain readable.
|
||||
|
||||
It causes an issues nn platforms without an HPD GPIO, like the Pi4,
|
||||
where the DDC probing will be our primary mean to detect a display, and
|
||||
thus we will never detect the HPD pulse. This was fine before since the
|
||||
pulse was small enough that we would never detect it, and we also didn't
|
||||
have anything (like the scrambler) that needed to be set up in the
|
||||
display.
|
||||
|
||||
However, now that we have both, the display during the HPD pulse will
|
||||
clear its scrambler status, and since we won't detect the
|
||||
disconnect/reconnect cycle we will never enable the scrambler back.
|
||||
|
||||
As our main reason for that DDC probing is gone, let's just remove it.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 5cca1dacc933..918941a2bc58 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -193,8 +193,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
connected = true;
|
||||
- } else if (drm_probe_ddc(vc4_hdmi->ddc)) {
|
||||
- connected = true;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u32 hotplug;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From 84da606fe60662e046d6f7982d8a9281245b09f5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 25 Jun 2021 17:16:51 +0200
|
||||
Subject: [PATCH 021/634] drm/vc4: hdmi: Fix HPD GPIO detection
|
||||
|
||||
Prior to commit 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod"), in the
|
||||
detect hook, if we had an HPD GPIO we would only rely on it and return
|
||||
whatever state it was in.
|
||||
|
||||
However, that commit changed that by mistake to only consider the case
|
||||
where we have a GPIO and it returns a logical high, and would fall back
|
||||
to the other methods otherwise.
|
||||
|
||||
Since we can read the EDIDs when the HPD signal is low on some displays,
|
||||
we changed the detection status from disconnected to connected, and we
|
||||
would ignore an HPD pulse.
|
||||
|
||||
Fixes: 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 918941a2bc58..50e9e1f3ac47 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -190,9 +190,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
|
||||
- if (vc4_hdmi->hpd_gpio &&
|
||||
- gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
- connected = true;
|
||||
+ if (vc4_hdmi->hpd_gpio) {
|
||||
+ if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
|
||||
+ connected = true;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u32 hotplug;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
From 6ca024fdd37a7953f7f6ee301fef026cf9446272 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 26 May 2021 16:07:01 +0200
|
||||
Subject: [PATCH 022/634] drm/vc4: Make vc4_crtc_get_encoder public
|
||||
|
||||
We'll need that function in vc4_kms to compute the core clock rate
|
||||
requirements.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 8 ++++----
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 5 +++++
|
||||
2 files changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e3ed52d96f42..7cfd4a097847 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -281,10 +281,10 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
|
||||
* allows drivers to push pixels to more than one encoder from the
|
||||
* same CRTC.
|
||||
*/
|
||||
-static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector))
|
||||
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state,
|
||||
+ struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
+ struct drm_connector *connector))
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 4b550ebd9572..f5e678491502 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -544,6 +544,11 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
return container_of(data, struct vc4_pv_data, base);
|
||||
}
|
||||
|
||||
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state,
|
||||
+ struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
+ struct drm_connector *connector));
|
||||
+
|
||||
struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
/* Dlist area for this CRTC configuration. */
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
From c2092ee4811081bab692db0ccf4893797df54b13 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 14 Jun 2021 15:27:24 +0200
|
||||
Subject: [PATCH 023/634] drm/vc4: crtc: Add encoder to vc4_crtc_config_pv
|
||||
prototype
|
||||
|
||||
vc4_crtc_config_pv() retrieves the encoder again, even though its only
|
||||
caller, vc4_crtc_atomic_enable(), already did.
|
||||
|
||||
Pass the encoder pointer as an argument instead of going through all the
|
||||
connectors to retrieve it again.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 7cfd4a097847..e5c2e29a6f01 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -315,12 +315,11 @@ static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
|
||||
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
|
||||
}
|
||||
|
||||
-static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
+static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encoder,
|
||||
+ struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_new_connector_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
|
||||
@@ -597,7 +596,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
if (vc4_encoder->pre_crtc_configure)
|
||||
vc4_encoder->pre_crtc_configure(encoder, state);
|
||||
|
||||
- vc4_crtc_config_pv(crtc, state);
|
||||
+ vc4_crtc_config_pv(crtc, encoder, state);
|
||||
|
||||
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
From af2318d413f366931b7efaf179c326d67557e64b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 16:07:22 +0200
|
||||
Subject: [PATCH 024/634] drm/vc4: crtc: Rework the encoder retrieval code
|
||||
(again)
|
||||
|
||||
It turns out the encoder retrieval code, in addition to being
|
||||
unnecessarily complicated, has a bug when only the planes and crtcs are
|
||||
affected by a given atomic commit.
|
||||
|
||||
Indeed, in such a case, either drm_atomic_get_old_connector_state or
|
||||
drm_atomic_get_new_connector_state will return NULL and thus our encoder
|
||||
retrieval code will not match on anything.
|
||||
|
||||
We can however simplify the code by using drm_for_each_encoder_mask, the
|
||||
drm_crtc_state storing the encoders a given CRTC is connected to
|
||||
directly and without relying on any other state.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 30 +++++++++---------------------
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 4 +---
|
||||
2 files changed, 10 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e5c2e29a6f01..fbc1d4638650 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -282,26 +282,14 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
|
||||
* same CRTC.
|
||||
*/
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector))
|
||||
+ struct drm_crtc_state *state)
|
||||
{
|
||||
- struct drm_connector *connector;
|
||||
- struct drm_connector_list_iter conn_iter;
|
||||
-
|
||||
- drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
||||
- drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
- struct drm_connector_state *conn_state = get_state(state, connector);
|
||||
+ struct drm_encoder *encoder;
|
||||
|
||||
- if (!conn_state)
|
||||
- continue;
|
||||
+ WARN_ON(hweight32(state->encoder_mask) > 1);
|
||||
|
||||
- if (conn_state->crtc == crtc) {
|
||||
- drm_connector_list_iter_end(&conn_iter);
|
||||
- return connector->encoder;
|
||||
- }
|
||||
- }
|
||||
- drm_connector_list_iter_end(&conn_iter);
|
||||
+ drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask)
|
||||
+ return encoder;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -550,8 +538,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
|
||||
crtc);
|
||||
struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_old_connector_state);
|
||||
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, old_state);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
require_hvs_enabled(dev);
|
||||
@@ -578,10 +565,11 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
|
||||
+ crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_new_connector_state);
|
||||
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, new_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
|
||||
require_hvs_enabled(dev);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index f5e678491502..60826aca9e5b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -545,9 +545,7 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
}
|
||||
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector));
|
||||
+ struct drm_crtc_state *state);
|
||||
|
||||
struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From f13f8a8233fdec553f3788edba1ebf5a6090b330 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 16:13:02 +0200
|
||||
Subject: [PATCH 025/634] drm/vc4: crtc: Add some logging
|
||||
|
||||
The encoder retrieval code has been a source of bugs and glitches in the
|
||||
past and the crtc <-> encoder association been wrong in a number of
|
||||
different ways.
|
||||
|
||||
Add some logging to quickly spot issues if they occur.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index fbc1d4638650..6decaa12a078 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -541,6 +541,9 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, old_state);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
+ drm_dbg(dev, "Disabling CRTC %s (%u) connected to Encoder %s (%u)",
|
||||
+ crtc->name, crtc->base.id, encoder->name, encoder->base.id);
|
||||
+
|
||||
require_hvs_enabled(dev);
|
||||
|
||||
/* Disable vblank irq handling before crtc is disabled. */
|
||||
@@ -572,6 +575,9 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, new_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
|
||||
+ drm_dbg(dev, "Enabling CRTC %s (%u) connected to Encoder %s (%u)",
|
||||
+ crtc->name, crtc->base.id, encoder->name, encoder->base.id);
|
||||
+
|
||||
require_hvs_enabled(dev);
|
||||
|
||||
/* Enable vblank irq handling before crtc is started otherwise
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
From b678d84ff877cf7f4264707f30f5e26c643f8414 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 17:19:22 +0200
|
||||
Subject: [PATCH 026/634] drm/vc4: Leverage the load tracker on the BCM2711
|
||||
|
||||
The load tracker was initially designed to report and warn about a load
|
||||
too high for the HVS. To do so, it computes for each plane the impact
|
||||
it's going to have on the HVS, and will warn (if it's enabled) if we go
|
||||
over what the hardware can process.
|
||||
|
||||
While the limits being used are a bit irrelevant to the BCM2711, the
|
||||
algorithm to compute the HVS load will be one component used in order to
|
||||
compute the core clock rate on the BCM2711.
|
||||
|
||||
Let's remove the hooks to prevent the load tracker to do its
|
||||
computation, but since we don't have the same limits, don't check them
|
||||
against them, and prevent the debugfs file to enable it from being
|
||||
created.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_debugfs.c | 7 +++++--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 3 ---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 16 +++++-----------
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 5 -----
|
||||
4 files changed, 10 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
index 6da22af4ee91..ba2d8ea562af 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/platform_device.h>
|
||||
|
||||
#include "vc4_drv.h"
|
||||
#include "vc4_regs.h"
|
||||
@@ -26,8 +27,10 @@ vc4_debugfs_init(struct drm_minor *minor)
|
||||
struct vc4_dev *vc4 = to_vc4_dev(minor->dev);
|
||||
struct vc4_debugfs_info_entry *entry;
|
||||
|
||||
- debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
- minor->debugfs_root, &vc4->load_tracker_enabled);
|
||||
+ if (!of_device_is_compatible(vc4->hvs->pdev->dev.of_node,
|
||||
+ "brcm,bcm2711-vc5"))
|
||||
+ debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
+ minor->debugfs_root, &vc4->load_tracker_enabled);
|
||||
|
||||
list_for_each_entry(entry, &vc4->debugfs_list, link) {
|
||||
drm_debugfs_create_files(&entry->info, 1,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 60826aca9e5b..813c5d0ea98e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -202,9 +202,6 @@ struct vc4_dev {
|
||||
|
||||
int power_refcount;
|
||||
|
||||
- /* Set to true when the load tracker is supported. */
|
||||
- bool load_tracker_available;
|
||||
-
|
||||
/* Set to true when the load tracker is active. */
|
||||
bool load_tracker_enabled;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 028f19f7a5f8..41cb4869da50 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -552,9 +552,6 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state)
|
||||
struct drm_plane *plane;
|
||||
int i;
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return 0;
|
||||
-
|
||||
priv_state = drm_atomic_get_private_obj_state(state,
|
||||
&vc4->load_tracker);
|
||||
if (IS_ERR(priv_state))
|
||||
@@ -629,9 +626,6 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return;
|
||||
-
|
||||
drm_atomic_private_obj_fini(&vc4->load_tracker);
|
||||
}
|
||||
|
||||
@@ -639,9 +633,6 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
|
||||
{
|
||||
struct vc4_load_tracker_state *load_state;
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return 0;
|
||||
-
|
||||
load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
|
||||
if (!load_state)
|
||||
return -ENOMEM;
|
||||
@@ -869,9 +860,12 @@ int vc4_kms_load(struct drm_device *dev)
|
||||
"brcm,bcm2711-vc5");
|
||||
int ret;
|
||||
|
||||
+ /*
|
||||
+ * The limits enforced by the load tracker aren't relevant for
|
||||
+ * the BCM2711, but the load tracker computations are used for
|
||||
+ * the core clock rate calculation.
|
||||
+ */
|
||||
if (!is_vc5) {
|
||||
- vc4->load_tracker_available = true;
|
||||
-
|
||||
/* Start with the load tracker enabled. Can be
|
||||
* disabled through the debugfs load_tracker file.
|
||||
*/
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 19161b6ab27f..ac761c683663 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -529,11 +529,6 @@ static void vc4_plane_calc_load(struct drm_plane_state *state)
|
||||
struct vc4_plane_state *vc4_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
unsigned int vscale_factor;
|
||||
- struct vc4_dev *vc4;
|
||||
-
|
||||
- vc4 = to_vc4_dev(state->plane->dev);
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return;
|
||||
|
||||
vc4_state = to_vc4_plane_state(state);
|
||||
crtc_state = drm_atomic_get_existing_crtc_state(state->state,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
From cd009dc7e47225c5736cae1d706adcb30b8d4ef5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 8 Oct 2020 16:08:06 +0200
|
||||
Subject: [PATCH 027/634] drm/vc4: hdmi: Raise the maximum clock rate
|
||||
|
||||
Now that we have the infrastructure in place, we can raise the maximum
|
||||
pixel rate we can reach for HDMI0 on the BCM2711.
|
||||
|
||||
HDMI1 is left untouched since its pixelvalve has a smaller FIFO and
|
||||
would need a clock faster than what we can provide to support the same
|
||||
modes.
|
||||
|
||||
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 50e9e1f3ac47..80ce69e0ead5 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -2697,7 +2697,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
|
||||
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
|
||||
.debugfs_name = "hdmi0_regs",
|
||||
.card_name = "vc4-hdmi-0",
|
||||
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
|
||||
+ .max_pixel_clock = 600000000,
|
||||
.registers = vc5_hdmi_hdmi0_fields,
|
||||
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
|
||||
.phy_lane_mapping = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From 4c78953fff281d78eabbd336a17bcded00d6316f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 25 Jun 2021 16:22:39 +0200
|
||||
Subject: [PATCH 028/634] drm/vc4: hdmi: Enable the scrambler on reconnection
|
||||
|
||||
If we have a state already and disconnect/reconnect the display, the
|
||||
SCDC messages won't be sent again since we didn't go through a disable /
|
||||
enable cycle.
|
||||
|
||||
In order to fix this, let's call the vc4_hdmi_enable_scrambling function
|
||||
in the detect callback if there is a mode and it needs the scrambler to
|
||||
be enabled.
|
||||
|
||||
Fixes: c85695a2016e ("drm/vc4: hdmi: Enable the scrambler")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 80ce69e0ead5..87870775471d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -180,6 +180,8 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
||||
#endif
|
||||
|
||||
+static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder);
|
||||
+
|
||||
static enum drm_connector_status
|
||||
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@@ -216,6 +218,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
+ vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base.base);
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_connected;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
From 32ab2dd5dc63120f1e006e4a3a6beaafbd5dd550 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 26 May 2021 16:13:02 +0200
|
||||
Subject: [PATCH 029/634] drm/vc4: Increase the core clock based on HVS load
|
||||
|
||||
Depending on a given HVS output (HVS to PixelValves) and input (planes
|
||||
attached to a channel) load, the HVS needs for the core clock to be
|
||||
raised above its boot time default.
|
||||
|
||||
Failing to do so will result in a vblank timeout and a stalled display
|
||||
pipeline.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 15 +++++
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 2 +
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 110 ++++++++++++++++++++++++++++++---
|
||||
3 files changed, 118 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 6decaa12a078..287dbc89ad64 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -659,12 +659,27 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
struct drm_connector *conn;
|
||||
struct drm_connector_state *conn_state;
|
||||
+ struct drm_encoder *encoder;
|
||||
int ret, i;
|
||||
|
||||
ret = vc4_hvs_atomic_check(crtc, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ encoder = vc4_get_crtc_encoder(crtc, crtc_state);
|
||||
+ if (encoder) {
|
||||
+ const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
||||
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
+
|
||||
+ mode = &crtc_state->adjusted_mode;
|
||||
+ if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) {
|
||||
+ vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000,
|
||||
+ mode->clock * 9 / 10) * 1000;
|
||||
+ } else {
|
||||
+ vc4_state->hvs_load = mode->clock * 1000;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
for_each_new_connector_in_state(state, conn, conn_state,
|
||||
i) {
|
||||
if (conn_state->crtc != crtc)
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 813c5d0ea98e..4329e09d357c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -558,6 +558,8 @@ struct vc4_crtc_state {
|
||||
unsigned int bottom;
|
||||
} margins;
|
||||
|
||||
+ unsigned long hvs_load;
|
||||
+
|
||||
/* Transitional state below, only valid during atomic commits */
|
||||
bool update_muxing;
|
||||
};
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 41cb4869da50..79d4d9dd1394 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -39,9 +39,11 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
|
||||
|
||||
struct vc4_hvs_state {
|
||||
struct drm_private_state base;
|
||||
+ unsigned long core_clock_rate;
|
||||
|
||||
struct {
|
||||
unsigned in_use: 1;
|
||||
+ unsigned long fifo_load;
|
||||
struct drm_crtc_commit *pending_commit;
|
||||
} fifo_state[HVS_NUM_CHANNELS];
|
||||
};
|
||||
@@ -340,10 +342,19 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
struct vc4_hvs *hvs = vc4->hvs;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
+ struct vc4_hvs_state *new_hvs_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct vc4_hvs_state *old_hvs_state;
|
||||
int i;
|
||||
|
||||
+ old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
+ if (WARN_ON(!old_hvs_state))
|
||||
+ return;
|
||||
+
|
||||
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
+ if (WARN_ON(!new_hvs_state))
|
||||
+ return;
|
||||
+
|
||||
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state;
|
||||
|
||||
@@ -354,12 +365,13 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
|
||||
}
|
||||
|
||||
- if (vc4->hvs->hvs5)
|
||||
- clk_set_min_rate(hvs->core_clk, 500000000);
|
||||
+ if (vc4->hvs->hvs5) {
|
||||
+ unsigned long core_rate = max_t(unsigned long,
|
||||
+ 500000000,
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
|
||||
- old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
- if (!old_hvs_state)
|
||||
- return;
|
||||
+ clk_set_min_rate(hvs->core_clk, core_rate);
|
||||
+ }
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
@@ -399,8 +411,12 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
|
||||
- if (vc4->hvs->hvs5)
|
||||
- clk_set_min_rate(hvs->core_clk, 0);
|
||||
+ if (vc4->hvs->hvs5) {
|
||||
+ drm_dbg(dev, "Running the core clock at %lu Hz\n",
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
+
|
||||
+ clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
|
||||
@@ -657,9 +673,9 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
|
||||
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
|
||||
|
||||
-
|
||||
for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
|
||||
+ state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
|
||||
|
||||
if (!old_state->fifo_state[i].pending_commit)
|
||||
continue;
|
||||
@@ -668,6 +684,8 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
|
||||
}
|
||||
|
||||
+ state->core_clock_rate = old_state->core_clock_rate;
|
||||
+
|
||||
return &state->base;
|
||||
}
|
||||
|
||||
@@ -822,6 +840,76 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+vc4_core_clock_atomic_check(struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(state->dev);
|
||||
+ struct drm_private_state *priv_state;
|
||||
+ struct vc4_hvs_state *hvs_new_state;
|
||||
+ struct vc4_load_tracker_state *load_state;
|
||||
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
||||
+ struct drm_crtc *crtc;
|
||||
+ unsigned int num_outputs;
|
||||
+ unsigned long pixel_rate;
|
||||
+ unsigned long cob_rate;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ priv_state = drm_atomic_get_private_obj_state(state,
|
||||
+ &vc4->load_tracker);
|
||||
+ if (IS_ERR(priv_state))
|
||||
+ return PTR_ERR(priv_state);
|
||||
+
|
||||
+ load_state = to_vc4_load_tracker_state(priv_state);
|
||||
+
|
||||
+ hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
+ if (!hvs_new_state)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for_each_oldnew_crtc_in_state(state, crtc,
|
||||
+ old_crtc_state,
|
||||
+ new_crtc_state,
|
||||
+ i) {
|
||||
+ if (old_crtc_state->active) {
|
||||
+ struct vc4_crtc_state *old_vc4_state =
|
||||
+ to_vc4_crtc_state(old_crtc_state);
|
||||
+ unsigned int channel = old_vc4_state->assigned_channel;
|
||||
+
|
||||
+ hvs_new_state->fifo_state[channel].fifo_load = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (new_crtc_state->active) {
|
||||
+ struct vc4_crtc_state *new_vc4_state =
|
||||
+ to_vc4_crtc_state(new_crtc_state);
|
||||
+ unsigned int channel = new_vc4_state->assigned_channel;
|
||||
+
|
||||
+ hvs_new_state->fifo_state[channel].fifo_load =
|
||||
+ new_vc4_state->hvs_load;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ cob_rate = 0;
|
||||
+ num_outputs = 0;
|
||||
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
+ if (!hvs_new_state->fifo_state[i].in_use)
|
||||
+ continue;
|
||||
+
|
||||
+ num_outputs++;
|
||||
+ cob_rate += hvs_new_state->fifo_state[i].fifo_load;
|
||||
+ }
|
||||
+
|
||||
+ pixel_rate = load_state->hvs_load;
|
||||
+ if (num_outputs > 1) {
|
||||
+ pixel_rate = (pixel_rate * 40) / 100;
|
||||
+ } else {
|
||||
+ pixel_rate = (pixel_rate * 60) / 100;
|
||||
+ }
|
||||
+
|
||||
+ hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
|
||||
{
|
||||
@@ -839,7 +927,11 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return vc4_load_tracker_atomic_check(state);
|
||||
+ ret = vc4_load_tracker_atomic_check(state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return vc4_core_clock_atomic_check(state);
|
||||
}
|
||||
|
||||
static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
From 13fd7f615657b8b300e1840a1ec393079126f53f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:53:03 +0200
|
||||
Subject: [PATCH 030/634] drm/vc4: select PM
|
||||
|
||||
We already depend on runtime PM to get the power domains and clocks for
|
||||
most of the devices supported by the vc4 driver, so let's just select it
|
||||
to make sure it's there, and remove the ifdef.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
|
||||
index 345a5570a3da..52a1c309cb4a 100644
|
||||
--- a/drivers/gpu/drm/vc4/Kconfig
|
||||
+++ b/drivers/gpu/drm/vc4/Kconfig
|
||||
@@ -9,6 +9,7 @@ config DRM_VC4
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_PANEL_BRIDGE
|
||||
+ select PM
|
||||
select SND_PCM
|
||||
select SND_PCM_ELD
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
From 9219926b71a1c16eb77ef9d96b14913b7f03757d Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 13:50:12 +0200
|
||||
Subject: [PATCH 032/634] drm/vc4: hdmi: Actually check for the connector
|
||||
status in hotplug
|
||||
|
||||
The drm_helper_hpd_irq_event() documentation states that this function
|
||||
is "useful for drivers which can't or don't track hotplug interrupts for
|
||||
each connector." and that "Drivers which support hotplug interrupts for
|
||||
each connector individually and which have a more fine-grained detect
|
||||
logic should bypass this code and directly call
|
||||
drm_kms_helper_hotplug_event()". This is thus what we ended-up doing.
|
||||
|
||||
However, what this actually means, and is further explained in the
|
||||
drm_kms_helper_hotplug_event() documentation, is that
|
||||
drm_kms_helper_hotplug_event() should be called by drivers that can
|
||||
track the connection status change, and if it has changed we should call
|
||||
that function.
|
||||
|
||||
This underlying expectation we failed to provide is that the caller of
|
||||
drm_kms_helper_hotplug_event() should call drm_helper_probe_detect() to
|
||||
probe the new status of the connector.
|
||||
|
||||
Since we didn't do it, it meant that even though we were sending the
|
||||
notification to user-space and the DRM clients that something changed we
|
||||
never probed or updated our internal connector status ourselves.
|
||||
|
||||
This went mostly unnoticed since the detect callback usually doesn't
|
||||
have any side-effect. Also, if we were using the DRM fbdev emulation
|
||||
(which is a DRM client), or any user-space application that can deal
|
||||
with hotplug events, chances are they would react to the hotplug event
|
||||
by probing the connector status eventually.
|
||||
|
||||
However, now that we have to enable the scrambler in detect() if it was
|
||||
enabled it has a side effect, and an application such as Kodi or
|
||||
modetest doesn't deal with hotplug events. This resulted with a black
|
||||
screen when Kodi or modetest was running when a screen was disconnected
|
||||
and then reconnected, or switched off and on.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 87870775471d..053fbaf765ca 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1783,10 +1783,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
- struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
+ struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
+ struct drm_device *dev = connector->dev;
|
||||
|
||||
if (dev && dev->registered)
|
||||
- drm_kms_helper_hotplug_event(dev);
|
||||
+ drm_connector_helper_hpd_irq_event(connector);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
From 59a74cec84cf3d24346e378fd9b93df8ee593135 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 6 Jan 2020 14:05:42 +0000
|
||||
Subject: [PATCH 204/634] pinctrl: bcm2835: Change init order for gpio hogs
|
||||
|
||||
pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio
|
||||
side is registered first, but this breaks gpio hogs (which are
|
||||
configured during gpiochip_add_data). Part of the hog initialisation
|
||||
is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't
|
||||
yet been registered this results in an -EPROBE_DEFER from which it can
|
||||
never recover.
|
||||
|
||||
Change the initialisation sequence to register the pinctrl driver
|
||||
first.
|
||||
|
||||
See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 29 +++++++++++++++------------
|
||||
1 file changed, 16 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
index 1fb103eb34a2..28ddc9f139a6 100644
|
||||
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
@@ -1243,6 +1243,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
raw_spin_lock_init(&pc->irq_lock[i]);
|
||||
}
|
||||
|
||||
+ pc->pctl_desc = *pdata->pctl_desc;
|
||||
+ pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
|
||||
+ if (IS_ERR(pc->pctl_dev)) {
|
||||
+ gpiochip_remove(&pc->gpio_chip);
|
||||
+ return PTR_ERR(pc->pctl_dev);
|
||||
+ }
|
||||
+
|
||||
+ pc->gpio_range = *pdata->gpio_range;
|
||||
+ pc->gpio_range.base = pc->gpio_chip.base;
|
||||
+ pc->gpio_range.gc = &pc->gpio_chip;
|
||||
+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
+
|
||||
girq = &pc->gpio_chip.irq;
|
||||
girq->chip = &bcm2835_gpio_irq_chip;
|
||||
girq->parent_handler = bcm2835_gpio_irq_handler;
|
||||
@@ -1250,8 +1262,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
- if (!girq->parents)
|
||||
+ if (!girq->parents) {
|
||||
+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
return -ENOMEM;
|
||||
+ }
|
||||
|
||||
if (is_7211) {
|
||||
pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
|
||||
@@ -1306,21 +1320,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
|
||||
err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
|
||||
if (err) {
|
||||
dev_err(dev, "could not add GPIO chip\n");
|
||||
+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
return err;
|
||||
}
|
||||
|
||||
- pc->pctl_desc = *pdata->pctl_desc;
|
||||
- pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
|
||||
- if (IS_ERR(pc->pctl_dev)) {
|
||||
- gpiochip_remove(&pc->gpio_chip);
|
||||
- return PTR_ERR(pc->pctl_dev);
|
||||
- }
|
||||
-
|
||||
- pc->gpio_range = *pdata->gpio_range;
|
||||
- pc->gpio_range.base = pc->gpio_chip.base;
|
||||
- pc->gpio_range.gc = &pc->gpio_chip;
|
||||
- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
From 78214f46d4903daf99263fdcc19ef2cb10d9030e Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 19 May 2020 14:54:28 +0100
|
||||
Subject: [PATCH 441/634] drm/vc4: Adopt the dma configuration from the HVS or
|
||||
V3D component
|
||||
|
||||
vc4_drv isn't necessarily under the /soc node in DT as it is a
|
||||
virtual device, but it is the one that does the allocations.
|
||||
The DMA addresses are consumed by primarily the HVS or V3D, and
|
||||
those require VideoCore cache alias address mapping, and so will be
|
||||
under /soc.
|
||||
|
||||
During probe find the a suitable device node for HVS or V3D,
|
||||
and adopt the DMA configuration of that node.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 18 ++++++++++++++++++
|
||||
1 file changed, 18 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index f6c16c5aee68..2a2e99873e40 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -214,6 +214,14 @@ static void vc4_match_add_drivers(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
+const struct of_device_id vc4_dma_range_matches[] = {
|
||||
+ { .compatible = "brcm,bcm2835-hvs" },
|
||||
+ { .compatible = "brcm,bcm2835-v3d" },
|
||||
+ { .compatible = "brcm,cygnus-v3d" },
|
||||
+ { .compatible = "brcm,vc4-v3d" },
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
static int vc4_drm_bind(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
@@ -231,6 +239,16 @@ static int vc4_drm_bind(struct device *dev)
|
||||
vc4_drm_driver.driver_features &= ~DRIVER_RENDER;
|
||||
of_node_put(node);
|
||||
|
||||
+ node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
|
||||
+ NULL);
|
||||
+ if (node) {
|
||||
+ ret = of_dma_configure(dev, node, true);
|
||||
+ of_node_put(node);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
vc4 = devm_drm_dev_alloc(dev, &vc4_drm_driver, struct vc4_dev, base);
|
||||
if (IS_ERR(vc4))
|
||||
return PTR_ERR(vc4);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
From 01281cef6f63e94e91a5eec62691b92d62451364 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Fri, 24 Jan 2020 14:25:41 +0000
|
||||
Subject: [PATCH 443/634] drm/vc4: Add support for DRM_FORMAT_P030 to vc4
|
||||
planes
|
||||
|
||||
This currently doesn't handle non-zero source rectangles correctly,
|
||||
but add support for DRM_FORMAT_P030 with DRM_FORMAT_MOD_BROADCOM_SAND128
|
||||
modifier to planes when running on HVS5.
|
||||
|
||||
WIP still for source cropping SAND/P030 formats
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 79 ++++++++++++++++++++++++---------
|
||||
1 file changed, 57 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index ac761c683663..37a99ab9538c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -33,6 +33,7 @@ static const struct hvs_format {
|
||||
u32 hvs; /* HVS_FORMAT_* */
|
||||
u32 pixel_order;
|
||||
u32 pixel_order_hvs5;
|
||||
+ bool hvs5_only;
|
||||
} hvs_formats[] = {
|
||||
{
|
||||
.drm = DRM_FORMAT_XRGB8888,
|
||||
@@ -128,6 +129,12 @@ static const struct hvs_format {
|
||||
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
|
||||
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
|
||||
},
|
||||
+ {
|
||||
+ .drm = DRM_FORMAT_P030,
|
||||
+ .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
|
||||
+ .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
|
||||
+ .hvs5_only = true,
|
||||
+ },
|
||||
};
|
||||
|
||||
static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
|
||||
@@ -764,27 +771,33 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
|
||||
u32 tile_w, tile, x_off, pix_per_tile;
|
||||
|
||||
- hvs_format = HVS_PIXEL_FORMAT_H264;
|
||||
-
|
||||
- switch (base_format_mod) {
|
||||
- case DRM_FORMAT_MOD_BROADCOM_SAND64:
|
||||
- tiling = SCALER_CTL0_TILING_64B;
|
||||
- tile_w = 64;
|
||||
- break;
|
||||
- case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
+ if (fb->format->format == DRM_FORMAT_P030) {
|
||||
+ hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
|
||||
tiling = SCALER_CTL0_TILING_128B;
|
||||
- tile_w = 128;
|
||||
- break;
|
||||
- case DRM_FORMAT_MOD_BROADCOM_SAND256:
|
||||
- tiling = SCALER_CTL0_TILING_256B_OR_T;
|
||||
- tile_w = 256;
|
||||
- break;
|
||||
- default:
|
||||
- break;
|
||||
+ tile_w = 96;
|
||||
+ } else {
|
||||
+ hvs_format = HVS_PIXEL_FORMAT_H264;
|
||||
+
|
||||
+ switch (base_format_mod) {
|
||||
+ case DRM_FORMAT_MOD_BROADCOM_SAND64:
|
||||
+ tiling = SCALER_CTL0_TILING_64B;
|
||||
+ tile_w = 64;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
+ tiling = SCALER_CTL0_TILING_128B;
|
||||
+ tile_w = 128;
|
||||
+ break;
|
||||
+ case DRM_FORMAT_MOD_BROADCOM_SAND256:
|
||||
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
|
||||
+ tile_w = 256;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
-
|
||||
if (param > SCALER_TILE_HEIGHT_MASK) {
|
||||
- DRM_DEBUG_KMS("SAND height too large (%d)\n", param);
|
||||
+ DRM_DEBUG_KMS("SAND height too large (%d)\n",
|
||||
+ param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -794,6 +807,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
|
||||
/* Adjust the base pointer to the first pixel to be scanned
|
||||
* out.
|
||||
+ *
|
||||
+ * For P030, y_ptr [31:4] is the 128bit word for the start pixel
|
||||
+ * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
|
||||
+ * word that should be taken as the first pixel.
|
||||
+ * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
|
||||
+ * element within the 128bit word, eg for pixel 3 the value
|
||||
+ * should be 6.
|
||||
*/
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
vc4_state->offsets[i] += param * tile_w * tile;
|
||||
@@ -955,7 +975,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
|
||||
/* Pitch word 1/2 */
|
||||
for (i = 1; i < num_planes; i++) {
|
||||
- if (hvs_format != HVS_PIXEL_FORMAT_H264) {
|
||||
+ if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
|
||||
+ hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
|
||||
vc4_dlist_write(vc4_state,
|
||||
VC4_SET_FIELD(fb->pitches[i],
|
||||
SCALER_SRC_PITCH));
|
||||
@@ -1315,6 +1336,13 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
+ case DRM_FORMAT_P030:
|
||||
+ switch (fourcc_mod_broadcom_mod(modifier)) {
|
||||
+ case DRM_FORMAT_MOD_BROADCOM_SAND128:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
case DRM_FORMAT_RGBX1010102:
|
||||
case DRM_FORMAT_BGRX1010102:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
@@ -1347,8 +1375,11 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
struct drm_plane *plane = NULL;
|
||||
struct vc4_plane *vc4_plane;
|
||||
u32 formats[ARRAY_SIZE(hvs_formats)];
|
||||
+ int num_formats = 0;
|
||||
int ret = 0;
|
||||
unsigned i;
|
||||
+ bool hvs5 = of_device_is_compatible(dev->dev->of_node,
|
||||
+ "brcm,bcm2711-vc5");
|
||||
static const uint64_t modifiers[] = {
|
||||
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
|
||||
DRM_FORMAT_MOD_BROADCOM_SAND128,
|
||||
@@ -1363,13 +1394,17 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
if (!vc4_plane)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(hvs_formats); i++)
|
||||
- formats[i] = hvs_formats[i].drm;
|
||||
+ for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
|
||||
+ if (!hvs_formats[i].hvs5_only || hvs5) {
|
||||
+ formats[num_formats] = hvs_formats[i].drm;
|
||||
+ num_formats++;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
plane = &vc4_plane->base;
|
||||
ret = drm_universal_plane_init(dev, plane, 0,
|
||||
&vc4_plane_funcs,
|
||||
- formats, ARRAY_SIZE(formats),
|
||||
+ formats, num_formats,
|
||||
modifiers, type, NULL);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
From 6f0f000ac5988d07865104be6585fdb4a075aa4b Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 17 Sep 2019 18:28:17 +0100
|
||||
Subject: [PATCH 444/634] drm/vc4: Add support for YUV color encodings and
|
||||
ranges
|
||||
|
||||
The BT601/BT709 color encoding and limited vs full
|
||||
range properties were not being exposed, defaulting
|
||||
always to BT601 limited range.
|
||||
|
||||
Expose the parameters and set the registers appropriately.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_regs.h | 3 ++
|
||||
2 files changed, 72 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 37a99ab9538c..9dd447ecd404 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -623,6 +623,53 @@ static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* The colorspace conversion matrices are held in 3 entries in the dlist.
|
||||
+ * Create an array of them, with entries for each full and limited mode, and
|
||||
+ * each supported colorspace.
|
||||
+ */
|
||||
+#define VC4_LIMITED_RANGE 0
|
||||
+#define VC4_FULL_RANGE 1
|
||||
+
|
||||
+static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
|
||||
+ {
|
||||
+ /* Limited range */
|
||||
+ {
|
||||
+ /* BT601 */
|
||||
+ SCALER_CSC0_ITR_R_601_5,
|
||||
+ SCALER_CSC1_ITR_R_601_5,
|
||||
+ SCALER_CSC2_ITR_R_601_5,
|
||||
+ }, {
|
||||
+ /* BT709 */
|
||||
+ SCALER_CSC0_ITR_R_709_3,
|
||||
+ SCALER_CSC1_ITR_R_709_3,
|
||||
+ SCALER_CSC2_ITR_R_709_3,
|
||||
+ }, {
|
||||
+ /* BT2020. Not supported yet - copy 601 */
|
||||
+ SCALER_CSC0_ITR_R_601_5,
|
||||
+ SCALER_CSC1_ITR_R_601_5,
|
||||
+ SCALER_CSC2_ITR_R_601_5,
|
||||
+ }
|
||||
+ }, {
|
||||
+ /* Full range */
|
||||
+ {
|
||||
+ /* JFIF */
|
||||
+ SCALER_CSC0_JPEG_JFIF,
|
||||
+ SCALER_CSC1_JPEG_JFIF,
|
||||
+ SCALER_CSC2_JPEG_JFIF,
|
||||
+ }, {
|
||||
+ /* BT709 */
|
||||
+ SCALER_CSC0_ITR_R_709_3_FR,
|
||||
+ SCALER_CSC1_ITR_R_709_3_FR,
|
||||
+ SCALER_CSC2_ITR_R_709_3_FR,
|
||||
+ }, {
|
||||
+ /* BT2020. Not supported yet - copy JFIF */
|
||||
+ SCALER_CSC0_JPEG_JFIF,
|
||||
+ SCALER_CSC1_JPEG_JFIF,
|
||||
+ SCALER_CSC2_JPEG_JFIF,
|
||||
+ }
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
/* Writes out a full display list for an active plane to the plane's
|
||||
* private dlist state.
|
||||
*/
|
||||
@@ -987,9 +1034,20 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
|
||||
/* Colorspace conversion words */
|
||||
if (vc4_state->is_yuv) {
|
||||
- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5);
|
||||
- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5);
|
||||
- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5);
|
||||
+ enum drm_color_encoding color_encoding = state->color_encoding;
|
||||
+ enum drm_color_range color_range = state->color_range;
|
||||
+ const u32 *ccm;
|
||||
+
|
||||
+ if (color_encoding >= DRM_COLOR_ENCODING_MAX)
|
||||
+ color_encoding = DRM_COLOR_YCBCR_BT601;
|
||||
+ if (color_range >= DRM_COLOR_RANGE_MAX)
|
||||
+ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
|
||||
+
|
||||
+ ccm = colorspace_coeffs[color_range][color_encoding];
|
||||
+
|
||||
+ vc4_dlist_write(vc4_state, ccm[0]);
|
||||
+ vc4_dlist_write(vc4_state, ccm[1]);
|
||||
+ vc4_dlist_write(vc4_state, ccm[2]);
|
||||
}
|
||||
|
||||
vc4_state->lbm_offset = 0;
|
||||
@@ -1418,6 +1476,14 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
DRM_MODE_REFLECT_X |
|
||||
DRM_MODE_REFLECT_Y);
|
||||
|
||||
+ drm_plane_create_color_properties(plane,
|
||||
+ BIT(DRM_COLOR_YCBCR_BT601) |
|
||||
+ BIT(DRM_COLOR_YCBCR_BT709),
|
||||
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
|
||||
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
|
||||
+ DRM_COLOR_YCBCR_BT709,
|
||||
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
|
||||
+
|
||||
return plane;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
index 489f921ef44d..78fd28599aeb 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
@@ -976,6 +976,7 @@ enum hvs_pixel_format {
|
||||
#define SCALER_CSC0_ITR_R_601_5 0x00f00000
|
||||
#define SCALER_CSC0_ITR_R_709_3 0x00f00000
|
||||
#define SCALER_CSC0_JPEG_JFIF 0x00000000
|
||||
+#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
|
||||
|
||||
/* S2.8 contribution of Cb to Green */
|
||||
#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
|
||||
@@ -992,6 +993,7 @@ enum hvs_pixel_format {
|
||||
#define SCALER_CSC1_ITR_R_601_5 0xe73304a8
|
||||
#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
|
||||
#define SCALER_CSC1_JPEG_JFIF 0xea34a400
|
||||
+#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
|
||||
|
||||
/* S2.8 contribution of Cb to Red */
|
||||
#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
|
||||
@@ -1005,6 +1007,7 @@ enum hvs_pixel_format {
|
||||
#define SCALER_CSC2_ITR_R_601_5 0x00066204
|
||||
#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
|
||||
#define SCALER_CSC2_JPEG_JFIF 0x000599c5
|
||||
+#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
|
||||
|
||||
#define SCALER_TPZ0_VERT_RECALC BIT(31)
|
||||
#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From 1480cb4fbbf4276df89c6a14d4d0fbfacbf982b2 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 19 May 2020 16:20:30 +0100
|
||||
Subject: [PATCH 445/634] drm/vc4: Add FKMS as an acceptable node for dma
|
||||
ranges.
|
||||
|
||||
Under FKMS, the firmware (via FKMS) also requires the VideoCore cache
|
||||
aliases for image planes, as defined by the dma-ranges under /soc.
|
||||
|
||||
Add rpi-firmware-kms to the list of acceptable nodes to look for
|
||||
to copy dma config from.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index 2a2e99873e40..63d0d17537c1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -216,6 +216,7 @@ static void vc4_match_add_drivers(struct device *dev,
|
||||
|
||||
const struct of_device_id vc4_dma_range_matches[] = {
|
||||
{ .compatible = "brcm,bcm2835-hvs" },
|
||||
+ { .compatible = "raspberrypi,rpi-firmware-kms" },
|
||||
{ .compatible = "brcm,bcm2835-v3d" },
|
||||
{ .compatible = "brcm,cygnus-v3d" },
|
||||
{ .compatible = "brcm,vc4-v3d" },
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
From a023c47b56995ef66decfe1012efb51bf1fad38c Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 31 Jul 2019 17:36:34 +0100
|
||||
Subject: [PATCH 446/634] drm/vc4: A present but empty dmas disables audio
|
||||
|
||||
Overlays are unable to remove properties in the base DTB, but they
|
||||
can overwrite them. Allow a present but empty 'dmas' property
|
||||
to also disable the HDMI audio interface.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/2489
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 053fbaf765ca..f5055657bf9b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1690,10 +1690,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
const __be32 *addr;
|
||||
int index;
|
||||
int ret;
|
||||
+ int len;
|
||||
|
||||
- if (!of_find_property(dev->of_node, "dmas", NULL)) {
|
||||
+ if (!of_find_property(dev->of_node, "dmas", &len) ||
|
||||
+ len == 0) {
|
||||
dev_warn(dev,
|
||||
- "'dmas' DT property is missing, no HDMI audio\n");
|
||||
+ "'dmas' DT property is missing or empty, no HDMI audio\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
From 4db4f5f3401c7197e997d210d0d1f3fc3495cd1f Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 6 Oct 2020 18:44:42 +0100
|
||||
Subject: [PATCH 447/634] drm/vc4: Add debugfs node that dumps the current
|
||||
display lists
|
||||
|
||||
This allows easy analysis of display lists when debugging.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 41 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 41 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 604933e20e6a..ab79d0a82a19 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -95,6 +95,45 @@ static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data)
|
||||
+{
|
||||
+ struct drm_info_node *node = m->private;
|
||||
+ struct drm_device *dev = node->minor->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
+ struct drm_printer p = drm_seq_file_printer(m);
|
||||
+ unsigned int next_entry_start = 0;
|
||||
+ unsigned int i, j;
|
||||
+ u32 dlist_word, dispstat;
|
||||
+
|
||||
+ for (i = 0; i < SCALER_CHANNELS_COUNT; i++) {
|
||||
+ dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(i)),
|
||||
+ SCALER_DISPSTATX_MODE);
|
||||
+ if (dispstat == SCALER_DISPSTATX_MODE_DISABLED ||
|
||||
+ dispstat == SCALER_DISPSTATX_MODE_EOF) {
|
||||
+ drm_printf(&p, "HVS chan %u disabled\n", i);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ drm_printf(&p, "HVS chan %u:\n", i);
|
||||
+
|
||||
+ for (j = HVS_READ(SCALER_DISPLISTX(i)); j < 256; j++) {
|
||||
+ dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j);
|
||||
+ drm_printf(&p, "dlist: %02d: 0x%08x\n", j,
|
||||
+ dlist_word);
|
||||
+ if (!next_entry_start ||
|
||||
+ next_entry_start == j) {
|
||||
+ if (dlist_word & SCALER_CTL0_END)
|
||||
+ break;
|
||||
+ next_entry_start = j +
|
||||
+ VC4_GET_FIELD(dlist_word,
|
||||
+ SCALER_CTL0_SIZE);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* The filter kernel is composed of dwords each containing 3 9-bit
|
||||
* signed integers packed next to each other.
|
||||
*/
|
||||
@@ -689,6 +728,8 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset);
|
||||
vc4_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun,
|
||||
NULL);
|
||||
+ vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist,
|
||||
+ NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
From 9b38bb5816dc9b004318743d8c10c6b96fdd71b2 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 21 Oct 2020 18:34:56 +0100
|
||||
Subject: [PATCH 448/634] drm/vc4: Add all the HDMI registers into the debugfs
|
||||
dumps
|
||||
|
||||
The vc5 HDMI registers hadn't been added into the debugfs
|
||||
register sets, therefore weren't dumped on request.
|
||||
Add them in.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 39 ++++++++++++++++++++++++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 8 +++++++
|
||||
2 files changed, 47 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index f5055657bf9b..6826103aef37 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -112,6 +112,12 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
|
||||
|
||||
drm_print_regset32(&p, &vc4_hdmi->hdmi_regset);
|
||||
drm_print_regset32(&p, &vc4_hdmi->hd_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->cec_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->csc_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->dvp_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->phy_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->ram_regset);
|
||||
+ drm_print_regset32(&p, &vc4_hdmi->rm_regset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2352,6 +2358,7 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
struct platform_device *pdev = vc4_hdmi->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
+ int ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
|
||||
if (!res)
|
||||
@@ -2448,6 +2455,38 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
return PTR_ERR(vc4_hdmi->reset);
|
||||
}
|
||||
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->cec_regset, VC5_CEC);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->csc_regset, VC5_CSC);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->dvp_regset, VC5_DVP);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->phy_regset, VC5_PHY);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->ram_regset, VC5_RAM);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->rm_regset, VC5_RM);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 36c0b082a43b..db53500a8435 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -215,6 +215,14 @@ struct vc4_hdmi {
|
||||
* the scrambler on? Protected by @mutex.
|
||||
*/
|
||||
bool scdc_enabled;
|
||||
+
|
||||
+ /* VC5 debugfs regset */
|
||||
+ struct debugfs_regset32 cec_regset;
|
||||
+ struct debugfs_regset32 csc_regset;
|
||||
+ struct debugfs_regset32 dvp_regset;
|
||||
+ struct debugfs_regset32 phy_regset;
|
||||
+ struct debugfs_regset32 ram_regset;
|
||||
+ struct debugfs_regset32 rm_regset;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
From 5d869c5244e794a6a606bea50fae5f4859a63b6b Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 26 Oct 2020 12:38:27 +0000
|
||||
Subject: [PATCH 449/634] drm/vc4: Add the 2711 HVS as a suitable DMA node
|
||||
|
||||
With vc4-drv node not being under /soc on Pi4, we need to
|
||||
adopt the correct DMA parameters from a suitable sub-component.
|
||||
Add "brcm,bcm2711-hvs" to that list of components.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index 63d0d17537c1..baa419bc5199 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -216,6 +216,7 @@ static void vc4_match_add_drivers(struct device *dev,
|
||||
|
||||
const struct of_device_id vc4_dma_range_matches[] = {
|
||||
{ .compatible = "brcm,bcm2835-hvs" },
|
||||
+ { .compatible = "brcm,bcm2711-hvs" },
|
||||
{ .compatible = "raspberrypi,rpi-firmware-kms" },
|
||||
{ .compatible = "brcm,bcm2835-v3d" },
|
||||
{ .compatible = "brcm,cygnus-v3d" },
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
From 0ac27b440a32561fff95203bbea64457c7ad4caa Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Tue, 10 Nov 2020 20:04:08 +0000
|
||||
Subject: [PATCH 451/634] vc4: Clear unused infoframe packet RAM registers
|
||||
|
||||
Using a hdmi analyser the bytes in packet ram
|
||||
registers beyond the length were visible in the
|
||||
infoframes and it flagged the checksum as invalid.
|
||||
|
||||
Zeroing unused words of packet RAM avoids this
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 876833d25558..0d8735f6fed5 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -436,9 +436,11 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
const struct vc4_hdmi_register *ram_packet_start =
|
||||
&vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START];
|
||||
u32 packet_reg = ram_packet_start->offset + VC4_HDMI_PACKET_STRIDE * packet_id;
|
||||
+ u32 packet_reg_next = ram_packet_start->offset +
|
||||
+ VC4_HDMI_PACKET_STRIDE * (packet_id + 1);
|
||||
void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
|
||||
ram_packet_start->reg);
|
||||
- uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
|
||||
+ uint8_t buffer[VC4_HDMI_PACKET_STRIDE] = {};
|
||||
unsigned long flags;
|
||||
ssize_t len, i;
|
||||
int ret;
|
||||
@@ -474,6 +476,13 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
packet_reg += 4;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * clear remainder of packet ram as it's included in the
|
||||
+ * infoframe and triggers a checksum error on hdmi analyser
|
||||
+ */
|
||||
+ for (; packet_reg < packet_reg_next; packet_reg += 4)
|
||||
+ writel(0, base + packet_reg);
|
||||
+
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
From d6fb1d005219176d51f4705db8cfc1696f18e7d0 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Fri, 12 Feb 2021 17:31:37 +0000
|
||||
Subject: [PATCH 452/634] drm/vc4: Change the default DPI format to being
|
||||
18bpp, not 24.
|
||||
|
||||
DPI hasn't really been used up until now, so the default has
|
||||
been meaningless.
|
||||
In theory we should be able to pass the desired format for the
|
||||
adjacent bridge chip through, but framework seems to be missing
|
||||
for that.
|
||||
|
||||
As the main device to use DPI is the VGA666 or Adafruit Kippah,
|
||||
both of which use RGB666, change the default to being RGB666 instead
|
||||
of RGB888.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dpi.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
|
||||
index afb446f49e9c..dde2c6014748 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
|
||||
@@ -188,8 +188,8 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
- /* Default to 24bit if no connector found. */
|
||||
- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT);
|
||||
+ /* Default to 18bit if no connector found. */
|
||||
+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT);
|
||||
}
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From e9c41d0d371a0a53bcaff0c36ba53c74146b12ef Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Sun, 24 Jan 2021 15:44:10 +0000
|
||||
Subject: [PATCH 453/634] vc4/drm: Avoid full hdmi audio fifo writes
|
||||
|
||||
We are getting occasional VC4_HD_MAI_CTL_ERRORF in
|
||||
HDMI_MAI_CTL which seem to correspond with audio dropouts.
|
||||
|
||||
Reduce the threshold where we deassert DREQ to avoid the fifo overfilling
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 0d8735f6fed5..57683afda185 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1610,10 +1610,10 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
|
||||
/* Set the MAI threshold */
|
||||
HDMI_WRITE(HDMI_MAI_THR,
|
||||
- VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
|
||||
- VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
|
||||
- VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
|
||||
- VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
|
||||
+ VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICHIGH) |
|
||||
+ VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICLOW) |
|
||||
+ VC4_SET_FIELD(0x06, VC4_HD_MAI_THR_DREQHIGH) |
|
||||
+ VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_DREQLOW));
|
||||
|
||||
HDMI_WRITE(HDMI_MAI_CONFIG,
|
||||
VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
From 1c048ce68d012aa65e942ac20b95e63dfc54eb84 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Mon, 22 Mar 2021 19:43:48 +0000
|
||||
Subject: [PATCH 454/634] vc4/drm: Fix source offsets with DRM_FORMAT_P030
|
||||
|
||||
Spec says: bits [31:4] of the given address should point to
|
||||
the 128-bit word containing the desired starting pixel,
|
||||
and bits[3:0] should be between 0 and 11, indicating which
|
||||
of the 12-pixels in that 128-bit word is the first pixel to be used
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 25 +++++++++++++++++--------
|
||||
1 file changed, 17 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 9dd447ecd404..1a1a54fc3005 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -819,9 +819,21 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
u32 tile_w, tile, x_off, pix_per_tile;
|
||||
|
||||
if (fb->format->format == DRM_FORMAT_P030) {
|
||||
+ /*
|
||||
+ * Spec says: bits [31:4] of the given address should point to
|
||||
+ * the 128-bit word containing the desired starting pixel,
|
||||
+ * and bits[3:0] should be between 0 and 11, indicating which
|
||||
+ * of the 12-pixels in that 128-bit word is the first pixel to be used
|
||||
+ */
|
||||
+ u32 remaining_pixels = vc4_state->src_x % 96;
|
||||
+ u32 aligned = remaining_pixels / 12;
|
||||
+ u32 last_bits = remaining_pixels % 12;
|
||||
+
|
||||
+ x_off = aligned * 16 + last_bits;
|
||||
hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
|
||||
tiling = SCALER_CTL0_TILING_128B;
|
||||
- tile_w = 96;
|
||||
+ tile_w = 128;
|
||||
+ pix_per_tile = 96;
|
||||
} else {
|
||||
hvs_format = HVS_PIXEL_FORMAT_H264;
|
||||
|
||||
@@ -841,17 +853,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
+ pix_per_tile = tile_w / fb->format->cpp[0];
|
||||
+ x_off = (vc4_state->src_x % pix_per_tile) /
|
||||
+ (i ? h_subsample : 1) * fb->format->cpp[i];
|
||||
}
|
||||
if (param > SCALER_TILE_HEIGHT_MASK) {
|
||||
DRM_DEBUG_KMS("SAND height too large (%d)\n",
|
||||
param);
|
||||
return -EINVAL;
|
||||
}
|
||||
-
|
||||
- pix_per_tile = tile_w / fb->format->cpp[0];
|
||||
tile = vc4_state->src_x / pix_per_tile;
|
||||
- x_off = vc4_state->src_x % pix_per_tile;
|
||||
-
|
||||
/* Adjust the base pointer to the first pixel to be scanned
|
||||
* out.
|
||||
*
|
||||
@@ -867,9 +878,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
vc4_state->offsets[i] += src_y /
|
||||
(i ? v_subsample : 1) *
|
||||
tile_w;
|
||||
- vc4_state->offsets[i] += x_off /
|
||||
- (i ? h_subsample : 1) *
|
||||
- fb->format->cpp[i];
|
||||
+ vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
|
||||
}
|
||||
|
||||
pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
From 568920ba54a355561533ef94915d340eefe34a4b Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Mon, 15 Mar 2021 13:28:06 +0000
|
||||
Subject: [PATCH 455/634] vc4/drm: vc4_plane: Remove subpixel positioning check
|
||||
|
||||
There is little harm in ignoring fractional coordinates
|
||||
(they just get truncated).
|
||||
|
||||
Without this:
|
||||
modetest -M vc4 -F tiles,gradient -s 32:1920x1080-60 -P89@74:1920x1080*.1.1@XR24
|
||||
|
||||
is rejected. We have the same issue in Kodi when trying to
|
||||
use zoom options on video.
|
||||
|
||||
Note: even if all coordinates are fully integer. e.g.
|
||||
src:[0,0,1920,1080] dest:[-10,-10,1940,1100]
|
||||
|
||||
it will still get rejected as drm_atomic_helper_check_plane_state
|
||||
uses drm_rect_clip_scaled which transforms this to fractional src coords
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 21 ++++++++-------------
|
||||
1 file changed, 8 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 1a1a54fc3005..4ffd0730a130 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -339,7 +339,6 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
|
||||
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
- u32 subpixel_src_mask = (1 << 16) - 1;
|
||||
int num_planes = fb->format->num_planes;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
u32 h_subsample = fb->format->hsub;
|
||||
@@ -361,18 +360,14 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
|
||||
for (i = 0; i < num_planes; i++)
|
||||
vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
|
||||
|
||||
- /* We don't support subpixel source positioning for scaling. */
|
||||
- if ((state->src.x1 & subpixel_src_mask) ||
|
||||
- (state->src.x2 & subpixel_src_mask) ||
|
||||
- (state->src.y1 & subpixel_src_mask) ||
|
||||
- (state->src.y2 & subpixel_src_mask)) {
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- vc4_state->src_x = state->src.x1 >> 16;
|
||||
- vc4_state->src_y = state->src.y1 >> 16;
|
||||
- vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16;
|
||||
- vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16;
|
||||
+ /* We don't support subpixel source positioning for scaling,
|
||||
+ * but fractional coordinates can be generated by clipping
|
||||
+ * so just round for now
|
||||
+ */
|
||||
+ vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1<<16);
|
||||
+ vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1<<16);
|
||||
+ vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1<<16) - vc4_state->src_x;
|
||||
+ vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1<<16) - vc4_state->src_y;
|
||||
|
||||
vc4_state->crtc_x = state->dst.x1;
|
||||
vc4_state->crtc_y = state->dst.y1;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
From 503f88ed418e0c73a7d880f73229d39232b2d7b7 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Mon, 12 Apr 2021 17:27:43 +0100
|
||||
Subject: [PATCH 456/634] vc4/kms: vc4_plane: Support 2020 colourspace for yuv
|
||||
planes
|
||||
|
||||
https://gist.github.com/popcornmix/6b3e23103c60170b02b148e0ba5d6ed7
|
||||
|
||||
is the script used to generate the 601, 709 and 2020 colourspaces.
|
||||
I've regenerated the existing ones using script so it is reproducible
|
||||
but there are lsb differences compared to values here (copied from spec)
|
||||
whose origin is now lost.
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 19 ++++++++++---------
|
||||
drivers/gpu/drm/vc4/vc4_regs.h | 18 ++++++++++++------
|
||||
2 files changed, 22 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 4ffd0730a130..c100eeddd5ad 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -639,10 +639,10 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
|
||||
SCALER_CSC1_ITR_R_709_3,
|
||||
SCALER_CSC2_ITR_R_709_3,
|
||||
}, {
|
||||
- /* BT2020. Not supported yet - copy 601 */
|
||||
- SCALER_CSC0_ITR_R_601_5,
|
||||
- SCALER_CSC1_ITR_R_601_5,
|
||||
- SCALER_CSC2_ITR_R_601_5,
|
||||
+ /* BT2020 */
|
||||
+ SCALER_CSC0_ITR_R_2020,
|
||||
+ SCALER_CSC1_ITR_R_2020,
|
||||
+ SCALER_CSC2_ITR_R_2020,
|
||||
}
|
||||
}, {
|
||||
/* Full range */
|
||||
@@ -657,10 +657,10 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
|
||||
SCALER_CSC1_ITR_R_709_3_FR,
|
||||
SCALER_CSC2_ITR_R_709_3_FR,
|
||||
}, {
|
||||
- /* BT2020. Not supported yet - copy JFIF */
|
||||
- SCALER_CSC0_JPEG_JFIF,
|
||||
- SCALER_CSC1_JPEG_JFIF,
|
||||
- SCALER_CSC2_JPEG_JFIF,
|
||||
+ /* BT2020 */
|
||||
+ SCALER_CSC0_ITR_R_2020_FR,
|
||||
+ SCALER_CSC1_ITR_R_2020_FR,
|
||||
+ SCALER_CSC2_ITR_R_2020_FR,
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1482,7 +1482,8 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
|
||||
|
||||
drm_plane_create_color_properties(plane,
|
||||
BIT(DRM_COLOR_YCBCR_BT601) |
|
||||
- BIT(DRM_COLOR_YCBCR_BT709),
|
||||
+ BIT(DRM_COLOR_YCBCR_BT709) |
|
||||
+ BIT(DRM_COLOR_YCBCR_BT2020),
|
||||
BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
|
||||
BIT(DRM_COLOR_YCBCR_FULL_RANGE),
|
||||
DRM_COLOR_YCBCR_BT709,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
index 78fd28599aeb..7538b84a6dca 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
@@ -975,8 +975,10 @@ enum hvs_pixel_format {
|
||||
#define SCALER_CSC0_COEF_CR_OFS_SHIFT 0
|
||||
#define SCALER_CSC0_ITR_R_601_5 0x00f00000
|
||||
#define SCALER_CSC0_ITR_R_709_3 0x00f00000
|
||||
+#define SCALER_CSC0_ITR_R_2020 0x00f00000
|
||||
#define SCALER_CSC0_JPEG_JFIF 0x00000000
|
||||
#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000
|
||||
+#define SCALER_CSC0_ITR_R_2020_FR 0x00000000
|
||||
|
||||
/* S2.8 contribution of Cb to Green */
|
||||
#define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22)
|
||||
@@ -991,9 +993,11 @@ enum hvs_pixel_format {
|
||||
#define SCALER_CSC1_COEF_CR_BLU_MASK VC4_MASK(1, 0)
|
||||
#define SCALER_CSC1_COEF_CR_BLU_SHIFT 0
|
||||
#define SCALER_CSC1_ITR_R_601_5 0xe73304a8
|
||||
-#define SCALER_CSC1_ITR_R_709_3 0xf2b784a8
|
||||
-#define SCALER_CSC1_JPEG_JFIF 0xea34a400
|
||||
-#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400
|
||||
+#define SCALER_CSC1_ITR_R_709_3 0xf27784a8
|
||||
+#define SCALER_CSC1_ITR_R_2020 0xf43594a8
|
||||
+#define SCALER_CSC1_JPEG_JFIF 0xea349400
|
||||
+#define SCALER_CSC1_ITR_R_709_3_FR 0xf4388400
|
||||
+#define SCALER_CSC1_ITR_R_2020_FR 0xf5b6d400
|
||||
|
||||
/* S2.8 contribution of Cb to Red */
|
||||
#define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20)
|
||||
@@ -1004,10 +1008,12 @@ enum hvs_pixel_format {
|
||||
/* S2.8 contribution of Cb to Blue */
|
||||
#define SCALER_CSC2_COEF_CB_BLU_MASK VC4_MASK(19, 10)
|
||||
#define SCALER_CSC2_COEF_CB_BLU_SHIFT 10
|
||||
-#define SCALER_CSC2_ITR_R_601_5 0x00066204
|
||||
-#define SCALER_CSC2_ITR_R_709_3 0x00072a1c
|
||||
-#define SCALER_CSC2_JPEG_JFIF 0x000599c5
|
||||
+#define SCALER_CSC2_ITR_R_601_5 0x00066604
|
||||
+#define SCALER_CSC2_ITR_R_709_3 0x00072e1d
|
||||
+#define SCALER_CSC2_ITR_R_2020 0x0006b624
|
||||
+#define SCALER_CSC2_JPEG_JFIF 0x00059dc6
|
||||
#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb
|
||||
+#define SCALER_CSC2_ITR_R_2020_FR 0x0005e5e2
|
||||
|
||||
#define SCALER_TPZ0_VERT_RECALC BIT(31)
|
||||
#define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
From 4a8efdb006a53021458e67535ac7023d254338f7 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Tue, 13 Apr 2021 14:10:03 +0100
|
||||
Subject: [PATCH 457/634] drm/vc4: hdmi: Convert to the new clock request API
|
||||
|
||||
The new clock request API allows us to increase the rate of the
|
||||
core clock as required during mode set while decreasing it when
|
||||
we're done, resulting in a better power-efficiency.
|
||||
|
||||
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 79d4d9dd1394..f9dce01c052f 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -345,6 +345,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
struct vc4_hvs_state *new_hvs_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct vc4_hvs_state *old_hvs_state;
|
||||
+ struct clk_request *core_req;
|
||||
int i;
|
||||
|
||||
old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
@@ -370,7 +371,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
500000000,
|
||||
new_hvs_state->core_clock_rate);
|
||||
|
||||
- clk_set_min_rate(hvs->core_clk, core_rate);
|
||||
+ core_req = clk_request_start(hvs->core_clk, core_rate);
|
||||
}
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
@@ -415,7 +416,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_dbg(dev, "Running the core clock at %lu Hz\n",
|
||||
new_hvs_state->core_clock_rate);
|
||||
|
||||
- clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate);
|
||||
+ clk_request_done(core_req);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From 5ccb69c8e022a72ce37f7ba78fe5d676571c55d8 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Thu, 11 Feb 2021 18:37:04 +0000
|
||||
Subject: [PATCH 458/634] drm/vc4: Correct pixel order for DSI0
|
||||
|
||||
For slightly unknown reasons, dsi0 takes a different pixel format
|
||||
to dsi1, and that has to be set in the pixel valve.
|
||||
|
||||
Amend the setup accordingly.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 287dbc89ad64..5653476e8dcb 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -317,7 +317,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1;
|
||||
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
|
||||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
|
||||
- u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
|
||||
+ bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
|
||||
+ u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
|
||||
u8 ppc = pv_data->pixels_per_clock;
|
||||
bool debug_dump_regs = false;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
From 0e0e02fcc1b341136276a4ffc45bfdb6c67c6898 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 8 Feb 2021 11:22:01 +0000
|
||||
Subject: [PATCH 459/634] drm/vc4: Register dsi0 as the correct vc4 encoder
|
||||
type
|
||||
|
||||
vc4_dsi was registering both dsi0 and dsi1 as VC4_ENCODER_TYPE_DSI1
|
||||
which seemed to work OK for a single DSI display, but fails
|
||||
if there are two DSI displays connected.
|
||||
|
||||
Update to register the correct type.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
index a185027911ce..dfc68b2efd96 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
@@ -1514,7 +1514,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&dsi->bridge_chain);
|
||||
- vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1;
|
||||
+ vc4_dsi_encoder->base.type = dsi->variant->port ?
|
||||
+ VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0;
|
||||
vc4_dsi_encoder->dsi = dsi;
|
||||
dsi->encoder = &vc4_dsi_encoder->base.base;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
From d9fc3b49dbca8f27ac5ca34a956a676109643d6a Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 10 Feb 2021 18:46:22 +0000
|
||||
Subject: [PATCH 460/634] drm/vc4: Fix dsi0 interrupt support.
|
||||
|
||||
DSI0 seemingly had very little or no testing as a load of
|
||||
the register mappings were incorrect/missing, so host
|
||||
transfers always timed out due to enabling/checking incorrect
|
||||
bits in the interrupt enable and status registers.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dsi.c | 111 ++++++++++++++++++++++++++--------
|
||||
1 file changed, 85 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
index dfc68b2efd96..b6bedc8da63f 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
@@ -181,8 +181,50 @@
|
||||
|
||||
#define DSI0_TXPKT_PIX_FIFO 0x20 /* AKA PIX_FIFO */
|
||||
|
||||
-#define DSI0_INT_STAT 0x24
|
||||
-#define DSI0_INT_EN 0x28
|
||||
+#define DSI0_INT_STAT 0x24
|
||||
+#define DSI0_INT_EN 0x28
|
||||
+# define DSI0_INT_FIFO_ERR BIT(25)
|
||||
+# define DSI0_INT_CMDC_DONE_MASK VC4_MASK(24, 23)
|
||||
+# define DSI0_INT_CMDC_DONE_SHIFT 23
|
||||
+# define DSI0_INT_CMDC_DONE_NO_REPEAT 1
|
||||
+# define DSI0_INT_CMDC_DONE_REPEAT 3
|
||||
+# define DSI0_INT_PHY_DIR_RTF BIT(22)
|
||||
+# define DSI0_INT_PHY_D1_ULPS BIT(21)
|
||||
+# define DSI0_INT_PHY_D1_STOP BIT(20)
|
||||
+# define DSI0_INT_PHY_RXLPDT BIT(19)
|
||||
+# define DSI0_INT_PHY_RXTRIG BIT(18)
|
||||
+# define DSI0_INT_PHY_D0_ULPS BIT(17)
|
||||
+# define DSI0_INT_PHY_D0_LPDT BIT(16)
|
||||
+# define DSI0_INT_PHY_D0_FTR BIT(15)
|
||||
+# define DSI0_INT_PHY_D0_STOP BIT(14)
|
||||
+/* Signaled when the clock lane enters the given state. */
|
||||
+# define DSI0_INT_PHY_CLK_ULPS BIT(13)
|
||||
+# define DSI0_INT_PHY_CLK_HS BIT(12)
|
||||
+# define DSI0_INT_PHY_CLK_FTR BIT(11)
|
||||
+/* Signaled on timeouts */
|
||||
+# define DSI0_INT_PR_TO BIT(10)
|
||||
+# define DSI0_INT_TA_TO BIT(9)
|
||||
+# define DSI0_INT_LPRX_TO BIT(8)
|
||||
+# define DSI0_INT_HSTX_TO BIT(7)
|
||||
+/* Contention on a line when trying to drive the line low */
|
||||
+# define DSI0_INT_ERR_CONT_LP1 BIT(6)
|
||||
+# define DSI0_INT_ERR_CONT_LP0 BIT(5)
|
||||
+/* Control error: incorrect line state sequence on data lane 0. */
|
||||
+# define DSI0_INT_ERR_CONTROL BIT(4)
|
||||
+# define DSI0_INT_ERR_SYNC_ESC BIT(3)
|
||||
+# define DSI0_INT_RX2_PKT BIT(2)
|
||||
+# define DSI0_INT_RX1_PKT BIT(1)
|
||||
+# define DSI0_INT_CMD_PKT BIT(0)
|
||||
+
|
||||
+#define DSI0_INTERRUPTS_ALWAYS_ENABLED (DSI0_INT_ERR_SYNC_ESC | \
|
||||
+ DSI0_INT_ERR_CONTROL | \
|
||||
+ DSI0_INT_ERR_CONT_LP0 | \
|
||||
+ DSI0_INT_ERR_CONT_LP1 | \
|
||||
+ DSI0_INT_HSTX_TO | \
|
||||
+ DSI0_INT_LPRX_TO | \
|
||||
+ DSI0_INT_TA_TO | \
|
||||
+ DSI0_INT_PR_TO)
|
||||
+
|
||||
# define DSI1_INT_PHY_D3_ULPS BIT(30)
|
||||
# define DSI1_INT_PHY_D3_STOP BIT(29)
|
||||
# define DSI1_INT_PHY_D2_ULPS BIT(28)
|
||||
@@ -894,6 +936,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
|
||||
|
||||
DSI_PORT_WRITE(PHY_AFEC0, afec0);
|
||||
|
||||
+ /* AFEC reset hold time */
|
||||
+ mdelay(1);
|
||||
+
|
||||
DSI_PORT_WRITE(PHY_AFEC1,
|
||||
VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE1) |
|
||||
VC4_SET_FIELD(6, DSI0_PHY_AFEC1_IDR_DLANE0) |
|
||||
@@ -1060,12 +1105,9 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
|
||||
DSI_PORT_WRITE(CTRL, DSI_PORT_READ(CTRL) | DSI1_CTRL_EN);
|
||||
|
||||
/* Bring AFE out of reset. */
|
||||
- if (dsi->variant->port == 0) {
|
||||
- } else {
|
||||
- DSI_PORT_WRITE(PHY_AFEC0,
|
||||
- DSI_PORT_READ(PHY_AFEC0) &
|
||||
- ~DSI1_PHY_AFEC0_RESET);
|
||||
- }
|
||||
+ DSI_PORT_WRITE(PHY_AFEC0,
|
||||
+ DSI_PORT_READ(PHY_AFEC0) &
|
||||
+ ~DSI_PORT_BIT(PHY_AFEC0_RESET));
|
||||
|
||||
vc4_dsi_ulps(dsi, false);
|
||||
|
||||
@@ -1184,13 +1226,28 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||
/* Enable the appropriate interrupt for the transfer completion. */
|
||||
dsi->xfer_result = 0;
|
||||
reinit_completion(&dsi->xfer_completion);
|
||||
- DSI_PORT_WRITE(INT_STAT, DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
|
||||
- if (msg->rx_len) {
|
||||
- DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
|
||||
- DSI1_INT_PHY_DIR_RTF));
|
||||
+ if (dsi->variant->port == 0) {
|
||||
+ DSI_PORT_WRITE(INT_STAT,
|
||||
+ DSI0_INT_CMDC_DONE_MASK | DSI1_INT_PHY_DIR_RTF);
|
||||
+ if (msg->rx_len) {
|
||||
+ DSI_PORT_WRITE(INT_EN, (DSI0_INTERRUPTS_ALWAYS_ENABLED |
|
||||
+ DSI0_INT_PHY_DIR_RTF));
|
||||
+ } else {
|
||||
+ DSI_PORT_WRITE(INT_EN,
|
||||
+ (DSI0_INTERRUPTS_ALWAYS_ENABLED |
|
||||
+ VC4_SET_FIELD(DSI0_INT_CMDC_DONE_NO_REPEAT,
|
||||
+ DSI0_INT_CMDC_DONE)));
|
||||
+ }
|
||||
} else {
|
||||
- DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
|
||||
- DSI1_INT_TXPKT1_DONE));
|
||||
+ DSI_PORT_WRITE(INT_STAT,
|
||||
+ DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF);
|
||||
+ if (msg->rx_len) {
|
||||
+ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
|
||||
+ DSI1_INT_PHY_DIR_RTF));
|
||||
+ } else {
|
||||
+ DSI_PORT_WRITE(INT_EN, (DSI1_INTERRUPTS_ALWAYS_ENABLED |
|
||||
+ DSI1_INT_TXPKT1_DONE));
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Send the packet. */
|
||||
@@ -1207,7 +1264,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||
ret = dsi->xfer_result;
|
||||
}
|
||||
|
||||
- DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
|
||||
+ DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
|
||||
|
||||
if (ret)
|
||||
goto reset_fifo_and_return;
|
||||
@@ -1253,7 +1310,7 @@ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||
DSI_PORT_BIT(CTRL_RESET_FIFOS));
|
||||
|
||||
DSI_PORT_WRITE(TXPKT1C, 0);
|
||||
- DSI_PORT_WRITE(INT_EN, DSI1_INTERRUPTS_ALWAYS_ENABLED);
|
||||
+ DSI_PORT_WRITE(INT_EN, DSI_PORT_BIT(INTERRUPTS_ALWAYS_ENABLED));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1394,26 +1451,28 @@ static irqreturn_t vc4_dsi_irq_handler(int irq, void *data)
|
||||
DSI_PORT_WRITE(INT_STAT, stat);
|
||||
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_ERR_SYNC_ESC, "LPDT sync");
|
||||
+ DSI_PORT_BIT(INT_ERR_SYNC_ESC), "LPDT sync");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_ERR_CONTROL, "data lane 0 sequence");
|
||||
+ DSI_PORT_BIT(INT_ERR_CONTROL), "data lane 0 sequence");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_ERR_CONT_LP0, "LP0 contention");
|
||||
+ DSI_PORT_BIT(INT_ERR_CONT_LP0), "LP0 contention");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_ERR_CONT_LP1, "LP1 contention");
|
||||
+ DSI_PORT_BIT(INT_ERR_CONT_LP1), "LP1 contention");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_HSTX_TO, "HSTX timeout");
|
||||
+ DSI_PORT_BIT(INT_HSTX_TO), "HSTX timeout");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_LPRX_TO, "LPRX timeout");
|
||||
+ DSI_PORT_BIT(INT_LPRX_TO), "LPRX timeout");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_TA_TO, "turnaround timeout");
|
||||
+ DSI_PORT_BIT(INT_TA_TO), "turnaround timeout");
|
||||
dsi_handle_error(dsi, &ret, stat,
|
||||
- DSI1_INT_PR_TO, "peripheral reset timeout");
|
||||
+ DSI_PORT_BIT(INT_PR_TO), "peripheral reset timeout");
|
||||
|
||||
- if (stat & (DSI1_INT_TXPKT1_DONE | DSI1_INT_PHY_DIR_RTF)) {
|
||||
+ if (stat & ((dsi->variant->port ? DSI1_INT_TXPKT1_DONE :
|
||||
+ DSI0_INT_CMDC_DONE_MASK) |
|
||||
+ DSI_PORT_BIT(INT_PHY_DIR_RTF))) {
|
||||
complete(&dsi->xfer_completion);
|
||||
ret = IRQ_HANDLED;
|
||||
- } else if (stat & DSI1_INT_HSTX_TO) {
|
||||
+ } else if (stat & DSI_PORT_BIT(INT_HSTX_TO)) {
|
||||
complete(&dsi->xfer_completion);
|
||||
dsi->xfer_result = -ETIMEDOUT;
|
||||
ret = IRQ_HANDLED;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
From f90ecd85d1453fd60ff0156aec2e3b0fc22ea266 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Thu, 15 Apr 2021 16:18:16 +0100
|
||||
Subject: [PATCH 461/634] drm/vc4: Add correct stop condition to
|
||||
vc4_dsi_encoder_disable iteration
|
||||
|
||||
vc4_dsi_encoder_disable is partially an open coded version of
|
||||
drm_bridge_chain_disable, but it missed a termination condition
|
||||
in the loop for ->disable which meant that no post_disable
|
||||
calls were made.
|
||||
|
||||
Add in the termination clause.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dsi.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
index b6bedc8da63f..e433071bf797 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
@@ -803,6 +803,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
|
||||
list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
|
||||
if (iter->funcs->disable)
|
||||
iter->funcs->disable(iter);
|
||||
+
|
||||
+ if (iter == dsi->bridge)
|
||||
+ break;
|
||||
}
|
||||
|
||||
vc4_dsi_ulps(dsi, true);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
From 53bd65d8dc68d40a89026d5509013069cbc36a31 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 28 Apr 2021 16:14:21 +0100
|
||||
Subject: [PATCH 463/634] drm/vc4: Allow DBLCLK modes even if horz timing is
|
||||
odd.
|
||||
|
||||
The 2711 pixel valve can't produce odd horizontal timings, and
|
||||
checks were added to vc4_hdmi_encoder_atomic_check and
|
||||
vc4_hdmi_encoder_mode_valid to filter out/block selection of
|
||||
such modes.
|
||||
|
||||
Modes with DRM_MODE_FLAG_DBLCLK double all the horizontal timing
|
||||
values before programming them into the PV. The PV values,
|
||||
therefore, can not be odd, and so the modes can be supported.
|
||||
|
||||
Amend the filtering appropriately.
|
||||
|
||||
See https://github.com/raspberrypi/linux/issues/4307
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 57683afda185..2c83252819e9 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1267,6 +1267,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
unsigned long long tmds_rate;
|
||||
|
||||
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
|
||||
+ !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
|
||||
((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
|
||||
(mode->hsync_end % 2) || (mode->htotal % 2)))
|
||||
return -EINVAL;
|
||||
@@ -1314,6 +1315,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
|
||||
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
|
||||
+ !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
|
||||
((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
|
||||
(mode->hsync_end % 2) || (mode->htotal % 2)))
|
||||
return MODE_H_ILLEGAL;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
From 82eae7910c0537100d4b5a6bb697bb3e9996cd2a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 26 May 2021 16:13:02 +0200
|
||||
Subject: [PATCH 465/634] drm/vc4: Increase the core clock based on HVS load
|
||||
|
||||
Depending on a given HVS output (HVS to PixelValves) and input (planes
|
||||
attached to a channel) load, the HVS needs for the core clock to be
|
||||
raised above its boot time default.
|
||||
|
||||
Failing to do so will result in a vblank timeout and a stalled display
|
||||
pipeline.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 1 +
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 14 ++++++++++++++
|
||||
2 files changed, 15 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 4329e09d357c..3921959b4a5e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -321,6 +321,7 @@ struct vc4_hvs {
|
||||
u32 __iomem *dlist;
|
||||
|
||||
struct clk *core_clk;
|
||||
+ struct clk_request *core_req;
|
||||
|
||||
/* Memory manager for CRTCs to allocate space in the display
|
||||
* list. Units are dwords.
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index f9dce01c052f..a750b1e6c733 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -372,6 +372,12 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
new_hvs_state->core_clock_rate);
|
||||
|
||||
core_req = clk_request_start(hvs->core_clk, core_rate);
|
||||
+
|
||||
+ /*
|
||||
+ * And remove the previous one based on the HVS
|
||||
+ * requirements if any.
|
||||
+ */
|
||||
+ clk_request_done(hvs->core_req);
|
||||
}
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
@@ -416,6 +422,14 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_dbg(dev, "Running the core clock at %lu Hz\n",
|
||||
new_hvs_state->core_clock_rate);
|
||||
|
||||
+ /*
|
||||
+ * Request a clock rate based on the current HVS
|
||||
+ * requirements.
|
||||
+ */
|
||||
+ hvs->core_req = clk_request_start(hvs->core_clk,
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
+
|
||||
+ /* And drop the temporary request */
|
||||
clk_request_done(core_req);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
From 74c8e5b794c36fa5dc152a42765499326853484c Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 27 Oct 2021 14:38:50 +0100
|
||||
Subject: [PATCH 466/634] drm/vc4: hdmi: Simplify the connector state retrieval
|
||||
|
||||
When we have the entire DRM state, retrieving the connector state only
|
||||
requires the drm_connector pointer. Fortunately for us, we have
|
||||
allocated it as a part of the vc4_hdmi structure, so we can retrieve get
|
||||
a pointer by simply accessing our field in that structure.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 21 +++------------------
|
||||
1 file changed, 3 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 2c83252819e9..efffe21d2e73 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1002,30 +1002,15 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
||||
"VC4_HDMI_FIFO_CTL_RECENTER_DONE");
|
||||
}
|
||||
|
||||
-static struct drm_connector_state *
|
||||
-vc4_hdmi_encoder_get_connector_state(struct drm_encoder *encoder,
|
||||
- struct drm_atomic_state *state)
|
||||
-{
|
||||
- struct drm_connector_state *conn_state;
|
||||
- struct drm_connector *connector;
|
||||
- unsigned int i;
|
||||
-
|
||||
- for_each_new_connector_in_state(state, connector, conn_state, i) {
|
||||
- if (conn_state->best_encoder == encoder)
|
||||
- return conn_state;
|
||||
- }
|
||||
-
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
struct drm_connector_state *conn_state =
|
||||
- vc4_hdmi_encoder_get_connector_state(encoder, state);
|
||||
+ drm_atomic_get_new_connector_state(state, connector);
|
||||
struct vc4_hdmi_connector_state *vc4_conn_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(conn_state);
|
||||
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
unsigned long bvb_rate, hsm_rate;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
From f64d1bbe8a773f87ae1f4f68948b6935b64c8d75 Mon Sep 17 00:00:00 2001
|
||||
From: kFYatek <4499762+kFYatek@users.noreply.github.com>
|
||||
Date: Wed, 23 Jun 2021 01:11:26 +0200
|
||||
Subject: [PATCH 467/634] drm/vc4: Fix timings for interlaced modes
|
||||
|
||||
Increase the number of post-sync blanking lines on odd fields instead of
|
||||
decreasing it on even fields. This makes the total number of lines
|
||||
properly match the modelines.
|
||||
|
||||
Additionally fix the value of PV_VCONTROL_ODD_DELAY, which did not take
|
||||
pixels_per_clock into account, causing some displays to invert the
|
||||
fields when driven by bcm2711.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 7 ++++---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++------
|
||||
2 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 5653476e8dcb..e21119f32552 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -344,7 +344,8 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
PV_HORZB_HACTIVE));
|
||||
|
||||
CRTC_WRITE(PV_VERTA,
|
||||
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
|
||||
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
|
||||
+ interlace,
|
||||
PV_VERTA_VBP) |
|
||||
VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
|
||||
PV_VERTA_VSYNC));
|
||||
@@ -356,7 +357,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
if (interlace) {
|
||||
CRTC_WRITE(PV_VERTA_EVEN,
|
||||
VC4_SET_FIELD(mode->crtc_vtotal -
|
||||
- mode->crtc_vsync_end - 1,
|
||||
+ mode->crtc_vsync_end,
|
||||
PV_VERTA_VBP) |
|
||||
VC4_SET_FIELD(mode->crtc_vsync_end -
|
||||
mode->crtc_vsync_start,
|
||||
@@ -376,7 +377,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0) |
|
||||
PV_VCONTROL_INTERLACE |
|
||||
- VC4_SET_FIELD(mode->htotal * pixel_rep / 2,
|
||||
+ VC4_SET_FIELD(mode->htotal * pixel_rep / (2 * ppc),
|
||||
PV_VCONTROL_ODD_DELAY));
|
||||
CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||||
} else {
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index efffe21d2e73..502d5bea5f61 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -840,12 +840,12 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
VC4_HDMI_VERTA_VFP) |
|
||||
VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
|
||||
u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
|
||||
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
|
||||
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
|
||||
+ interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
|
||||
VC4_SET_FIELD(mode->crtc_vtotal -
|
||||
- mode->crtc_vsync_end -
|
||||
- interlaced,
|
||||
+ mode->crtc_vsync_end,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
unsigned long flags;
|
||||
|
||||
@@ -891,12 +891,12 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
VC5_HDMI_VERTA_VFP) |
|
||||
VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
|
||||
u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
|
||||
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
|
||||
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
|
||||
+ interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
|
||||
VC4_SET_FIELD(mode->crtc_vtotal -
|
||||
- mode->crtc_vsync_end -
|
||||
- interlaced,
|
||||
+ mode->crtc_vsync_end,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
unsigned long flags;
|
||||
unsigned char gcp;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From d7c52ab30d28898ea6df7cd0637c3e7ebc053b57 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 12 Jul 2021 12:27:59 +0100
|
||||
Subject: [PATCH 469/634] drm/vc4: Fix margin calculations for the right/bottom
|
||||
edges
|
||||
|
||||
The calculations clipped the right/bottom edge of the clipped
|
||||
range based on the left/top margins.
|
||||
|
||||
Fixes: 666e73587f90 ("drm/vc4: Take margin setup into account when updating planes")
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index c100eeddd5ad..4d97d1747eef 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -310,16 +310,16 @@ static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
|
||||
adjhdisplay,
|
||||
crtc_state->mode.hdisplay);
|
||||
vc4_pstate->crtc_x += left;
|
||||
- if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left)
|
||||
- vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left;
|
||||
+ if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
|
||||
+ vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
|
||||
|
||||
adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
|
||||
vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
|
||||
adjvdisplay,
|
||||
crtc_state->mode.vdisplay);
|
||||
vc4_pstate->crtc_y += top;
|
||||
- if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top)
|
||||
- vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top;
|
||||
+ if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
|
||||
+ vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
|
||||
|
||||
vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
|
||||
adjhdisplay,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
From 4e4edf458c458663de9989d4c101842fbc05c9ae Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:07:30 +0200
|
||||
Subject: [PATCH 470/634] drm/vc4: Fix timings for VEC modes
|
||||
|
||||
This commit fixes vertical timings of the VEC (composite output) modes
|
||||
to accurately represent the 525-line ("NTSC") and 625-line ("PAL") ITU-R
|
||||
standards.
|
||||
|
||||
Previous timings were actually defined as 502 and 601 lines, resulting
|
||||
in non-standard 62.69 Hz and 52 Hz signals being generated,
|
||||
respectively.
|
||||
|
||||
Changes to vc4_crtc.c have also been made, to make the PixelValve
|
||||
vertical timings accurately correspond to the DRM modeline in interlaced
|
||||
modes. The resulting VERTA/VERTB register values have been verified
|
||||
against the reference values set by the Raspberry Pi firmware.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 70 +++++++++++++++++++++-------------
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 4 +-
|
||||
2 files changed, 45 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e21119f32552..23be68a8ecec 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -318,8 +318,14 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
|
||||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
|
||||
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
|
||||
+ bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
|
||||
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
|
||||
u8 ppc = pv_data->pixels_per_clock;
|
||||
+
|
||||
+ u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
|
||||
+ u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
|
||||
+ u16 vert_fp = mode->crtc_vsync_start - mode->crtc_vdisplay;
|
||||
+
|
||||
bool debug_dump_regs = false;
|
||||
|
||||
if (debug_dump_regs) {
|
||||
@@ -343,49 +349,59 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
|
||||
PV_HORZB_HACTIVE));
|
||||
|
||||
- CRTC_WRITE(PV_VERTA,
|
||||
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
|
||||
- interlace,
|
||||
- PV_VERTA_VBP) |
|
||||
- VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
|
||||
- PV_VERTA_VSYNC));
|
||||
- CRTC_WRITE(PV_VERTB,
|
||||
- VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
|
||||
- PV_VERTB_VFP) |
|
||||
- VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
|
||||
-
|
||||
if (interlace) {
|
||||
+ bool odd_field_first = false;
|
||||
+ u32 field_delay = mode->htotal * pixel_rep / (2 * ppc);
|
||||
+ u16 vert_bp_even = vert_bp;
|
||||
+ u16 vert_fp_even = vert_fp;
|
||||
+
|
||||
+ if (is_vec) {
|
||||
+ /* VEC (composite output) */
|
||||
+ ++field_delay;
|
||||
+ if (mode->htotal == 858) {
|
||||
+ /* 525-line mode (NTSC or PAL-M) */
|
||||
+ odd_field_first = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (odd_field_first)
|
||||
+ ++vert_fp_even;
|
||||
+ else
|
||||
+ ++vert_bp;
|
||||
+
|
||||
CRTC_WRITE(PV_VERTA_EVEN,
|
||||
- VC4_SET_FIELD(mode->crtc_vtotal -
|
||||
- mode->crtc_vsync_end,
|
||||
- PV_VERTA_VBP) |
|
||||
- VC4_SET_FIELD(mode->crtc_vsync_end -
|
||||
- mode->crtc_vsync_start,
|
||||
- PV_VERTA_VSYNC));
|
||||
+ VC4_SET_FIELD(vert_bp_even, PV_VERTA_VBP) |
|
||||
+ VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
|
||||
CRTC_WRITE(PV_VERTB_EVEN,
|
||||
- VC4_SET_FIELD(mode->crtc_vsync_start -
|
||||
- mode->crtc_vdisplay,
|
||||
- PV_VERTB_VFP) |
|
||||
+ VC4_SET_FIELD(vert_fp_even, PV_VERTB_VFP) |
|
||||
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
|
||||
|
||||
- /* We set up first field even mode for HDMI. VEC's
|
||||
- * NTSC mode would want first field odd instead, once
|
||||
- * we support it (to do so, set ODD_FIRST and put the
|
||||
- * delay in VSYNCD_EVEN instead).
|
||||
+ /* We set up first field even mode for HDMI and VEC's PAL.
|
||||
+ * For NTSC, we need first field odd.
|
||||
*/
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0) |
|
||||
PV_VCONTROL_INTERLACE |
|
||||
- VC4_SET_FIELD(mode->htotal * pixel_rep / (2 * ppc),
|
||||
- PV_VCONTROL_ODD_DELAY));
|
||||
- CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||||
+ (odd_field_first
|
||||
+ ? PV_VCONTROL_ODD_FIRST
|
||||
+ : VC4_SET_FIELD(field_delay,
|
||||
+ PV_VCONTROL_ODD_DELAY)));
|
||||
+ CRTC_WRITE(PV_VSYNCD_EVEN,
|
||||
+ (odd_field_first ? field_delay : 0));
|
||||
} else {
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0));
|
||||
}
|
||||
|
||||
+ CRTC_WRITE(PV_VERTA,
|
||||
+ VC4_SET_FIELD(vert_bp, PV_VERTA_VBP) |
|
||||
+ VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
|
||||
+ CRTC_WRITE(PV_VERTB,
|
||||
+ VC4_SET_FIELD(vert_fp, PV_VERTB_VFP) |
|
||||
+ VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
|
||||
+
|
||||
if (is_dsi)
|
||||
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index 11fc3d6f66b1..4e2250b8fa23 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -256,7 +256,7 @@ static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
|
||||
static const struct drm_display_mode ntsc_mode = {
|
||||
DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
- 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
|
||||
+ 480, 480 + 7, 480 + 7 + 6, 525, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
@@ -278,7 +278,7 @@ static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
|
||||
static const struct drm_display_mode pal_mode = {
|
||||
DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
- 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
|
||||
+ 576, 576 + 4, 576 + 4 + 6, 625, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
From 0050f48b39fe4864078ebd841f4264fa06424b88 Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:07:49 +0200
|
||||
Subject: [PATCH 471/634] drm/vc4: Refactor VEC TV mode setting
|
||||
|
||||
Change the mode_set function pointer logic to declarative config0,
|
||||
config1 and custom_freq fields, to make TV mode setting logic more
|
||||
concise and uniform.
|
||||
|
||||
Additionally, remove the superfluous tv_mode field, which was redundant
|
||||
with the mode field in struct drm_tv_connector_state.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 69 +++++++++++------------------------
|
||||
1 file changed, 22 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index 4e2250b8fa23..809690f2dd55 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -170,8 +170,6 @@ struct vc4_vec {
|
||||
|
||||
struct clk *clock;
|
||||
|
||||
- const struct vc4_vec_tv_mode *tv_mode;
|
||||
-
|
||||
struct debugfs_regset32 regset;
|
||||
};
|
||||
|
||||
@@ -211,7 +209,9 @@ enum vc4_vec_tv_mode_id {
|
||||
|
||||
struct vc4_vec_tv_mode {
|
||||
const struct drm_display_mode *mode;
|
||||
- void (*mode_set)(struct vc4_vec *vec);
|
||||
+ u32 config0;
|
||||
+ u32 config1;
|
||||
+ u32 custom_freq;
|
||||
};
|
||||
|
||||
static const struct debugfs_reg32 vec_regs[] = {
|
||||
@@ -241,18 +241,6 @@ static const struct debugfs_reg32 vec_regs[] = {
|
||||
VC4_REG32(VEC_DAC_MISC),
|
||||
};
|
||||
|
||||
-static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
|
||||
-{
|
||||
- VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
|
||||
- VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
|
||||
-}
|
||||
-
|
||||
-static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
|
||||
-{
|
||||
- VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
|
||||
- VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
|
||||
-}
|
||||
-
|
||||
static const struct drm_display_mode ntsc_mode = {
|
||||
DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
@@ -260,21 +248,6 @@ static const struct drm_display_mode ntsc_mode = {
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
-static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
|
||||
-{
|
||||
- VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
|
||||
- VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
|
||||
-}
|
||||
-
|
||||
-static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
|
||||
-{
|
||||
- VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
|
||||
- VEC_WRITE(VEC_CONFIG1,
|
||||
- VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
|
||||
- VEC_WRITE(VEC_FREQ3_2, 0x223b);
|
||||
- VEC_WRITE(VEC_FREQ1_0, 0x61d1);
|
||||
-}
|
||||
-
|
||||
static const struct drm_display_mode pal_mode = {
|
||||
DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
@@ -285,19 +258,24 @@ static const struct drm_display_mode pal_mode = {
|
||||
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
[VC4_VEC_TV_MODE_NTSC] = {
|
||||
.mode = &ntsc_mode,
|
||||
- .mode_set = vc4_vec_ntsc_mode_set,
|
||||
+ .config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_J] = {
|
||||
.mode = &ntsc_mode,
|
||||
- .mode_set = vc4_vec_ntsc_j_mode_set,
|
||||
+ .config0 = VEC_CONFIG0_NTSC_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL] = {
|
||||
.mode = &pal_mode,
|
||||
- .mode_set = vc4_vec_pal_mode_set,
|
||||
+ .config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_M] = {
|
||||
.mode = &pal_mode,
|
||||
- .mode_set = vc4_vec_pal_m_mode_set,
|
||||
+ .config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
+ .custom_freq = 0x223b61d1,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -367,7 +345,6 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.tv_mode_property,
|
||||
VC4_VEC_TV_MODE_NTSC);
|
||||
- vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
|
||||
|
||||
drm_connector_attach_encoder(connector, vec->encoder);
|
||||
|
||||
@@ -400,6 +377,7 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
|
||||
struct vc4_vec *vec = vc4_vec_encoder->vec;
|
||||
+ unsigned int tv_mode = vec->connector->state->tv.mode;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(&vec->pdev->dev);
|
||||
@@ -455,7 +433,15 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
/* Mask all interrupts. */
|
||||
VEC_WRITE(VEC_MASK0, 0);
|
||||
|
||||
- vec->tv_mode->mode_set(vec);
|
||||
+ VEC_WRITE(VEC_CONFIG0, vc4_vec_tv_modes[tv_mode].config0);
|
||||
+ VEC_WRITE(VEC_CONFIG1, vc4_vec_tv_modes[tv_mode].config1);
|
||||
+ if (vc4_vec_tv_modes[tv_mode].custom_freq != 0) {
|
||||
+ VEC_WRITE(VEC_FREQ3_2,
|
||||
+ (vc4_vec_tv_modes[tv_mode].custom_freq >> 16) &
|
||||
+ 0xffff);
|
||||
+ VEC_WRITE(VEC_FREQ1_0,
|
||||
+ vc4_vec_tv_modes[tv_mode].custom_freq & 0xffff);
|
||||
+ }
|
||||
|
||||
VEC_WRITE(VEC_DAC_MISC,
|
||||
VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
|
||||
@@ -470,16 +456,6 @@ static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
- struct drm_crtc_state *crtc_state,
|
||||
- struct drm_connector_state *conn_state)
|
||||
-{
|
||||
- struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
|
||||
- struct vc4_vec *vec = vc4_vec_encoder->vec;
|
||||
-
|
||||
- vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
|
||||
-}
|
||||
-
|
||||
static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
@@ -500,7 +476,6 @@ static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
|
||||
.enable = vc4_vec_encoder_enable,
|
||||
.mode_fixup = vc4_vec_encoder_mode_fixup,
|
||||
.atomic_check = vc4_vec_encoder_atomic_check,
|
||||
- .atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
|
||||
};
|
||||
|
||||
static const struct vc4_vec_variant bcm2835_vec_variant = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
From 786d3424a7dd1ffb36ca211a1e4c23ac05320afd Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:07:53 +0200
|
||||
Subject: [PATCH 472/634] drm/vc4: Fix definition of PAL-M mode
|
||||
|
||||
PAL-M is a Brazilian analog TV standard that uses a PAL-style chroma
|
||||
subcarrier at 3.575611[888111] MHz on top of 525-line (480i60) timings.
|
||||
This commit makes the driver actually use the proper VEC preset for this
|
||||
mode instead of just changing PAL subcarrier frequency.
|
||||
|
||||
DRM mode constant names have also been changed, as they no longer
|
||||
correspond to the "NTSC" or "PAL" terms.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index 809690f2dd55..231ed492cb71 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -68,6 +68,7 @@
|
||||
#define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
|
||||
#define VEC_CONFIG0_NTSC_STD 0
|
||||
#define VEC_CONFIG0_PAL_BDGHI_STD 1
|
||||
+#define VEC_CONFIG0_PAL_M_STD 2
|
||||
#define VEC_CONFIG0_PAL_N_STD 3
|
||||
|
||||
#define VEC_SCHPH 0x108
|
||||
@@ -241,14 +242,14 @@ static const struct debugfs_reg32 vec_regs[] = {
|
||||
VC4_REG32(VEC_DAC_MISC),
|
||||
};
|
||||
|
||||
-static const struct drm_display_mode ntsc_mode = {
|
||||
+static const struct drm_display_mode drm_mode_480i = {
|
||||
DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
480, 480 + 7, 480 + 7 + 6, 525, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
-static const struct drm_display_mode pal_mode = {
|
||||
+static const struct drm_display_mode drm_mode_576i = {
|
||||
DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
576, 576 + 4, 576 + 4 + 6, 625, 0,
|
||||
@@ -257,25 +258,24 @@ static const struct drm_display_mode pal_mode = {
|
||||
|
||||
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
[VC4_VEC_TV_MODE_NTSC] = {
|
||||
- .mode = &ntsc_mode,
|
||||
+ .mode = &drm_mode_480i,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_J] = {
|
||||
- .mode = &ntsc_mode,
|
||||
+ .mode = &drm_mode_480i,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL] = {
|
||||
- .mode = &pal_mode,
|
||||
+ .mode = &drm_mode_576i,
|
||||
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_M] = {
|
||||
- .mode = &pal_mode,
|
||||
- .config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
- .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
- .custom_freq = 0x223b61d1,
|
||||
+ .mode = &drm_mode_480i,
|
||||
+ .config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
};
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
From d7adb28231c1e63db2752d6df2c13a95f900cdaf Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:07:58 +0200
|
||||
Subject: [PATCH 473/634] drm/vc4: Add support for more analog TV standards
|
||||
|
||||
Add support for the following composite output modes (all of them are
|
||||
somewhat more obscure than the previously defined ones):
|
||||
|
||||
- NTSC_443 - NTSC-style signal with the chroma subcarrier shifted to
|
||||
4.43361875 MHz (the PAL subcarrier frequency). Never used for
|
||||
broadcasting, but sometimes used as a hack to play NTSC content in PAL
|
||||
regions (e.g. on VCRs).
|
||||
- PAL_N - PAL with alternative chroma subcarrier frequency,
|
||||
3.58205625 MHz. Used as a broadcast standard in Argentina, Paraguay
|
||||
and Uruguay to fit 576i50 with colour in 6 MHz channel raster.
|
||||
- PAL60 - 480i60 signal with PAL-style color at normal European PAL
|
||||
frequency. Another non-standard, non-broadcast mode, used in similar
|
||||
contexts as NTSC_443. Some displays support one but not the other.
|
||||
- SECAM - French frequency-modulated analog color standard; also have
|
||||
been broadcast in Eastern Europe and various parts of Africa and Asia.
|
||||
Uses the same 576i50 timings as PAL.
|
||||
|
||||
Also added some comments explaining color subcarrier frequency
|
||||
registers.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 63 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 63 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index 231ed492cb71..e0bd484321d1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -45,6 +45,7 @@
|
||||
#define VEC_CONFIG0_YDEL(x) ((x) << 26)
|
||||
#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24)
|
||||
#define VEC_CONFIG0_CDEL(x) ((x) << 24)
|
||||
+#define VEC_CONFIG0_SECAM_STD BIT(21)
|
||||
#define VEC_CONFIG0_PBPR_FIL BIT(18)
|
||||
#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16)
|
||||
#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16)
|
||||
@@ -75,6 +76,27 @@
|
||||
#define VEC_SOFT_RESET 0x10c
|
||||
#define VEC_CLMP0_START 0x144
|
||||
#define VEC_CLMP0_END 0x148
|
||||
+
|
||||
+/*
|
||||
+ * These set the color subcarrier frequency
|
||||
+ * if VEC_CONFIG1_CUSTOM_FREQ is enabled.
|
||||
+ *
|
||||
+ * VEC_FREQ1_0 contains the most significant 16-bit half-word,
|
||||
+ * VEC_FREQ3_2 contains the least significant 16-bit half-word.
|
||||
+ * 0x80000000 seems to be equivalent to the pixel clock
|
||||
+ * (which itself is the VEC clock divided by 8).
|
||||
+ *
|
||||
+ * Reference values (with the default pixel clock of 13.5 MHz):
|
||||
+ *
|
||||
+ * NTSC (3579545.[45] Hz) - 0x21F07C1F
|
||||
+ * PAL (4433618.75 Hz) - 0x2A098ACB
|
||||
+ * PAL-M (3575611.[888111] Hz) - 0x21E6EFE3
|
||||
+ * PAL-N (3582056.25 Hz) - 0x21F69446
|
||||
+ *
|
||||
+ * NOTE: For SECAM, it is used as the Dr center frequency,
|
||||
+ * regardless of whether VEC_CONFIG1_CUSTOM_FREQ is enabled or not;
|
||||
+ * that is specified as 4406250 Hz, which corresponds to 0x29C71C72.
|
||||
+ */
|
||||
#define VEC_FREQ3_2 0x180
|
||||
#define VEC_FREQ1_0 0x184
|
||||
|
||||
@@ -117,6 +139,14 @@
|
||||
|
||||
#define VEC_INTERRUPT_CONTROL 0x190
|
||||
#define VEC_INTERRUPT_STATUS 0x194
|
||||
+
|
||||
+/*
|
||||
+ * Db center frequency for SECAM; the clock for this is the same as for
|
||||
+ * VEC_FREQ3_2/VEC_FREQ1_0, which is used for Dr center frequency.
|
||||
+ *
|
||||
+ * This is specified as 4250000 Hz, which corresponds to 0x284BDA13.
|
||||
+ * That is also the default value, so no need to set it explicitly.
|
||||
+ */
|
||||
#define VEC_FCW_SECAM_B 0x198
|
||||
#define VEC_SECAM_GAIN_VAL 0x19c
|
||||
|
||||
@@ -204,8 +234,12 @@ struct vc4_vec_connector {
|
||||
enum vc4_vec_tv_mode_id {
|
||||
VC4_VEC_TV_MODE_NTSC,
|
||||
VC4_VEC_TV_MODE_NTSC_J,
|
||||
+ VC4_VEC_TV_MODE_NTSC_443,
|
||||
VC4_VEC_TV_MODE_PAL,
|
||||
VC4_VEC_TV_MODE_PAL_M,
|
||||
+ VC4_VEC_TV_MODE_PAL_N,
|
||||
+ VC4_VEC_TV_MODE_PAL60,
|
||||
+ VC4_VEC_TV_MODE_SECAM,
|
||||
};
|
||||
|
||||
struct vc4_vec_tv_mode {
|
||||
@@ -267,6 +301,13 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
+ [VC4_VEC_TV_MODE_NTSC_443] = {
|
||||
+ /* NTSC with PAL chroma frequency */
|
||||
+ .mode = &drm_mode_480i,
|
||||
+ .config0 = VEC_CONFIG0_NTSC_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
+ .custom_freq = 0x2a098acb,
|
||||
+ },
|
||||
[VC4_VEC_TV_MODE_PAL] = {
|
||||
.mode = &drm_mode_576i,
|
||||
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
@@ -277,6 +318,24 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
.config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
+ [VC4_VEC_TV_MODE_PAL_N] = {
|
||||
+ .mode = &drm_mode_576i,
|
||||
+ .config0 = VEC_CONFIG0_PAL_N_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
+ },
|
||||
+ [VC4_VEC_TV_MODE_PAL60] = {
|
||||
+ /* PAL-M with chroma frequency of regular PAL */
|
||||
+ .mode = &drm_mode_480i,
|
||||
+ .config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
+ .custom_freq = 0x2a098acb,
|
||||
+ },
|
||||
+ [VC4_VEC_TV_MODE_SECAM] = {
|
||||
+ .mode = &drm_mode_576i,
|
||||
+ .config0 = VEC_CONFIG0_SECAM_STD,
|
||||
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
+ .custom_freq = 0x29c71c72,
|
||||
+ },
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
@@ -499,8 +558,12 @@ static const struct of_device_id vc4_vec_dt_match[] = {
|
||||
static const char * const tv_mode_names[] = {
|
||||
[VC4_VEC_TV_MODE_NTSC] = "NTSC",
|
||||
[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
|
||||
+ [VC4_VEC_TV_MODE_NTSC_443] = "NTSC-443",
|
||||
[VC4_VEC_TV_MODE_PAL] = "PAL",
|
||||
[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
|
||||
+ [VC4_VEC_TV_MODE_PAL_N] = "PAL-N",
|
||||
+ [VC4_VEC_TV_MODE_PAL60] = "PAL60",
|
||||
+ [VC4_VEC_TV_MODE_SECAM] = "SECAM",
|
||||
};
|
||||
|
||||
static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
From cb0f3c128dd03bae41ff68d04a2af324e8af0d2a Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:08:01 +0200
|
||||
Subject: [PATCH 474/634] drm/vc4: Allow setting the TV norm via module
|
||||
parameter
|
||||
|
||||
Similar to the ch7006 and nouveau drivers, introduce a "tv_mode" module
|
||||
parameter that allow setting the TV norm by specifying vc4.tv_norm= on
|
||||
the kernel command line.
|
||||
|
||||
If that is not specified, try inferring one of the most popular norms
|
||||
(PAL or NTSC) from the video mode specified on the command line. On
|
||||
Raspberry Pis, this causes the most common cases of the sdtv_mode
|
||||
setting in config.txt to be respected.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 72 ++++++++++++++++++++++++++++-------
|
||||
1 file changed, 58 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index e0bd484321d1..fb4360c0d9e3 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -66,7 +66,7 @@
|
||||
#define VEC_CONFIG0_YCDELAY BIT(4)
|
||||
#define VEC_CONFIG0_RAMPEN BIT(2)
|
||||
#define VEC_CONFIG0_YCDIS BIT(2)
|
||||
-#define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
|
||||
+#define VEC_CONFIG0_STD_MASK (VEC_CONFIG0_SECAM_STD | GENMASK(1, 0))
|
||||
#define VEC_CONFIG0_NTSC_STD 0
|
||||
#define VEC_CONFIG0_PAL_BDGHI_STD 1
|
||||
#define VEC_CONFIG0_PAL_M_STD 2
|
||||
@@ -185,6 +185,8 @@
|
||||
#define VEC_DAC_MISC_DAC_RST_N BIT(0)
|
||||
|
||||
|
||||
+static char *vc4_vec_tv_norm;
|
||||
+
|
||||
struct vc4_vec_variant {
|
||||
u32 dac_config;
|
||||
};
|
||||
@@ -338,6 +340,44 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
},
|
||||
};
|
||||
|
||||
+static const char * const tv_mode_names[] = {
|
||||
+ [VC4_VEC_TV_MODE_NTSC] = "NTSC",
|
||||
+ [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
|
||||
+ [VC4_VEC_TV_MODE_NTSC_443] = "NTSC-443",
|
||||
+ [VC4_VEC_TV_MODE_PAL] = "PAL",
|
||||
+ [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
|
||||
+ [VC4_VEC_TV_MODE_PAL_N] = "PAL-N",
|
||||
+ [VC4_VEC_TV_MODE_PAL60] = "PAL60",
|
||||
+ [VC4_VEC_TV_MODE_SECAM] = "SECAM",
|
||||
+};
|
||||
+
|
||||
+enum vc4_vec_tv_mode_id
|
||||
+vc4_vec_get_default_mode(struct drm_connector *connector)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (vc4_vec_tv_norm) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(tv_mode_names); i++)
|
||||
+ if (strcmp(vc4_vec_tv_norm, tv_mode_names[i]) == 0)
|
||||
+ return (enum vc4_vec_tv_mode_id) i;
|
||||
+ } else if (connector->cmdline_mode.specified &&
|
||||
+ ((connector->cmdline_mode.refresh_specified &&
|
||||
+ (connector->cmdline_mode.refresh == 25 ||
|
||||
+ connector->cmdline_mode.refresh == 50)) ||
|
||||
+ (!connector->cmdline_mode.refresh_specified &&
|
||||
+ (connector->cmdline_mode.yres == 288 ||
|
||||
+ connector->cmdline_mode.yres == 576)))) {
|
||||
+ /*
|
||||
+ * no explicitly specified TV norm; use PAL if a mode that
|
||||
+ * looks like PAL has been specified on the command line
|
||||
+ */
|
||||
+ return VC4_VEC_TV_MODE_PAL;
|
||||
+ }
|
||||
+
|
||||
+ /* in all other cases, default to NTSC */
|
||||
+ return VC4_VEC_TV_MODE_NTSC;
|
||||
+}
|
||||
+
|
||||
static enum drm_connector_status
|
||||
vc4_vec_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@@ -367,11 +407,19 @@ static int vc4_vec_connector_get_modes(struct drm_connector *connector)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static void vc4_vec_connector_reset(struct drm_connector *connector)
|
||||
+{
|
||||
+ drm_atomic_helper_connector_reset(connector);
|
||||
+ /* preserve TV standard */
|
||||
+ if (connector->state)
|
||||
+ connector->state->tv.mode = vc4_vec_get_default_mode(connector);
|
||||
+}
|
||||
+
|
||||
static const struct drm_connector_funcs vc4_vec_connector_funcs = {
|
||||
.detect = vc4_vec_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = vc4_vec_connector_destroy,
|
||||
- .reset = drm_atomic_helper_connector_reset,
|
||||
+ .reset = vc4_vec_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
@@ -403,7 +451,7 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
|
||||
|
||||
drm_object_attach_property(&connector->base,
|
||||
dev->mode_config.tv_mode_property,
|
||||
- VC4_VEC_TV_MODE_NTSC);
|
||||
+ vc4_vec_get_default_mode(connector));
|
||||
|
||||
drm_connector_attach_encoder(connector, vec->encoder);
|
||||
|
||||
@@ -555,17 +603,6 @@ static const struct of_device_id vc4_vec_dt_match[] = {
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
-static const char * const tv_mode_names[] = {
|
||||
- [VC4_VEC_TV_MODE_NTSC] = "NTSC",
|
||||
- [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
|
||||
- [VC4_VEC_TV_MODE_NTSC_443] = "NTSC-443",
|
||||
- [VC4_VEC_TV_MODE_PAL] = "PAL",
|
||||
- [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
|
||||
- [VC4_VEC_TV_MODE_PAL_N] = "PAL-N",
|
||||
- [VC4_VEC_TV_MODE_PAL60] = "PAL60",
|
||||
- [VC4_VEC_TV_MODE_SECAM] = "SECAM",
|
||||
-};
|
||||
-
|
||||
static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
@@ -674,3 +711,10 @@ struct platform_driver vc4_vec_driver = {
|
||||
.of_match_table = vc4_vec_dt_match,
|
||||
},
|
||||
};
|
||||
+
|
||||
+module_param_named(tv_norm, vc4_vec_tv_norm, charp, 0600);
|
||||
+MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
|
||||
+ "\t\tSupported: NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N,\n"
|
||||
+ "\t\t\tPAL60, SECAM.\n"
|
||||
+ "\t\tDefault: PAL if a 50 Hz mode has been set via video=,\n"
|
||||
+ "\t\t\tNTSC otherwise");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
From 435dc64038e7bbc027d5f4de1c8df7f13a411d29 Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:08:05 +0200
|
||||
Subject: [PATCH 475/634] drm/vc4: Refactor mode checking logic
|
||||
|
||||
Replace drm_encoder_helper_funcs::atomic_check with
|
||||
drm_connector_helper_funcs::atomic_check - the former is not called
|
||||
during drm_mode_obj_set_property_ioctl(). Set crtc_state->mode_changed
|
||||
if TV norm changes even without explicit mode change. This makes things
|
||||
like "xrandr --output Composite-1 --set mode PAL-M" work properly.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 42 ++++++++++++++++++++++-------------
|
||||
1 file changed, 26 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index fb4360c0d9e3..b684595a5d0b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -415,6 +415,31 @@ static void vc4_vec_connector_reset(struct drm_connector *connector)
|
||||
connector->state->tv.mode = vc4_vec_get_default_mode(connector);
|
||||
}
|
||||
|
||||
+static int vc4_vec_connector_atomic_check(struct drm_connector *conn,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct drm_connector_state *old_state =
|
||||
+ drm_atomic_get_old_connector_state(state, conn);
|
||||
+ struct drm_connector_state *new_state =
|
||||
+ drm_atomic_get_new_connector_state(state, conn);
|
||||
+
|
||||
+ const struct vc4_vec_tv_mode *vec_mode =
|
||||
+ &vc4_vec_tv_modes[new_state->tv.mode];
|
||||
+
|
||||
+ if (new_state->crtc) {
|
||||
+ struct drm_crtc_state *crtc_state =
|
||||
+ drm_atomic_get_new_crtc_state(state, new_state->crtc);
|
||||
+
|
||||
+ if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (old_state->tv.mode != new_state->tv.mode)
|
||||
+ crtc_state->mode_changed = true;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const struct drm_connector_funcs vc4_vec_connector_funcs = {
|
||||
.detect = vc4_vec_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
@@ -426,6 +451,7 @@ static const struct drm_connector_funcs vc4_vec_connector_funcs = {
|
||||
|
||||
static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
|
||||
.get_modes = vc4_vec_connector_get_modes,
|
||||
+ .atomic_check = vc4_vec_connector_atomic_check,
|
||||
};
|
||||
|
||||
static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
|
||||
@@ -563,26 +589,10 @@ static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
-static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
- struct drm_crtc_state *crtc_state,
|
||||
- struct drm_connector_state *conn_state)
|
||||
-{
|
||||
- const struct vc4_vec_tv_mode *vec_mode;
|
||||
-
|
||||
- vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
|
||||
-
|
||||
- if (conn_state->crtc &&
|
||||
- !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
|
||||
- return -EINVAL;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
|
||||
.disable = vc4_vec_encoder_disable,
|
||||
.enable = vc4_vec_encoder_enable,
|
||||
.mode_fixup = vc4_vec_encoder_mode_fixup,
|
||||
- .atomic_check = vc4_vec_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct vc4_vec_variant bcm2835_vec_variant = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
From 27c04928300510f13438df4a120f671df6b03321 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 25 Jun 2021 17:01:33 +0200
|
||||
Subject: [PATCH 476/634] drm/vc4: Remove conflicting framebuffers before
|
||||
callind bind_all
|
||||
|
||||
The bind hooks will modify their controller registers, so simplefb is
|
||||
going to be unusable anyway. Let's avoid any transient state where it
|
||||
could still be in the system but no longer functionnal.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index baa419bc5199..556bf17a6573 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -273,15 +273,15 @@ static int vc4_drm_bind(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = component_bind_all(dev, drm);
|
||||
+ ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = vc4_plane_create_additional_planes(drm);
|
||||
+ ret = component_bind_all(dev, drm);
|
||||
if (ret)
|
||||
- goto unbind_all;
|
||||
+ return ret;
|
||||
|
||||
- ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver);
|
||||
+ ret = vc4_plane_create_additional_planes(drm);
|
||||
if (ret)
|
||||
goto unbind_all;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
From 69f5c55779c1953ead79e807ef8823478887dbec Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 23 Jun 2021 11:54:58 +0200
|
||||
Subject: [PATCH 477/634] drm/vc4: Notify the firmware when DRM is in charge
|
||||
|
||||
Once the call to drm_fb_helper_remove_conflicting_framebuffers() has
|
||||
been made, simplefb has been unregistered and the KMS driver is entirely
|
||||
in charge of the display.
|
||||
|
||||
Thus, we can notify the firmware it can free whatever resource it was
|
||||
using to maintain simplefb functional.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 19 +++++++++++++++++++
|
||||
1 file changed, 19 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index 556bf17a6573..88d6d2c6fa23 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
#include "uapi/drm/vc4_drm.h"
|
||||
|
||||
#include "vc4_drv.h"
|
||||
@@ -273,10 +275,27 @@ static int vc4_drm_bind(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0);
|
||||
+ if (node) {
|
||||
+ vc4->firmware = rpi_firmware_get(node);
|
||||
+ of_node_put(node);
|
||||
+
|
||||
+ if (!vc4->firmware)
|
||||
+ return -EPROBE_DEFER;
|
||||
+ }
|
||||
+
|
||||
ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ if (vc4->firmware) {
|
||||
+ ret = rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_NOTIFY_DISPLAY_DONE,
|
||||
+ NULL, 0);
|
||||
+ if (ret)
|
||||
+ drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
ret = component_bind_all(dev, drm);
|
||||
if (ret)
|
||||
return ret;
|
||||
--
|
||||
2.33.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,63 +0,0 @@
|
|||
From 59dca213da407638874caf97b0e9c15f886df890 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 23 Jul 2021 15:45:54 +0200
|
||||
Subject: [PATCH 484/634] drm/vc4: hdmi: Unregister codec device on unbind
|
||||
|
||||
On bind we will register the HDMI codec device but we don't unregister
|
||||
it on unbind, leading to a device leakage. Unregister our device at
|
||||
unbind.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 8 ++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 1 +
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 502d5bea5f61..395a9e9c1e5a 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1746,6 +1746,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev));
|
||||
return PTR_ERR(codec_pdev);
|
||||
}
|
||||
+ vc4_hdmi->audio.codec_pdev = codec_pdev;
|
||||
|
||||
dai_link->cpus = &vc4_hdmi->audio.cpu;
|
||||
dai_link->codecs = &vc4_hdmi->audio.codec;
|
||||
@@ -1785,6 +1786,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
|
||||
}
|
||||
|
||||
+static void vc4_hdmi_audio_exit(struct vc4_hdmi *vc4_hdmi)
|
||||
+{
|
||||
+ platform_device_unregister(vc4_hdmi->audio.codec_pdev);
|
||||
+ vc4_hdmi->audio.codec_pdev = NULL;
|
||||
+}
|
||||
+
|
||||
static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
@@ -2689,6 +2696,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
|
||||
kfree(vc4_hdmi->hdmi_regset.regs);
|
||||
kfree(vc4_hdmi->hd_regset.regs);
|
||||
|
||||
+ vc4_hdmi_audio_exit(vc4_hdmi);
|
||||
vc4_hdmi_cec_exit(vc4_hdmi);
|
||||
vc4_hdmi_hotplug_exit(vc4_hdmi);
|
||||
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index db53500a8435..275c4674d50f 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -113,6 +113,7 @@ struct vc4_hdmi_audio {
|
||||
struct snd_soc_dai_link_component platform;
|
||||
struct snd_dmaengine_dai_dma_data dma_data;
|
||||
struct hdmi_audio_infoframe infoframe;
|
||||
+ struct platform_device *codec_pdev;
|
||||
bool streaming;
|
||||
};
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
From 214b5251ae7f2559119f4fe202e2d83fe27ea970 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Rutland <mark.rutland@arm.com>
|
||||
Date: Tue, 8 Jun 2021 09:55:12 +0100
|
||||
Subject: [PATCH 485/634] drm/vc4: fix vc4_atomic_commit_tail() logic
|
||||
|
||||
In vc4_atomic_commit_tail() we iterate of the set of old CRTCs, and
|
||||
attempt to wait on any channels which are still in use. When we iterate
|
||||
over the CRTCs, we have:
|
||||
|
||||
* `i` - the index of the CRTC
|
||||
* `channel` - the channel a CRTC is using
|
||||
|
||||
When we check the channel state, we consult:
|
||||
|
||||
old_hvs_state->fifo_state[channel].in_use
|
||||
|
||||
... but when we wait for the channel, we erroneously wait on:
|
||||
|
||||
old_hvs_state->fifo_state[i].pending_commit
|
||||
|
||||
... rather than:
|
||||
|
||||
old_hvs_state->fifo_state[channel].pending_commit
|
||||
|
||||
... and this bogus access has been observed to result in boot-time hangs
|
||||
on some arm64 configurations, and can be detected using KASAN. FIx this
|
||||
by using the correct index.
|
||||
|
||||
I've tested this on a Raspberry Pi 3 model B v1.2 with KASAN.
|
||||
|
||||
Trimmed KASAN splat:
|
||||
|
||||
| ==================================================================
|
||||
| BUG: KASAN: slab-out-of-bounds in vc4_atomic_commit_tail+0x1cc/0x910
|
||||
| Read of size 8 at addr ffff000007360440 by task kworker/u8:0/7
|
||||
| CPU: 2 PID: 7 Comm: kworker/u8:0 Not tainted 5.13.0-rc3-00009-g694c523e7267 #3
|
||||
|
|
||||
| Hardware name: Raspberry Pi 3 Model B (DT)
|
||||
| Workqueue: events_unbound deferred_probe_work_func
|
||||
| Call trace:
|
||||
| dump_backtrace+0x0/0x2b4
|
||||
| show_stack+0x1c/0x30
|
||||
| dump_stack+0xfc/0x168
|
||||
| print_address_description.constprop.0+0x2c/0x2c0
|
||||
| kasan_report+0x1dc/0x240
|
||||
| __asan_load8+0x98/0xd4
|
||||
| vc4_atomic_commit_tail+0x1cc/0x910
|
||||
| commit_tail+0x100/0x210
|
||||
| ...
|
||||
|
|
||||
| Allocated by task 7:
|
||||
| kasan_save_stack+0x2c/0x60
|
||||
| __kasan_kmalloc+0x90/0xb4
|
||||
| vc4_hvs_channels_duplicate_state+0x60/0x1a0
|
||||
| drm_atomic_get_private_obj_state+0x144/0x230
|
||||
| vc4_atomic_check+0x40/0x73c
|
||||
| drm_atomic_check_only+0x998/0xe60
|
||||
| drm_atomic_commit+0x34/0x94
|
||||
| drm_client_modeset_commit_atomic+0x2f4/0x3a0
|
||||
| drm_client_modeset_commit_locked+0x8c/0x230
|
||||
| drm_client_modeset_commit+0x38/0x60
|
||||
| drm_fb_helper_set_par+0x104/0x17c
|
||||
| fbcon_init+0x43c/0x970
|
||||
| visual_init+0x14c/0x1e4
|
||||
| ...
|
||||
|
|
||||
| The buggy address belongs to the object at ffff000007360400
|
||||
| which belongs to the cache kmalloc-128 of size 128
|
||||
| The buggy address is located 64 bytes inside of
|
||||
| 128-byte region [ffff000007360400, ffff000007360480)
|
||||
| The buggy address belongs to the page:
|
||||
| page:(____ptrval____) refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x7360
|
||||
| flags: 0x3fffc0000000200(slab|node=0|zone=0|lastcpupid=0xffff)
|
||||
| raw: 03fffc0000000200 dead000000000100 dead000000000122 ffff000004c02300
|
||||
| raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000
|
||||
| page dumped because: kasan: bad access detected
|
||||
|
|
||||
| Memory state around the buggy address:
|
||||
| ffff000007360300: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
| ffff000007360380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
| >ffff000007360400: 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc
|
||||
| ^
|
||||
| ffff000007360480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
|
||||
| ffff000007360500: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
|
||||
| ==================================================================
|
||||
|
||||
Link: https://lore.kernel.org/r/4d0c8318-bad8-2be7-e292-fc8f70c198de@samsung.com
|
||||
Link: https://lore.kernel.org/linux-arm-kernel/20210607151740.moncryl5zv3ahq4s@gilmour
|
||||
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
|
||||
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
Cc: Arnd Bergmann <arnd@arndb.de>
|
||||
Cc: Catalin Marinas <catalin.marinas@arm.com>
|
||||
Cc: Daniel Vetter <daniel@ffwll.ch>
|
||||
Cc: David Airlie <airlied@linux.ie>
|
||||
Cc: Emma Anholt <emma@anholt.net>
|
||||
Cc: Maxime Ripard <maxime@cerno.tech>
|
||||
Cc: Will Deacon <will@kernel.org>
|
||||
Cc: dri-devel@lists.freedesktop.org
|
||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210608085513.2069-1-mark.rutland@arm.com
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 26a31bd97a5d..8a8476f7df08 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -386,6 +386,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
to_vc4_crtc_state(old_crtc_state);
|
||||
+ struct drm_crtc_commit *commit;
|
||||
unsigned int channel = vc4_crtc_state->assigned_channel;
|
||||
int ret;
|
||||
|
||||
@@ -395,7 +396,11 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
if (!old_hvs_state->fifo_state[channel].in_use)
|
||||
continue;
|
||||
|
||||
- ret = drm_crtc_commit_wait(old_hvs_state->fifo_state[channel].pending_commit);
|
||||
+ commit = old_hvs_state->fifo_state[channel].pending_commit;
|
||||
+ if (!commit)
|
||||
+ continue;
|
||||
+
|
||||
+ ret = drm_crtc_commit_wait(commit);
|
||||
if (ret)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
From 362e013b4a3f887c718a5808c8825e98a0e3511e Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 13 Sep 2021 17:30:18 +0100
|
||||
Subject: [PATCH 505/634] drm/vc4: Reset HDMI MISC_CONTROL register.
|
||||
|
||||
The HDMI block can repeat pixels for double clocked modes,
|
||||
and the firmware is now configuring the block to do this as
|
||||
the PV is doing it incorrectly when at 2pixels/clock.
|
||||
If the kernel doesn't reset it then we end up with strange
|
||||
modes.
|
||||
|
||||
Reset MISC_CONTROL.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 8 ++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 3 +++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 395a9e9c1e5a..a6afd7d7f21c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -78,6 +78,9 @@
|
||||
#define VC5_HDMI_VERTB_VSPO_SHIFT 16
|
||||
#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
|
||||
|
||||
+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_SHIFT 0
|
||||
+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK VC4_MASK(3, 0)
|
||||
+
|
||||
#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0)
|
||||
|
||||
#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8
|
||||
@@ -962,6 +965,11 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
|
||||
HDMI_WRITE(HDMI_GCP_CONFIG, reg);
|
||||
|
||||
+ reg = HDMI_READ(HDMI_MISC_CONTROL);
|
||||
+ reg &= ~VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK;
|
||||
+ reg |= VC4_SET_FIELD(0, VC5_HDMI_MISC_CONTROL_PIXEL_REP);
|
||||
+ HDMI_WRITE(HDMI_MISC_CONTROL, reg);
|
||||
+
|
||||
HDMI_WRITE(HDMI_CLOCK_STOP, 0);
|
||||
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
index fc971506bd4f..24056441a4bb 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
@@ -125,6 +125,7 @@ enum vc4_hdmi_field {
|
||||
HDMI_VERTB0,
|
||||
HDMI_VERTB1,
|
||||
HDMI_VID_CTL,
|
||||
+ HDMI_MISC_CONTROL,
|
||||
};
|
||||
|
||||
struct vc4_hdmi_register {
|
||||
@@ -235,6 +236,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = {
|
||||
VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
|
||||
VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
|
||||
VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
|
||||
+ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x100),
|
||||
VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
|
||||
VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
|
||||
VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
|
||||
@@ -315,6 +317,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = {
|
||||
VC4_HDMI_REG(HDMI_VERTB0, 0x0f0),
|
||||
VC4_HDMI_REG(HDMI_VERTA1, 0x0f4),
|
||||
VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
|
||||
+ VC4_HDMI_REG(HDMI_MISC_CONTROL, 0x100),
|
||||
VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
|
||||
VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
|
||||
VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
From 8fe39ec43ba5d59b6f88d6a17477a2a1a206483d Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 6 Jul 2021 18:53:28 +0100
|
||||
Subject: [PATCH 506/634] drm/vc4: Release workaround buffer and DMA in error
|
||||
paths and unbind
|
||||
|
||||
On Pi0-3 the driver allocates a buffer and requests a DMA channel
|
||||
because the ARM can't write to DSI1's registers directly.
|
||||
However unbind and the error paths in bind don't release the buffer or
|
||||
the DMA channel.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dsi.c | 51 ++++++++++++++++++++++++++---------
|
||||
1 file changed, 39 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
index e433071bf797..abfa19cc9b45 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
@@ -1616,7 +1616,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
if (ret != -EPROBE_DEFER)
|
||||
DRM_ERROR("Failed to get DMA channel: %d\n",
|
||||
ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma_mem;
|
||||
}
|
||||
|
||||
/* Get the physical address of the device's registers. The
|
||||
@@ -1645,7 +1645,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get interrupt: %d\n", ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
dsi->escape_clock = devm_clk_get(dev, "escape");
|
||||
@@ -1653,7 +1653,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
ret = PTR_ERR(dsi->escape_clock);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get escape clock: %d\n", ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
dsi->pll_phy_clock = devm_clk_get(dev, "phy");
|
||||
@@ -1661,7 +1661,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
ret = PTR_ERR(dsi->pll_phy_clock);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get phy clock: %d\n", ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
dsi->pixel_clock = devm_clk_get(dev, "pixel");
|
||||
@@ -1669,7 +1669,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
ret = PTR_ERR(dsi->pixel_clock);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get pixel clock: %d\n", ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
|
||||
@@ -1684,33 +1684,37 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
if (ret == -ENODEV)
|
||||
return 0;
|
||||
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
if (panel) {
|
||||
dsi->bridge = devm_drm_panel_bridge_add_typed(dev, panel,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
- if (IS_ERR(dsi->bridge))
|
||||
- return PTR_ERR(dsi->bridge);
|
||||
+ if (IS_ERR(dsi->bridge)) {
|
||||
+ ret = PTR_ERR(dsi->bridge);
|
||||
+ goto err_free_dma;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* The esc clock rate is supposed to always be 100Mhz. */
|
||||
ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set esc clock: %d\n", ret);
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
}
|
||||
|
||||
ret = vc4_dsi_init_phy_clocks(dsi);
|
||||
if (ret)
|
||||
- return ret;
|
||||
+ goto err_free_dma;
|
||||
|
||||
drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
|
||||
drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
|
||||
|
||||
ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, 0);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "bridge attach failed: %d\n", ret);
|
||||
+ goto err_free_dma;
|
||||
+ }
|
||||
/* Disable the atomic helper calls into the bridge. We
|
||||
* manually call the bridge pre_enable / enable / etc. calls
|
||||
* from our driver, since we need to sequence them within the
|
||||
@@ -1723,6 +1727,19 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
+
|
||||
+err_free_dma:
|
||||
+ if (dsi->reg_dma_chan) {
|
||||
+ dma_release_channel(dsi->reg_dma_chan);
|
||||
+ dsi->reg_dma_chan = NULL;
|
||||
+ }
|
||||
+err_free_dma_mem:
|
||||
+ if (dsi->reg_dma_mem) {
|
||||
+ dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr);
|
||||
+ dsi->reg_dma_mem = NULL;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void vc4_dsi_unbind(struct device *dev, struct device *master,
|
||||
@@ -1739,6 +1756,16 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
|
||||
*/
|
||||
list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain);
|
||||
drm_encoder_cleanup(dsi->encoder);
|
||||
+
|
||||
+ if (dsi->reg_dma_chan) {
|
||||
+ dma_release_channel(dsi->reg_dma_chan);
|
||||
+ dsi->reg_dma_chan = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (dsi->reg_dma_mem) {
|
||||
+ dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr);
|
||||
+ dsi->reg_dma_mem = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
static const struct component_ops vc4_dsi_ops = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
From c5819b09ed426ed64570bc11c4f0ca9622a32889 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Fri, 18 Jun 2021 21:52:28 +0100
|
||||
Subject: [PATCH 507/634] drm/vc4: Correct DSI divider calculations
|
||||
|
||||
The divider calculations tried to find the divider
|
||||
just faster than the clock requested. However if
|
||||
it required a divider of 7 then the for loop
|
||||
aborted without handling the "error" case, and could
|
||||
end up with a clock lower than requested.
|
||||
|
||||
Correct the loop so that we always have a clock greater
|
||||
than requested.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_dsi.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
index abfa19cc9b45..270e26e56e51 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
|
||||
@@ -850,11 +850,9 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
/* Find what divider gets us a faster clock than the requested
|
||||
* pixel clock.
|
||||
*/
|
||||
- for (divider = 1; divider < 8; divider++) {
|
||||
- if (parent_rate / divider < pll_clock) {
|
||||
- divider--;
|
||||
+ for (divider = 1; divider < 7; divider++) {
|
||||
+ if (parent_rate / (divider + 1) < pll_clock)
|
||||
break;
|
||||
- }
|
||||
}
|
||||
|
||||
/* Now that we've picked a PLL divider, calculate back to its
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
From dfededf17d005d8f5f6a86247f1cb7ba019fbc5c Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 27 Aug 2021 18:20:25 +0200
|
||||
Subject: [PATCH 587/634] Add missing drm_crtc_commit_put
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 8a8476f7df08..cc905b8c3282 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -403,6 +403,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
ret = drm_crtc_commit_wait(commit);
|
||||
if (ret)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
+
|
||||
+ drm_crtc_commit_put(commit);
|
||||
}
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
From 8c994de768f64b6697798c7b08f25b05485195c9 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 30 Aug 2021 15:30:41 +0200
|
||||
Subject: [PATCH 588/634] drm/vc4: Wait for the commit before starting our
|
||||
clock request
|
||||
|
||||
Several DRM/KMS atomic commits can run in parallel if they affect
|
||||
different CRTC. These commits share the global HVS state, so we have
|
||||
some code to make sure we run commits in sequence. This synchronization
|
||||
code is one of the first thing that runs in vc4_atomic_commit_tail().
|
||||
|
||||
Another constraints we have is that we need to make sure the HVS clock
|
||||
gets a boost during the commit. That code relies on clk_requests and
|
||||
will remove the old requests and start a new one. We also need another,
|
||||
temporary, request for the duration of the commit.
|
||||
|
||||
The algorithm is thus to start a temporary request, drop the previous
|
||||
one, do the commit, start a new request for the current mode, and
|
||||
finally drop the temporary request.
|
||||
|
||||
However, the part that takes a temporary request and drops the older one
|
||||
runs before the commit synchronization code.
|
||||
|
||||
Thus, under the proper conditions, we can end up dropping twice the old
|
||||
request, resulting in an use-after-free.
|
||||
|
||||
To avoid it, let's move the clock setup in the protected section.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 34 ++++++++++++++++++++--------------
|
||||
1 file changed, 20 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index cc905b8c3282..8c63b962b2e6 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -369,20 +369,6 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
|
||||
}
|
||||
|
||||
- if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
- unsigned long core_rate = max_t(unsigned long,
|
||||
- 500000000,
|
||||
- new_hvs_state->core_clock_rate);
|
||||
-
|
||||
- core_req = clk_request_start(hvs->core_clk, core_rate);
|
||||
-
|
||||
- /*
|
||||
- * And remove the previous one based on the HVS
|
||||
- * requirements if any.
|
||||
- */
|
||||
- clk_request_done(hvs->core_req);
|
||||
- }
|
||||
-
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
to_vc4_crtc_state(old_crtc_state);
|
||||
@@ -407,6 +393,26 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_crtc_commit_put(commit);
|
||||
}
|
||||
|
||||
+ if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
+ unsigned long core_rate = max_t(unsigned long,
|
||||
+ 500000000,
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
+
|
||||
+ drm_dbg(dev, "Raising the core clock at %lu Hz\n", core_rate);
|
||||
+
|
||||
+ /*
|
||||
+ * Do a temporary request on the core clock during the
|
||||
+ * modeset.
|
||||
+ */
|
||||
+ core_req = clk_request_start(hvs->core_clk, core_rate);
|
||||
+
|
||||
+ /*
|
||||
+ * And remove the previous one based on the HVS
|
||||
+ * requirements if any.
|
||||
+ */
|
||||
+ clk_request_done(hvs->core_req);
|
||||
+ }
|
||||
+
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
|
||||
vc4_ctm_commit(vc4, state);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
From 4b11270886ebe8019e079040638ed0766d505ae5 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Wed, 27 Oct 2021 16:22:41 +0100
|
||||
Subject: [PATCH 589/634] Revert "Add missing drm_crtc_commit_put"
|
||||
|
||||
This reverts commit c3ca5d8eccbb8a380e784ba01421dd484618d0d1.
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 8c63b962b2e6..2511113a6f82 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -389,8 +389,6 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
ret = drm_crtc_commit_wait(commit);
|
||||
if (ret)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
-
|
||||
- drm_crtc_commit_put(commit);
|
||||
}
|
||||
|
||||
if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
From b522484f4b813a26b597934fbb61573eb7f17f00 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 27 Apr 2021 14:24:21 +0200
|
||||
Subject: [PATCH 594/634] drm/vc4: Add support for gamma on BCM2711
|
||||
|
||||
BCM2711 changes from a 256 entry lookup table to a 16 point
|
||||
piecewise linear function as the pipeline bitdepth has increased
|
||||
to make a LUT unwieldy.
|
||||
|
||||
Implement a simple conversion from a 256 entry LUT that userspace
|
||||
is likely to expect to 16 evenly spread points in the PWL. This
|
||||
could be improved with curve fitting at a later date.
|
||||
|
||||
Co-developed-by: Juerg Haefliger <juergh@canonical.com>
|
||||
Signed-off-by: Juerg Haefliger <juergh@canonical.com>
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 35 +++++++++++---
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 28 +++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 87 ++++++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_regs.h | 22 +++++++++
|
||||
4 files changed, 159 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 23be68a8ecec..e06801557cec 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -1162,19 +1162,42 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
|
||||
|
||||
if (!vc4->hvs->hvs5) {
|
||||
drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
|
||||
+ } else {
|
||||
+ /* This is a lie for hvs5 which uses a 16 point PWL, but it
|
||||
+ * allows for something smarter than just 16 linearly spaced
|
||||
+ * segments. Conversion is done in vc5_hvs_update_gamma_lut.
|
||||
+ */
|
||||
+ drm_mode_crtc_set_gamma_size(crtc, 256);
|
||||
+ }
|
||||
|
||||
- drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
|
||||
+ drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
|
||||
|
||||
+ if (!vc4->hvs->hvs5) {
|
||||
/* We support CTM, but only for one CRTC at a time. It's therefore
|
||||
* implemented as private driver state in vc4_kms, not here.
|
||||
*/
|
||||
drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
|
||||
- }
|
||||
|
||||
- for (i = 0; i < crtc->gamma_size; i++) {
|
||||
- vc4_crtc->lut_r[i] = i;
|
||||
- vc4_crtc->lut_g[i] = i;
|
||||
- vc4_crtc->lut_b[i] = i;
|
||||
+ /* Initialize the VC4 gamma LUTs */
|
||||
+ for (i = 0; i < crtc->gamma_size; i++) {
|
||||
+ vc4_crtc->lut_r[i] = i;
|
||||
+ vc4_crtc->lut_g[i] = i;
|
||||
+ vc4_crtc->lut_b[i] = i;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Initialize the VC5 gamma PWL entries. Assume 12-bit pipeline,
|
||||
+ * evenly spread over full range.
|
||||
+ */
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) {
|
||||
+ vc4_crtc->pwl_r[i] =
|
||||
+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
+ vc4_crtc->pwl_g[i] =
|
||||
+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
+ vc4_crtc->pwl_b[i] =
|
||||
+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
+ vc4_crtc->pwl_a[i] =
|
||||
+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8);
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 48d5d13f38a3..56d014b91e4e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <drm/drm_modeset_lock.h>
|
||||
|
||||
#include "uapi/drm/vc4_drm.h"
|
||||
+#include "vc4_regs.h"
|
||||
|
||||
struct drm_device;
|
||||
struct drm_gem_object;
|
||||
@@ -481,6 +482,17 @@ struct vc4_pv_data {
|
||||
|
||||
};
|
||||
|
||||
+struct vc5_gamma_entry {
|
||||
+ u32 x_c_terms;
|
||||
+ u32 grad_term;
|
||||
+};
|
||||
+
|
||||
+#define VC5_HVS_SET_GAMMA_ENTRY(x, c, g) (struct vc5_gamma_entry){ \
|
||||
+ .x_c_terms = VC4_SET_FIELD((x), SCALER5_DSPGAMMA_OFF_X) | \
|
||||
+ VC4_SET_FIELD((c), SCALER5_DSPGAMMA_OFF_C), \
|
||||
+ .grad_term = (g) \
|
||||
+}
|
||||
+
|
||||
struct vc4_crtc {
|
||||
struct drm_crtc base;
|
||||
struct platform_device *pdev;
|
||||
@@ -490,9 +502,19 @@ struct vc4_crtc {
|
||||
/* Timestamp at start of vblank irq - unaffected by lock delays. */
|
||||
ktime_t t_vblank;
|
||||
|
||||
- u8 lut_r[256];
|
||||
- u8 lut_g[256];
|
||||
- u8 lut_b[256];
|
||||
+ union {
|
||||
+ struct { /* VC4 gamma LUT */
|
||||
+ u8 lut_r[256];
|
||||
+ u8 lut_g[256];
|
||||
+ u8 lut_b[256];
|
||||
+ };
|
||||
+ struct { /* VC5 gamma PWL entries */
|
||||
+ struct vc5_gamma_entry pwl_r[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
+ struct vc5_gamma_entry pwl_g[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
+ struct vc5_gamma_entry pwl_b[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
+ struct vc5_gamma_entry pwl_a[SCALER5_DSPGAMMA_NUM_POINTS];
|
||||
+ };
|
||||
+ };
|
||||
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index ab79d0a82a19..73751bd6775a 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -236,6 +236,80 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
|
||||
vc4_hvs_lut_load(crtc);
|
||||
}
|
||||
|
||||
+static void vc5_hvs_write_gamma_entry(struct vc4_dev *vc4,
|
||||
+ u32 offset,
|
||||
+ struct vc5_gamma_entry *gamma)
|
||||
+{
|
||||
+ HVS_WRITE(offset, gamma->x_c_terms);
|
||||
+ HVS_WRITE(offset + 4, gamma->grad_term);
|
||||
+}
|
||||
+
|
||||
+static void vc5_hvs_lut_load(struct drm_crtc *crtc)
|
||||
+{
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
+ u32 i;
|
||||
+ u32 offset = SCALER5_DSPGAMMA_START +
|
||||
+ vc4_state->assigned_channel * SCALER5_DSPGAMMA_CHAN_OFFSET;
|
||||
+
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_r[i]);
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_g[i]);
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_b[i]);
|
||||
+
|
||||
+ if (vc4_state->assigned_channel == 2) {
|
||||
+ /* Alpha only valid on channel 2 */
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8)
|
||||
+ vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_a[i]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void vc5_hvs_update_gamma_lut(struct drm_crtc *crtc)
|
||||
+{
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ struct drm_color_lut *lut = crtc->state->gamma_lut->data;
|
||||
+ unsigned int step, i;
|
||||
+ u32 start, end;
|
||||
+
|
||||
+#define VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl, chan) \
|
||||
+ start = drm_color_lut_extract(lut[i * step].chan, 12); \
|
||||
+ end = drm_color_lut_extract(lut[(i + 1) * step - 1].chan, 12); \
|
||||
+ \
|
||||
+ /* Negative gradients not permitted by the hardware, so \
|
||||
+ * flatten such points out. \
|
||||
+ */ \
|
||||
+ if (end < start) \
|
||||
+ end = start; \
|
||||
+ \
|
||||
+ /* Assume 12bit pipeline. \
|
||||
+ * X evenly spread over full range (12 bit). \
|
||||
+ * C as U12.4 format. \
|
||||
+ * Gradient as U4.8 format. \
|
||||
+ */ \
|
||||
+ vc4_crtc->pwl[i] = \
|
||||
+ VC5_HVS_SET_GAMMA_ENTRY(i << 8, start << 4, \
|
||||
+ ((end - start) << 4) / (step - 1))
|
||||
+
|
||||
+ /* HVS5 has a 16 point piecewise linear function for each colour
|
||||
+ * channel (including alpha on channel 2) on each display channel.
|
||||
+ *
|
||||
+ * Currently take a crude subsample of the gamma LUT, but this could
|
||||
+ * be improved to implement curve fitting.
|
||||
+ */
|
||||
+ step = crtc->gamma_size / SCALER5_DSPGAMMA_NUM_POINTS;
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) {
|
||||
+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_r, red);
|
||||
+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_g, green);
|
||||
+ VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_b, blue);
|
||||
+ }
|
||||
+
|
||||
+ vc5_hvs_lut_load(crtc);
|
||||
+}
|
||||
+
|
||||
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
@@ -329,14 +403,16 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
|
||||
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
|
||||
|
||||
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
|
||||
- SCALER_DISPBKGND_AUTOHS |
|
||||
- ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
|
||||
+ SCALER_DISPBKGND_AUTOHS | SCALER_DISPBKGND_GAMMA |
|
||||
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
|
||||
|
||||
/* Reload the LUT, since the SRAMs would have been disabled if
|
||||
* all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
|
||||
*/
|
||||
- vc4_hvs_lut_load(crtc);
|
||||
+ if (!vc4->hvs->hvs5)
|
||||
+ vc4_hvs_lut_load(crtc);
|
||||
+ else
|
||||
+ vc5_hvs_lut_load(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -534,7 +610,10 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
|
||||
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
|
||||
|
||||
if (crtc->state->gamma_lut) {
|
||||
- vc4_hvs_update_gamma_lut(crtc);
|
||||
+ if (!vc4->hvs->hvs5)
|
||||
+ vc4_hvs_update_gamma_lut(crtc);
|
||||
+ else
|
||||
+ vc5_hvs_update_gamma_lut(crtc);
|
||||
dispbkgndx |= SCALER_DISPBKGND_GAMMA;
|
||||
} else {
|
||||
/* Unsetting DISPBKGND_GAMMA skips the gamma lut step
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
index 7538b84a6dca..5989b2ff28c7 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
@@ -491,6 +491,28 @@
|
||||
#define SCALER_DLIST_START 0x00002000
|
||||
#define SCALER_DLIST_SIZE 0x00004000
|
||||
|
||||
+/* Gamma PWL for each channel. 16 points for each of 4 colour channels (alpha
|
||||
+ * only on channel 2). 8 bytes per entry, offsets first, then gradient:
|
||||
+ * Y = GRAD * X + C
|
||||
+ *
|
||||
+ * Values for X and C are left justified, and vary depending on the width of
|
||||
+ * the HVS channel:
|
||||
+ * 8-bit pipeline: X uses [31:24], C is U8.8 format, and GRAD is U4.8.
|
||||
+ * 12-bit pipeline: X uses [31:20], C is U12.4 format, and GRAD is U4.8.
|
||||
+ *
|
||||
+ * The 3 HVS channels start at 0x400 offsets (ie chan 1 starts at 0x2400, and
|
||||
+ * chan 2 at 0x2800).
|
||||
+ */
|
||||
+#define SCALER5_DSPGAMMA_NUM_POINTS 16
|
||||
+#define SCALER5_DSPGAMMA_START 0x00002000
|
||||
+#define SCALER5_DSPGAMMA_CHAN_OFFSET 0x400
|
||||
+# define SCALER5_DSPGAMMA_OFF_X_MASK VC4_MASK(31, 20)
|
||||
+# define SCALER5_DSPGAMMA_OFF_X_SHIFT 20
|
||||
+# define SCALER5_DSPGAMMA_OFF_C_MASK VC4_MASK(15, 0)
|
||||
+# define SCALER5_DSPGAMMA_OFF_C_SHIFT 0
|
||||
+# define SCALER5_DSPGAMMA_GRAD_MASK VC4_MASK(11, 0)
|
||||
+# define SCALER5_DSPGAMMA_GRAD_SHIFT 0
|
||||
+
|
||||
#define SCALER5_DLIST_START 0x00004000
|
||||
|
||||
# define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
From 07731742ce0c5d4f90d87a475df32165f6dcdfbf Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 28 Apr 2021 12:32:10 +0200
|
||||
Subject: [PATCH 595/634] drm/vc4: Add debugfs node that dumps the vc5 gamma
|
||||
PWL entries
|
||||
|
||||
This helps with debugging the conversion from a 256 point gamma LUT to
|
||||
16 point PWL entries as used by the BCM2711.
|
||||
|
||||
Co-developed-by: Juerg Haefliger <juergh@canonical.com>
|
||||
Signed-off-by: Juerg Haefliger <juergh@canonical.com>
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 81 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 81 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 73751bd6775a..6fbf26e9f113 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -134,6 +134,84 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data)
|
||||
+{
|
||||
+ struct drm_info_node *node = m->private;
|
||||
+ struct drm_device *dev = node->minor->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
+ struct drm_printer p = drm_seq_file_printer(m);
|
||||
+ unsigned int i, chan;
|
||||
+ u32 dispstat, dispbkgndx;
|
||||
+
|
||||
+ for (chan = 0; chan < SCALER_CHANNELS_COUNT; chan++) {
|
||||
+ u32 x_c, grad;
|
||||
+ u32 offset = SCALER5_DSPGAMMA_START +
|
||||
+ chan * SCALER5_DSPGAMMA_CHAN_OFFSET;
|
||||
+
|
||||
+ dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)),
|
||||
+ SCALER_DISPSTATX_MODE);
|
||||
+ if (dispstat == SCALER_DISPSTATX_MODE_DISABLED ||
|
||||
+ dispstat == SCALER_DISPSTATX_MODE_EOF) {
|
||||
+ drm_printf(&p, "HVS channel %u: Channel disabled\n", chan);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
|
||||
+ if (!(dispbkgndx & SCALER_DISPBKGND_GAMMA)) {
|
||||
+ drm_printf(&p, "HVS channel %u: Gamma disabled\n", chan);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ drm_printf(&p, "HVS channel %u:\n", chan);
|
||||
+ drm_printf(&p, " red:\n");
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
+ x_c = HVS_READ(offset);
|
||||
+ grad = HVS_READ(offset + 4);
|
||||
+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
+ x_c, grad,
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
+ grad);
|
||||
+ }
|
||||
+ drm_printf(&p, " green:\n");
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
+ x_c = HVS_READ(offset);
|
||||
+ grad = HVS_READ(offset + 4);
|
||||
+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
+ x_c, grad,
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
+ grad);
|
||||
+ }
|
||||
+ drm_printf(&p, " blue:\n");
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
+ x_c = HVS_READ(offset);
|
||||
+ grad = HVS_READ(offset + 4);
|
||||
+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
+ x_c, grad,
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
+ grad);
|
||||
+ }
|
||||
+
|
||||
+ /* Alpha only valid on channel 2 */
|
||||
+ if (chan != 2)
|
||||
+ continue;
|
||||
+
|
||||
+ drm_printf(&p, " alpha:\n");
|
||||
+ for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) {
|
||||
+ x_c = HVS_READ(offset);
|
||||
+ grad = HVS_READ(offset + 4);
|
||||
+ drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n",
|
||||
+ x_c, grad,
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X),
|
||||
+ VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C),
|
||||
+ grad);
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* The filter kernel is composed of dwords each containing 3 9-bit
|
||||
* signed integers packed next to each other.
|
||||
*/
|
||||
@@ -809,6 +887,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
||||
NULL);
|
||||
vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist,
|
||||
NULL);
|
||||
+ if (hvs->hvs5)
|
||||
+ vc4_debugfs_add_file(drm, "hvs_gamma", vc5_hvs_debugfs_gamma,
|
||||
+ NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
From 6c2da4ae666989c7a534115287b8a587230fea02 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 14 Jun 2021 15:28:30 +0200
|
||||
Subject: [PATCH 596/634] drm/vc4: hvs: Force modeset on gamma lut change
|
||||
|
||||
The HVS Gamma block can only be updated when idle, so we need to disable
|
||||
the HVS channel when the gamma property is set in an atomic commit.
|
||||
|
||||
Since the pixelvalve cannot have its assigned channel halted without
|
||||
stalling unless it's disabled as well, in our case that means forcing a
|
||||
full disable / enable cycle on the pipeline.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 17 +++++++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 3 +++
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 32 +++++++++++++++++++++++++++++++-
|
||||
3 files changed, 51 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e06801557cec..8a081fa0c366 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -294,6 +294,23 @@ struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+#define drm_for_each_connector_mask(connector, dev, connector_mask) \
|
||||
+ list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \
|
||||
+ for_each_if ((connector_mask) & drm_connector_mask(connector))
|
||||
+
|
||||
+struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *state)
|
||||
+{
|
||||
+ struct drm_connector *connector;
|
||||
+
|
||||
+ WARN_ON(hweight32(state->connector_mask) > 1);
|
||||
+
|
||||
+ drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask)
|
||||
+ return connector;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 56d014b91e4e..67a70d38e22e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -568,6 +568,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
return container_of(data, struct vc4_pv_data, base);
|
||||
}
|
||||
|
||||
+struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *state);
|
||||
+
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 6fbf26e9f113..6372c48097d5 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -519,6 +519,36 @@ void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan)
|
||||
SCALER_DISPSTATX_EMPTY);
|
||||
}
|
||||
|
||||
+static int vc4_hvs_gamma_check(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
+ struct drm_connector_state *conn_state;
|
||||
+ struct drm_connector *connector;
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
+
|
||||
+ if (!vc4->hvs->hvs5)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!crtc_state->color_mgmt_changed)
|
||||
+ return 0;
|
||||
+
|
||||
+ connector = vc4_get_crtc_connector(crtc, crtc_state);
|
||||
+ if (!connector)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
|
||||
+ return 0;
|
||||
+
|
||||
+ conn_state = drm_atomic_get_connector_state(state, connector);
|
||||
+ if (!conn_state)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ crtc_state->mode_changed = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
@@ -549,7 +579,7 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return 0;
|
||||
+ return vc4_hvs_gamma_check(crtc, state);
|
||||
}
|
||||
|
||||
static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
From 017a412bded3979956f20d530db0128b772b925d Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:08:08 +0200
|
||||
Subject: [PATCH 598/634] drm/vc4: Relax VEC modeline requirements and add
|
||||
progressive mode support
|
||||
|
||||
Make vc4_vec_encoder_atomic_check() accept arbitrary modelines, as long
|
||||
as they result in somewhat sane output from the VEC. The bounds have
|
||||
been determined empirically. Additionally, add support for the
|
||||
progressive 262-line and 312-line modes.
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 1 +
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 97 ++++++++++++++++++++++++++++------
|
||||
2 files changed, 83 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 8a081fa0c366..65c53a10ed6d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -410,6 +410,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
|
||||
CRTC_WRITE(PV_V_CONTROL,
|
||||
PV_VCONTROL_CONTINUOUS |
|
||||
(is_dsi ? PV_VCONTROL_DSI : 0));
|
||||
+ CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||||
}
|
||||
|
||||
CRTC_WRITE(PV_VERTA,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index b684595a5d0b..661fac65b8a8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -423,18 +423,11 @@ static int vc4_vec_connector_atomic_check(struct drm_connector *conn,
|
||||
struct drm_connector_state *new_state =
|
||||
drm_atomic_get_new_connector_state(state, conn);
|
||||
|
||||
- const struct vc4_vec_tv_mode *vec_mode =
|
||||
- &vc4_vec_tv_modes[new_state->tv.mode];
|
||||
-
|
||||
- if (new_state->crtc) {
|
||||
+ if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) {
|
||||
struct drm_crtc_state *crtc_state =
|
||||
drm_atomic_get_new_crtc_state(state, new_state->crtc);
|
||||
|
||||
- if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
|
||||
- return -EINVAL;
|
||||
-
|
||||
- if (old_state->tv.mode != new_state->tv.mode)
|
||||
- crtc_state->mode_changed = true;
|
||||
+ crtc_state->mode_changed = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -559,7 +552,10 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
VEC_WRITE(VEC_CLMP0_START, 0xac);
|
||||
VEC_WRITE(VEC_CLMP0_END, 0xec);
|
||||
VEC_WRITE(VEC_CONFIG2,
|
||||
- VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
|
||||
+ VEC_CONFIG2_UV_DIG_DIS |
|
||||
+ VEC_CONFIG2_RGB_DIG_DIS |
|
||||
+ ((encoder->crtc->state->adjusted_mode.flags &
|
||||
+ DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
|
||||
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
|
||||
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
|
||||
|
||||
@@ -582,17 +578,88 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
|
||||
-static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
- const struct drm_display_mode *mode,
|
||||
- struct drm_display_mode *adjusted_mode)
|
||||
+static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
{
|
||||
- return true;
|
||||
+ const struct drm_display_mode *reference_mode =
|
||||
+ vc4_vec_tv_modes[conn_state->tv.mode].mode;
|
||||
+
|
||||
+ if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
|
||||
+ crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
|
||||
+ crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 ||
|
||||
+ crtc_state->adjusted_mode.crtc_hsync_end -
|
||||
+ crtc_state->adjusted_mode.crtc_hsync_start < 1)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ switch (reference_mode->vtotal) {
|
||||
+ case 525:
|
||||
+ if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vdisplay > 253 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_start -
|
||||
+ crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_end -
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal -
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_end < 4 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal > 262)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((crtc_state->adjusted_mode.flags &
|
||||
+ DRM_MODE_FLAG_INTERLACE) &&
|
||||
+ (crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
|
||||
+ crtc_state->adjusted_mode.vsync_start % 2 != 1 ||
|
||||
+ crtc_state->adjusted_mode.vsync_end % 2 != 1 ||
|
||||
+ crtc_state->adjusted_mode.vtotal % 2 != 1))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* progressive mode is hard-wired to 262 total lines */
|
||||
+ if (!(crtc_state->adjusted_mode.flags &
|
||||
+ DRM_MODE_FLAG_INTERLACE) &&
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal != 262)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ case 625:
|
||||
+ if (crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vdisplay > 305 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_start -
|
||||
+ crtc_state->adjusted_mode.crtc_vdisplay < 1 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_end -
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_start != 3 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal -
|
||||
+ crtc_state->adjusted_mode.crtc_vsync_end < 2 ||
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal > 312)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((crtc_state->adjusted_mode.flags &
|
||||
+ DRM_MODE_FLAG_INTERLACE) &&
|
||||
+ (crtc_state->adjusted_mode.vdisplay % 2 != 0 ||
|
||||
+ crtc_state->adjusted_mode.vsync_start % 2 != 0 ||
|
||||
+ crtc_state->adjusted_mode.vsync_end % 2 != 0 ||
|
||||
+ crtc_state->adjusted_mode.vtotal % 2 != 1))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* progressive mode is hard-wired to 312 total lines */
|
||||
+ if (!(crtc_state->adjusted_mode.flags &
|
||||
+ DRM_MODE_FLAG_INTERLACE) &&
|
||||
+ crtc_state->adjusted_mode.crtc_vtotal != 312)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
|
||||
.disable = vc4_vec_encoder_disable,
|
||||
.enable = vc4_vec_encoder_enable,
|
||||
- .mode_fixup = vc4_vec_encoder_mode_fixup,
|
||||
+ .atomic_check = vc4_vec_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct vc4_vec_variant bcm2835_vec_variant = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
From 4bcf5e8ac14bf77216868a165cac0a414d0d5687 Mon Sep 17 00:00:00 2001
|
||||
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
Date: Thu, 15 Jul 2021 01:08:11 +0200
|
||||
Subject: [PATCH 599/634] drm/vc4: Make VEC progressive modes readily
|
||||
accessible
|
||||
|
||||
Add predefined modelines for the 240p (NTSC) and 288p (PAL) progressive
|
||||
modes, and report them through vc4_vec_connector_get_modes().
|
||||
|
||||
Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_vec.c | 73 ++++++++++++++++++++++++++---------
|
||||
1 file changed, 55 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
index 661fac65b8a8..d263fdaa1ee8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
|
||||
@@ -245,7 +245,8 @@ enum vc4_vec_tv_mode_id {
|
||||
};
|
||||
|
||||
struct vc4_vec_tv_mode {
|
||||
- const struct drm_display_mode *mode;
|
||||
+ const struct drm_display_mode *interlaced_mode;
|
||||
+ const struct drm_display_mode *progressive_mode;
|
||||
u32 config0;
|
||||
u32 config1;
|
||||
u32 custom_freq;
|
||||
@@ -279,61 +280,81 @@ static const struct debugfs_reg32 vec_regs[] = {
|
||||
};
|
||||
|
||||
static const struct drm_display_mode drm_mode_480i = {
|
||||
- DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
+ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
480, 480 + 7, 480 + 7 + 6, 525, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
+static const struct drm_display_mode drm_mode_240p = {
|
||||
+ DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
+ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
|
||||
+ 240, 240 + 3, 240 + 3 + 3, 262, 0, 0)
|
||||
+};
|
||||
+
|
||||
static const struct drm_display_mode drm_mode_576i = {
|
||||
- DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
+ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
576, 576 + 4, 576 + 4 + 6, 625, 0,
|
||||
DRM_MODE_FLAG_INTERLACE)
|
||||
};
|
||||
|
||||
+static const struct drm_display_mode drm_mode_288p = {
|
||||
+ DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500,
|
||||
+ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
|
||||
+ 288, 288 + 2, 288 + 2 + 3, 312, 0, 0)
|
||||
+};
|
||||
+
|
||||
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
|
||||
[VC4_VEC_TV_MODE_NTSC] = {
|
||||
- .mode = &drm_mode_480i,
|
||||
+ .interlaced_mode = &drm_mode_480i,
|
||||
+ .progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_J] = {
|
||||
- .mode = &drm_mode_480i,
|
||||
+ .interlaced_mode = &drm_mode_480i,
|
||||
+ .progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_NTSC_443] = {
|
||||
/* NTSC with PAL chroma frequency */
|
||||
- .mode = &drm_mode_480i,
|
||||
+ .interlaced_mode = &drm_mode_480i,
|
||||
+ .progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_NTSC_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
.custom_freq = 0x2a098acb,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL] = {
|
||||
- .mode = &drm_mode_576i,
|
||||
+ .interlaced_mode = &drm_mode_576i,
|
||||
+ .progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_M] = {
|
||||
- .mode = &drm_mode_480i,
|
||||
+ .interlaced_mode = &drm_mode_480i,
|
||||
+ .progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL_N] = {
|
||||
- .mode = &drm_mode_576i,
|
||||
+ .interlaced_mode = &drm_mode_576i,
|
||||
+ .progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_PAL_N_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_PAL60] = {
|
||||
/* PAL-M with chroma frequency of regular PAL */
|
||||
- .mode = &drm_mode_480i,
|
||||
+ .interlaced_mode = &drm_mode_480i,
|
||||
+ .progressive_mode = &drm_mode_240p,
|
||||
.config0 = VEC_CONFIG0_PAL_M_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
|
||||
.custom_freq = 0x2a098acb,
|
||||
},
|
||||
[VC4_VEC_TV_MODE_SECAM] = {
|
||||
- .mode = &drm_mode_576i,
|
||||
+ .interlaced_mode = &drm_mode_576i,
|
||||
+ .progressive_mode = &drm_mode_288p,
|
||||
.config0 = VEC_CONFIG0_SECAM_STD,
|
||||
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
|
||||
.custom_freq = 0x29c71c72,
|
||||
@@ -393,16 +414,32 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector)
|
||||
static int vc4_vec_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_connector_state *state = connector->state;
|
||||
- struct drm_display_mode *mode;
|
||||
-
|
||||
- mode = drm_mode_duplicate(connector->dev,
|
||||
- vc4_vec_tv_modes[state->tv.mode].mode);
|
||||
- if (!mode) {
|
||||
+ struct drm_display_mode *interlaced_mode, *progressive_mode;
|
||||
+
|
||||
+ interlaced_mode =
|
||||
+ drm_mode_duplicate(connector->dev,
|
||||
+ vc4_vec_tv_modes[state->tv.mode].interlaced_mode);
|
||||
+ progressive_mode =
|
||||
+ drm_mode_duplicate(connector->dev,
|
||||
+ vc4_vec_tv_modes[state->tv.mode].progressive_mode);
|
||||
+ if (!interlaced_mode || !progressive_mode) {
|
||||
DRM_ERROR("Failed to create a new display mode\n");
|
||||
+ drm_mode_destroy(connector->dev, interlaced_mode);
|
||||
+ drm_mode_destroy(connector->dev, progressive_mode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- drm_mode_probed_add(connector, mode);
|
||||
+ if (connector->cmdline_mode.specified &&
|
||||
+ connector->cmdline_mode.refresh_specified &&
|
||||
+ !connector->cmdline_mode.interlace)
|
||||
+ /* progressive mode set at boot, let's make it preferred */
|
||||
+ progressive_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
+ else
|
||||
+ /* otherwise, interlaced mode is preferred */
|
||||
+ interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
+
|
||||
+ drm_mode_probed_add(connector, interlaced_mode);
|
||||
+ drm_mode_probed_add(connector, progressive_mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -583,7 +620,7 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
const struct drm_display_mode *reference_mode =
|
||||
- vc4_vec_tv_modes[conn_state->tv.mode].mode;
|
||||
+ vc4_vec_tv_modes[conn_state->tv.mode].interlaced_mode;
|
||||
|
||||
if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock ||
|
||||
crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal ||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
From 34b3c67f34338cbdf08d927dbbedbb9074bb072d Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 27 Aug 2021 18:20:25 +0200
|
||||
Subject: [PATCH 610/634] drm/vc4: kms: Add missing drm_crtc_commit_put
|
||||
|
||||
Commit 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a
|
||||
commit") introduced a global state for the HVS, with each FIFO storing
|
||||
the current CRTC commit so that we can properly synchronize commits.
|
||||
|
||||
However, the refcounting was off and we thus ended up leaking the
|
||||
drm_crtc_commit structure every commit. Add a drm_crtc_commit_put to
|
||||
prevent the leakage.
|
||||
|
||||
Fixes: 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a commit")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 2511113a6f82..8c63b962b2e6 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -389,6 +389,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
ret = drm_crtc_commit_wait(commit);
|
||||
if (ret)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
+
|
||||
+ drm_crtc_commit_put(commit);
|
||||
}
|
||||
|
||||
if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
From e77ab08dffd64552b5f22ec0ba2d9cf371475883 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 20 Oct 2021 13:31:22 +0200
|
||||
Subject: [PATCH 611/634] drm/vc4: kms: Fix return code check
|
||||
|
||||
The HVS global state functions return an error pointer, but in most
|
||||
cases we check if it's NULL, possibly resulting in an invalid pointer
|
||||
dereference.
|
||||
|
||||
Fixes: 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a commit")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 8c63b962b2e6..82462d4c4853 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -352,11 +352,11 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
int i;
|
||||
|
||||
old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
- if (WARN_ON(!old_hvs_state))
|
||||
+ if (WARN_ON(IS_ERR(old_hvs_state)))
|
||||
return;
|
||||
|
||||
new_hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
- if (WARN_ON(!new_hvs_state))
|
||||
+ if (WARN_ON(IS_ERR(new_hvs_state)))
|
||||
return;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||
@@ -470,8 +470,8 @@ static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
|
||||
state->legacy_cursor_update = false;
|
||||
|
||||
hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
- if (!hvs_state)
|
||||
- return -EINVAL;
|
||||
+ if (WARN_ON(IS_ERR(hvs_state)))
|
||||
+ return PTR_ERR(hvs_state);
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
@@ -816,8 +816,8 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
|
||||
unsigned int i;
|
||||
|
||||
hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
- if (!hvs_new_state)
|
||||
- return -EINVAL;
|
||||
+ if (IS_ERR(hvs_new_state))
|
||||
+ return PTR_ERR(hvs_new_state);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hvs_new_state->fifo_state); i++)
|
||||
if (!hvs_new_state->fifo_state[i].in_use)
|
||||
@@ -909,8 +909,8 @@ vc4_core_clock_atomic_check(struct drm_atomic_state *state)
|
||||
load_state = to_vc4_load_tracker_state(priv_state);
|
||||
|
||||
hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
- if (!hvs_new_state)
|
||||
- return -EINVAL;
|
||||
+ if (IS_ERR(hvs_new_state))
|
||||
+ return PTR_ERR(hvs_new_state);
|
||||
|
||||
for_each_oldnew_crtc_in_state(state, crtc,
|
||||
old_crtc_state,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
From 1adf064f5c8a44ae56bc609a7648f384363a3df4 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 21 Oct 2021 13:57:25 +0200
|
||||
Subject: [PATCH 612/634] drm/vc4: kms: Clear the HVS FIFO commit pointer once
|
||||
done
|
||||
|
||||
Commit 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a
|
||||
commit") introduced a wait on the previous commit done on a given HVS
|
||||
FIFO.
|
||||
|
||||
However, we never cleared that pointer once done. Since
|
||||
drm_crtc_commit_put can free the drm_crtc_commit structure directly if
|
||||
we were the last user, this means that it can lead to a use-after free
|
||||
if we were to duplicate the state, and that stale pointer would even be
|
||||
copied to the new state.
|
||||
|
||||
Set the pointer to NULL once we're done with the wait so that we don't
|
||||
carry over a pointer to a free'd structure.
|
||||
|
||||
Fixes: 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a commit")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 82462d4c4853..59f10c4d76ae 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -391,6 +391,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_err(dev, "Timed out waiting for commit\n");
|
||||
|
||||
drm_crtc_commit_put(commit);
|
||||
+ old_hvs_state->fifo_state[channel].pending_commit = NULL;
|
||||
}
|
||||
|
||||
if (vc4->hvs && vc4->hvs->hvs5) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
From ff06c5211fc9921c45ed2fe23f43ff2e8656c402 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 21 Oct 2021 13:57:44 +0200
|
||||
Subject: [PATCH 613/634] drm/vc4: kms: Don't duplicate pending commit
|
||||
|
||||
Our HVS global state, when duplicated, will also copy the pointer to the
|
||||
drm_crtc_commit (and increase the reference count) for each FIFO if the
|
||||
pointer is not NULL.
|
||||
|
||||
However, our atomic_setup function will overwrite that pointer without
|
||||
putting the reference back leading to a memory leak.
|
||||
|
||||
Since the commit is only relevant during the atomic commit process, it
|
||||
doesn't make sense to duplicate the reference to the commit anyway.
|
||||
Let's remove it.
|
||||
|
||||
Fixes: 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a commit")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 6 ------
|
||||
1 file changed, 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 59f10c4d76ae..2ac6c7c66fc2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -720,12 +720,6 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
|
||||
state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
|
||||
-
|
||||
- if (!old_state->fifo_state[i].pending_commit)
|
||||
- continue;
|
||||
-
|
||||
- state->fifo_state[i].pending_commit =
|
||||
- drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
|
||||
}
|
||||
|
||||
state->core_clock_rate = old_state->core_clock_rate;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
From dd7d827b5466f4820a477484c25a28a309d43b20 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 5 Nov 2021 10:51:25 +0100
|
||||
Subject: [PATCH 614/634] drm/vc4: kms: Fix previous HVS commit wait
|
||||
|
||||
Our current code is supposed to serialise the commits by waiting for all
|
||||
the drm_crtc_commits associated to the previous HVS state.
|
||||
|
||||
However, assuming we have two CRTCs running and being configured and we
|
||||
configure each one alternatively, we end up in a situation where we're
|
||||
not waiting at all.
|
||||
|
||||
Indeed, starting with a state (state 0) where both CRTCs are running,
|
||||
and doing a commit (state 1) on the first CRTC (CRTC 0), we'll associate
|
||||
its commit to its assigned FIFO in vc4_hvs_state.
|
||||
|
||||
If we get a new commit (state 2), this time affecting the second CRTC
|
||||
(CRTC 1), the DRM core will allow both commits to execute in parallel
|
||||
(assuming they don't have any share resources).
|
||||
|
||||
Our code in vc4_atomic_commit_tail is supposed to make sure we only get
|
||||
one commit at a time and serialised by order of submission. It does so
|
||||
by using for_each_old_crtc_in_state, making sure that the CRTC has a
|
||||
FIFO assigned, is used, and has a commit pending. If it does, then we'll
|
||||
wait for the commit before going forward.
|
||||
|
||||
During the transition from state 0 to state 1, as our old CRTC state we
|
||||
get the CRTC 0 state 0, its commit, we wait for it, everything works fine.
|
||||
|
||||
During the transition from state 1 to state 2 though, the use of
|
||||
for_each_old_crtc_in_state is wrong. Indeed, while the code assumes it's
|
||||
returning the state of the CRTC in the old state (so CRTC 0 state 1), it
|
||||
actually returns the old state of the CRTC affected by the current
|
||||
commit, so CRTC 0 state 0 since it wasn't part of state 1.
|
||||
|
||||
Due to this, if we alternate between the configuration of CRTC 0 and
|
||||
CRTC 1, we never actually wait for anything since we should be waiting
|
||||
on the other every time, but it never is affected by the previous
|
||||
commit.
|
||||
|
||||
Change the logic to, at every commit, look at every FIFO in the previous
|
||||
HVS state, and if it's in use and has a commit associated to it, wait
|
||||
for that commit.
|
||||
|
||||
Fixes: 9ec03d7f1ed3 ("drm/vc4: kms: Wait on previous FIFO users before a commit")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 10 ++--------
|
||||
1 file changed, 2 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 2ac6c7c66fc2..2721a0f61dc0 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -343,12 +343,12 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
struct drm_device *dev = state->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_hvs *hvs = vc4->hvs;
|
||||
- struct drm_crtc_state *old_crtc_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct vc4_hvs_state *new_hvs_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct vc4_hvs_state *old_hvs_state;
|
||||
struct clk_request *core_req;
|
||||
+ unsigned int channel;
|
||||
int i;
|
||||
|
||||
old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
@@ -369,16 +369,10 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
|
||||
}
|
||||
|
||||
- for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
- struct vc4_crtc_state *vc4_crtc_state =
|
||||
- to_vc4_crtc_state(old_crtc_state);
|
||||
+ for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
|
||||
struct drm_crtc_commit *commit;
|
||||
- unsigned int channel = vc4_crtc_state->assigned_channel;
|
||||
int ret;
|
||||
|
||||
- if (channel == VC4_HVS_CHANNEL_DISABLED)
|
||||
- continue;
|
||||
-
|
||||
if (!old_hvs_state->fifo_state[channel].in_use)
|
||||
continue;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
From fec8348360a6326272064885cfe94b2695f94864 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 4 Nov 2021 14:04:37 +0100
|
||||
Subject: [PATCH 615/634] drm/vc4: kms: Move clock request to our HVS state
|
||||
|
||||
Our current clock request has been stored so far on the main HVS
|
||||
structure, but even though we shouldn't have two commits in parallel and
|
||||
it shouldn't cause any functional change, the request itself is linked
|
||||
to a given HVS state.
|
||||
|
||||
Move the request there to make a bit more sense.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 1 -
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 8 +++++---
|
||||
2 files changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 67a70d38e22e..81bca15b31e2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -326,7 +326,6 @@ struct vc4_hvs {
|
||||
u32 __iomem *dlist;
|
||||
|
||||
struct clk *core_clk;
|
||||
- struct clk_request *core_req;
|
||||
|
||||
/* Memory manager for CRTCs to allocate space in the display
|
||||
* list. Units are dwords.
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 2721a0f61dc0..77c2a7ce5ef6 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -40,6 +40,7 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
|
||||
struct vc4_hvs_state {
|
||||
struct drm_private_state base;
|
||||
unsigned long core_clock_rate;
|
||||
+ struct clk_request *core_req;
|
||||
|
||||
struct {
|
||||
unsigned in_use: 1;
|
||||
@@ -405,7 +406,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
* And remove the previous one based on the HVS
|
||||
* requirements if any.
|
||||
*/
|
||||
- clk_request_done(hvs->core_req);
|
||||
+ clk_request_done(old_hvs_state->core_req);
|
||||
+ old_hvs_state->core_req = NULL;
|
||||
}
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, state);
|
||||
@@ -439,8 +441,8 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
* Request a clock rate based on the current HVS
|
||||
* requirements.
|
||||
*/
|
||||
- hvs->core_req = clk_request_start(hvs->core_clk,
|
||||
- new_hvs_state->core_clock_rate);
|
||||
+ new_hvs_state->core_req = clk_request_start(hvs->core_clk,
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
|
||||
/* And drop the temporary request */
|
||||
clk_request_done(core_req);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
From cc93e4c6e01d1274e1e241d45265bb88405697c1 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 8 Nov 2021 17:32:45 +0000
|
||||
Subject: [PATCH 625/634] drm/vc4: Enable gamma block only when required.
|
||||
|
||||
With HVS5 the gamma block is now only reprogrammed with
|
||||
a disable/enable. Loading the table from vc4_hvs_init_channel
|
||||
(called from vc4_hvs_atomic_enable) appears to be at an
|
||||
invalid point in time and so isn't applied.
|
||||
|
||||
Switch to enabling and disabling the gamma table instead. This
|
||||
isn't safe if the pipeline is running, but it isn't now.
|
||||
For HVS4 it is safe to enable and disable dynamically, so
|
||||
adopt that approach there too.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 22 +++++++++++++++++-----
|
||||
1 file changed, 17 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 6372c48097d5..1302260d7d87 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -480,8 +480,12 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
|
||||
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
|
||||
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
|
||||
|
||||
+ if (crtc->state->gamma_lut)
|
||||
+ /* Enable gamma on if required */
|
||||
+ dispbkgndx |= SCALER_DISPBKGND_GAMMA;
|
||||
+
|
||||
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
|
||||
- SCALER_DISPBKGND_AUTOHS | SCALER_DISPBKGND_GAMMA |
|
||||
+ SCALER_DISPBKGND_AUTOHS |
|
||||
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
|
||||
|
||||
/* Reload the LUT, since the SRAMs would have been disabled if
|
||||
@@ -718,17 +722,25 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
|
||||
u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
|
||||
|
||||
if (crtc->state->gamma_lut) {
|
||||
- if (!vc4->hvs->hvs5)
|
||||
+ if (!vc4->hvs->hvs5) {
|
||||
vc4_hvs_update_gamma_lut(crtc);
|
||||
- else
|
||||
+ dispbkgndx |= SCALER_DISPBKGND_GAMMA;
|
||||
+ } else {
|
||||
vc5_hvs_update_gamma_lut(crtc);
|
||||
- dispbkgndx |= SCALER_DISPBKGND_GAMMA;
|
||||
+ }
|
||||
} else {
|
||||
/* Unsetting DISPBKGND_GAMMA skips the gamma lut step
|
||||
* in hardware, which is the same as a linear lut that
|
||||
* DRM expects us to use in absence of a user lut.
|
||||
+ *
|
||||
+ * Do NOT change state dynamically for hvs5 as it
|
||||
+ * inserts a delay in the pipeline that will cause
|
||||
+ * stalls if enabled/disabled whilst running. The other
|
||||
+ * should already be disabling/enabling the pipeline
|
||||
+ * when gamma changes.
|
||||
*/
|
||||
- dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
|
||||
+ if (!vc4->hvs->hvs5)
|
||||
+ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
|
||||
}
|
||||
HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
From 35b77f70d93442750a907586fd1cf7b28331061a Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Mon, 8 Nov 2021 18:25:49 +0000
|
||||
Subject: [PATCH 626/634] drm/vc4: Only add gamma properties once.
|
||||
|
||||
Two calls were made to drm_crtc_enable_color_mgmt to add gamma
|
||||
and CTM, however they were both set to add the gamma properties,
|
||||
so they ended up added twice.
|
||||
|
||||
Fixes: 766cc6b1f7fc "drm/vc4: Add CTM support"
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 65c53a10ed6d..cf4dcf8ef433 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -1194,7 +1194,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
|
||||
/* We support CTM, but only for one CRTC at a time. It's therefore
|
||||
* implemented as private driver state in vc4_kms, not here.
|
||||
*/
|
||||
- drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size);
|
||||
+ drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
|
||||
|
||||
/* Initialize the VC4 gamma LUTs */
|
||||
for (i = 0; i < crtc->gamma_size; i++) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From a528d57967f93fb0ae67e5e6a57074805d926928 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 10 Nov 2021 16:36:12 +0000
|
||||
Subject: [PATCH 628/634] drm/vc4: Validate the size of the gamma_lut
|
||||
|
||||
Add a check to vc4_hvs_gamma_check to ensure a new non-empty
|
||||
gamma LUT is of the correct length before accepting it.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 1302260d7d87..a873d9d8fd58 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -538,6 +538,16 @@ static int vc4_hvs_gamma_check(struct drm_crtc *crtc,
|
||||
if (!crtc_state->color_mgmt_changed)
|
||||
return 0;
|
||||
|
||||
+ if (crtc_state->gamma_lut) {
|
||||
+ unsigned int len = drm_color_lut_size(crtc_state->gamma_lut);
|
||||
+
|
||||
+ if (len != crtc->gamma_size) {
|
||||
+ DRM_DEBUG_KMS("Invalid LUT size; got %u, expected %u\n",
|
||||
+ len, crtc->gamma_size);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
connector = vc4_get_crtc_connector(crtc, crtc_state);
|
||||
if (!connector)
|
||||
return -EINVAL;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
From 7de6460aef7e0122b110b5ef38513fdea630c18c Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Tue, 16 Nov 2021 10:34:34 +0000
|
||||
Subject: [PATCH 629/634] drm/vc4: Don't try disabling SCDC on Pi0-3.
|
||||
|
||||
The code that set the scdc_enabled flag to ensure it was
|
||||
disabled at boot time also ran on Pi0-3 where there is no
|
||||
SCDC support. This lead to a warning in vc4_hdmi_encoder_post_crtc_disable
|
||||
due to vc4_hdmi_disable_scrambling being called and trying to
|
||||
read (and write) register HDMI_SCRAMBLER_CTL which doesn't
|
||||
exist on those platforms.
|
||||
|
||||
Only set the flag should the interface be configured to support
|
||||
more than HDMI 1.4.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index a6afd7d7f21c..70a1beb67dda 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -2557,7 +2557,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
* vc4_hdmi_disable_scrambling() will thus run at boot, make
|
||||
* sure it's disabled, and avoid any inconsistency.
|
||||
*/
|
||||
- vc4_hdmi->scdc_enabled = true;
|
||||
+ if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
|
||||
+ vc4_hdmi->scdc_enabled = true;
|
||||
|
||||
ret = variant->init_resources(vc4_hdmi);
|
||||
if (ret)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
From 58b75a603967b8de888949220993bafd65fcca60 Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Tue, 26 Oct 2021 06:49:54 +0100
|
||||
Subject: [PATCH 631/634] media: v4l2-core: fix VIDIOC_DQEVENT handling on
|
||||
non-x86
|
||||
|
||||
My previous bugfix addressed an API inconsistency found by syzbot,
|
||||
and it correctly fixed the issue on x86-64 machines, which now behave
|
||||
correctly for both native and compat tasks.
|
||||
|
||||
Unfortunately, John found that the patch broke compat mode on all other
|
||||
architectures, as they can no longer rely on the VIDIOC_DQEVENT_TIME32
|
||||
code from the native handler as a fallback in the compat code.
|
||||
|
||||
The best way I can see for addressing this is to generalize the
|
||||
VIDIOC_DQEVENT32_TIME32 code from x86 and use that for all architectures,
|
||||
leaving only the VIDIOC_DQEVENT32 variant as x86 specific. The original
|
||||
code was trying to be clever and use the same conversion helper for native
|
||||
32-bit code and compat mode, but that turned out to be too obscure so
|
||||
even I missed that bit I had introduced myself when I made the fix.
|
||||
|
||||
Fixes: c344f07aa1b4 ("media: v4l2-core: ignore native time32 ioctls on 64-bit")
|
||||
Reported-by: John Stultz <john.stultz@linaro.org>
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Tested-by: John Stultz <john.stultz@linaro.org>
|
||||
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
|
||||
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 41 ++++++++-----------
|
||||
1 file changed, 17 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
||||
index 47aff3b19742..80aaf07b16f2 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
||||
@@ -744,10 +744,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
|
||||
/*
|
||||
* x86 is the only compat architecture with different struct alignment
|
||||
* between 32-bit and 64-bit tasks.
|
||||
- *
|
||||
- * On all other architectures, v4l2_event32 and v4l2_event32_time32 are
|
||||
- * the same as v4l2_event and v4l2_event_time32, so we can use the native
|
||||
- * handlers, converting v4l2_event to v4l2_event_time32 if necessary.
|
||||
*/
|
||||
struct v4l2_event32 {
|
||||
__u32 type;
|
||||
@@ -765,21 +761,6 @@ struct v4l2_event32 {
|
||||
__u32 reserved[8];
|
||||
};
|
||||
|
||||
-#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
-struct v4l2_event32_time32 {
|
||||
- __u32 type;
|
||||
- union {
|
||||
- compat_s64 value64;
|
||||
- __u8 data[64];
|
||||
- } u;
|
||||
- __u32 pending;
|
||||
- __u32 sequence;
|
||||
- struct old_timespec32 timestamp;
|
||||
- __u32 id;
|
||||
- __u32 reserved[8];
|
||||
-};
|
||||
-#endif
|
||||
-
|
||||
static int put_v4l2_event32(struct v4l2_event *p64,
|
||||
struct v4l2_event32 __user *p32)
|
||||
{
|
||||
@@ -795,7 +776,22 @@ static int put_v4l2_event32(struct v4l2_event *p64,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
+struct v4l2_event32_time32 {
|
||||
+ __u32 type;
|
||||
+ union {
|
||||
+ compat_s64 value64;
|
||||
+ __u8 data[64];
|
||||
+ } u;
|
||||
+ __u32 pending;
|
||||
+ __u32 sequence;
|
||||
+ struct old_timespec32 timestamp;
|
||||
+ __u32 id;
|
||||
+ __u32 reserved[8];
|
||||
+};
|
||||
+
|
||||
static int put_v4l2_event32_time32(struct v4l2_event *p64,
|
||||
struct v4l2_event32_time32 __user *p32)
|
||||
{
|
||||
@@ -811,7 +807,6 @@ static int put_v4l2_event32_time32(struct v4l2_event *p64,
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
-#endif
|
||||
|
||||
struct v4l2_edid32 {
|
||||
__u32 pad;
|
||||
@@ -873,9 +868,7 @@ static int put_v4l2_edid32(struct v4l2_edid *p64,
|
||||
#define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32)
|
||||
#define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32)
|
||||
#define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32)
|
||||
-#ifdef CONFIG_X86_64
|
||||
#define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32)
|
||||
-#endif
|
||||
#define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32)
|
||||
#endif
|
||||
|
||||
@@ -929,10 +922,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
|
||||
#ifdef CONFIG_X86_64
|
||||
case VIDIOC_DQEVENT32:
|
||||
return VIDIOC_DQEVENT;
|
||||
+#endif
|
||||
#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
case VIDIOC_DQEVENT32_TIME32:
|
||||
return VIDIOC_DQEVENT;
|
||||
-#endif
|
||||
#endif
|
||||
}
|
||||
return cmd;
|
||||
@@ -1025,10 +1018,10 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
|
||||
#ifdef CONFIG_X86_64
|
||||
case VIDIOC_DQEVENT32:
|
||||
return put_v4l2_event32(parg, arg);
|
||||
+#endif
|
||||
#ifdef CONFIG_COMPAT_32BIT_TIME
|
||||
case VIDIOC_DQEVENT32_TIME32:
|
||||
return put_v4l2_event32_time32(parg, arg);
|
||||
-#endif
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
--
|
||||
2.33.1
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue