aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch459
1 files changed, 0 insertions, 459 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch b/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch
deleted file mode 100644
index d470f3b7f0..0000000000
--- a/target/linux/bcm27xx/patches-5.4/950-0555-drm-vc4-crtc-Assign-output-to-channel-automatically.patch
+++ /dev/null
@@ -1,459 +0,0 @@
-From 9efecb2ccd14a6d226ba2afa04f6e70b96026b3e Mon Sep 17 00:00:00 2001
-From: Maxime Ripard <maxime@cerno.tech>
-Date: Thu, 26 Dec 2019 17:53:18 +0100
-Subject: [PATCH] drm/vc4: crtc: Assign output to channel automatically
-
-The HVS found in the BCM2711 has 6 outputs and 3 FIFOs, with each output
-being connected to a pixelvalve, and some muxing between the FIFOs and
-outputs.
-
-Any output cannot feed from any FIFO though, and they all have a bunch of
-constraints.
-
-In order to support this, let's store the possible FIFOs each output can be
-assigned to in the vc4_crtc_data, and use that information at atomic_check
-time to iterate over all the CRTCs enabled and assign them FIFOs.
-
-The channel assigned is then set in the vc4_crtc_state so that the rest of
-the driver can use it.
-
-Signed-off-by: Maxime Ripard <maxime@cerno.tech>
----
- drivers/gpu/drm/vc4/vc4_crtc.c | 37 +++++----
- drivers/gpu/drm/vc4/vc4_drv.h | 7 +-
- drivers/gpu/drm/vc4/vc4_kms.c | 146 +++++++++++++++++++++++++++++++--
- drivers/gpu/drm/vc4/vc4_regs.h | 10 +++
- 4 files changed, 175 insertions(+), 25 deletions(-)
-
---- a/drivers/gpu/drm/vc4/vc4_crtc.c
-+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
-@@ -90,6 +90,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct drm_crtc *crtc = drm_crtc_from_index(dev, crtc_id);
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
- unsigned int cob_size;
- u32 val;
- int fifo_lines;
-@@ -106,7 +107,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- * Read vertical scanline which is currently composed for our
- * pixelvalve by the HVS, and also the scaler status.
- */
-- val = HVS_READ(SCALER_DISPSTATX(vc4_crtc->channel));
-+ val = HVS_READ(SCALER_DISPSTATX(vc4_crtc_state->assigned_channel));
-
- /* Get optional system timestamp after query. */
- if (etime)
-@@ -126,7 +127,7 @@ bool vc4_crtc_get_scanoutpos(struct drm_
- *hpos += mode->crtc_htotal / 2;
- }
-
-- cob_size = vc4_crtc_get_cob_allocation(vc4_crtc, vc4_crtc->channel);
-+ cob_size = vc4_crtc_get_cob_allocation(vc4_crtc, vc4_crtc_state->assigned_channel);
- /* This is the offset we need for translating hvs -> pv scanout pos. */
- fifo_lines = cob_size / mode->crtc_hdisplay;
-
-@@ -213,6 +214,7 @@ vc4_crtc_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_crtc_state = to_vc4_crtc_state(crtc->state);
- u32 i;
-
- /* The LUT memory is laid out with each HVS channel in order,
-@@ -221,7 +223,7 @@ vc4_crtc_lut_load(struct drm_crtc *crtc)
- */
- HVS_WRITE(SCALER_GAMADDR,
- SCALER_GAMADDR_AUTOINC |
-- (vc4_crtc->channel * 3 * crtc->gamma_size));
-+ (vc4_crtc_state->assigned_channel * 3 * crtc->gamma_size));
-
- for (i = 0; i < crtc->gamma_size; i++)
- HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]);
-@@ -394,7 +396,7 @@ static void vc4_crtc_mode_set_nofb(struc
- drm_print_regset32(&p, &vc4_crtc->regset);
- }
-
-- if (vc4_crtc->channel == 2) {
-+ if (vc4_crtc->data->hvs_output == 2) {
- u32 dispctrl;
- u32 dsp3_mux;
-
-@@ -421,7 +423,7 @@ static void vc4_crtc_mode_set_nofb(struc
- if (!vc4_state->feed_txp)
- vc4_crtc_config_pv(crtc);
-
-- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
-+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
- SCALER_DISPBKGND_AUTOHS |
- SCALER_DISPBKGND_GAMMA |
- (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
-@@ -453,7 +455,8 @@ static void vc4_crtc_atomic_disable(stru
- struct drm_device *dev = crtc->dev;
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-- u32 chan = vc4_crtc->channel;
-+ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(old_state);
-+ u32 chan = vc4_crtc_state->assigned_channel;
- int ret;
- require_hvs_enabled(dev);
-
-@@ -532,12 +535,12 @@ static void vc4_crtc_update_dlist(struct
- crtc->state->event = NULL;
- }
-
-- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
-+ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
- vc4_state->mm.start);
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
- } else {
-- HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
-+ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
- vc4_state->mm.start);
- }
- }
-@@ -586,7 +589,7 @@ static void vc4_crtc_atomic_enable(struc
- (vc4_state->feed_txp ?
- SCALER5_DISPCTRLX_ONESHOT : 0);
-
-- HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), dispctrl);
-+ HVS_WRITE(SCALER_DISPCTRLX(vc4_state->assigned_channel), dispctrl);
-
- /* When feeding the transposer block the pixelvalve is unneeded and
- * should not be enabled.
-@@ -702,7 +705,6 @@ static void vc4_crtc_atomic_flush(struct
- {
- 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);
- struct drm_plane *plane;
- struct vc4_plane_state *vc4_plane_state;
-@@ -744,8 +746,8 @@ static void vc4_crtc_atomic_flush(struct
- /* This sets a black background color fill, as is the case
- * with other DRM drivers.
- */
-- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
-- HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) |
-+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
-+ HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) |
- SCALER_DISPBKGND_FILL);
-
- /* Only update DISPLIST if the CRTC was already running and is not
-@@ -759,7 +761,7 @@ static void vc4_crtc_atomic_flush(struct
- vc4_crtc_update_dlist(crtc);
-
- if (crtc->state->color_mgmt_changed) {
-- u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel));
-+ u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
-
- if (crtc->state->gamma_lut) {
- vc4_crtc_update_gamma_lut(crtc);
-@@ -771,7 +773,7 @@ static void vc4_crtc_atomic_flush(struct
- */
- dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
- }
-- HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), dispbkgndx);
-+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
- }
-
- if (debug_dump_regs) {
-@@ -802,7 +804,7 @@ static void vc4_crtc_handle_page_flip(st
- 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_crtc->channel;
-+ u32 chan = vc4_state->assigned_channel;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->event_lock, flags);
-@@ -1002,6 +1004,7 @@ static struct drm_crtc_state *vc4_crtc_d
- 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;
-
- __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
- return &vc4_state->base;
-@@ -1061,6 +1064,7 @@ static const struct drm_crtc_helper_func
- };
-
- static const struct vc4_crtc_data bcm2835_pv0_data = {
-+ .hvs_available_channels = BIT(0),
- .hvs_output = 0,
- .debugfs_name = "crtc0_regs",
- .pixels_per_clock = 1,
-@@ -1071,6 +1075,7 @@ static const struct vc4_crtc_data bcm283
- };
-
- static const struct vc4_crtc_data bcm2835_pv1_data = {
-+ .hvs_available_channels = BIT(2),
- .hvs_output = 2,
- .debugfs_name = "crtc1_regs",
- .pixels_per_clock = 1,
-@@ -1081,6 +1086,7 @@ static const struct vc4_crtc_data bcm283
- };
-
- static const struct vc4_crtc_data bcm2835_pv2_data = {
-+ .hvs_available_channels = BIT(1),
- .hvs_output = 1,
- .debugfs_name = "crtc2_regs",
- .pixels_per_clock = 1,
-@@ -1172,7 +1178,6 @@ static int vc4_crtc_bind(struct device *
- drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
- &vc4_crtc_funcs, NULL);
- drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
-- vc4_crtc->channel = vc4_crtc->data->hvs_output;
- drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r));
- drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size);
-
---- a/drivers/gpu/drm/vc4/vc4_drv.h
-+++ b/drivers/gpu/drm/vc4/vc4_drv.h
-@@ -452,6 +452,9 @@ to_vc4_encoder(struct drm_encoder *encod
- }
-
- struct vc4_crtc_data {
-+ /* Which channels of the HVS can the output source from */
-+ unsigned int hvs_available_channels;
-+
- /* Which output of the HVS this pixelvalve sources from. */
- int hvs_output;
-
-@@ -471,9 +474,6 @@ struct vc4_crtc {
- /* Timestamp at start of vblank irq - unaffected by lock delays. */
- ktime_t t_vblank;
-
-- /* Which HVS channel we're using for our CRTC. */
-- int channel;
--
- u8 lut_r[256];
- u8 lut_g[256];
- u8 lut_b[256];
-@@ -495,6 +495,7 @@ struct vc4_crtc_state {
- struct drm_mm_node mm;
- bool feed_txp;
- bool txp_armed;
-+ unsigned int assigned_channel;
-
- struct {
- unsigned int left;
---- a/drivers/gpu/drm/vc4/vc4_kms.c
-+++ b/drivers/gpu/drm/vc4/vc4_kms.c
-@@ -11,6 +11,9 @@
- * crtc, HDMI encoder).
- */
-
-+#include <linux/bitfield.h>
-+#include <linux/bitops.h>
-+
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include <drm/drm_crtc.h>
-@@ -148,6 +151,72 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru
- VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO));
- }
-
-+static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
-+ struct drm_atomic_state *state)
-+{
-+ struct drm_crtc_state *crtc_state;
-+ struct drm_crtc *crtc;
-+ unsigned char dsp2_mux = 0;
-+ unsigned char dsp3_mux = 3;
-+ unsigned char dsp4_mux = 3;
-+ unsigned char dsp5_mux = 3;
-+ unsigned int i;
-+ u32 reg;
-+
-+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
-+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+
-+ if (!crtc_state->active)
-+ continue;
-+
-+ switch (vc4_crtc->data->hvs_output) {
-+ case 2:
-+ dsp2_mux = (vc4_state->assigned_channel == 2) ? 1 : 0;
-+ break;
-+
-+ case 3:
-+ dsp3_mux = vc4_state->assigned_channel;
-+ break;
-+
-+ case 4:
-+ dsp4_mux = vc4_state->assigned_channel;
-+ break;
-+
-+ case 5:
-+ dsp5_mux = vc4_state->assigned_channel;
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ }
-+
-+ reg = HVS_READ(SCALER_DISPECTRL);
-+ if (FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg) != dsp2_mux)
-+ HVS_WRITE(SCALER_DISPECTRL,
-+ (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) |
-+ VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX));
-+
-+ reg = HVS_READ(SCALER_DISPCTRL);
-+ if (FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg) != dsp3_mux)
-+ HVS_WRITE(SCALER_DISPCTRL,
-+ (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) |
-+ VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX));
-+
-+ reg = HVS_READ(SCALER_DISPEOLN);
-+ if (FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg) != dsp4_mux)
-+ HVS_WRITE(SCALER_DISPEOLN,
-+ (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) |
-+ VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX));
-+
-+ reg = HVS_READ(SCALER_DISPDITHER);
-+ if (FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg) != dsp5_mux)
-+ HVS_WRITE(SCALER_DISPDITHER,
-+ (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) |
-+ VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX));
-+}
-+
- static void
- vc4_atomic_complete_commit(struct drm_atomic_state *state)
- {
-@@ -157,11 +226,15 @@ vc4_atomic_complete_commit(struct drm_at
- int i;
-
- for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) {
-- if (!state->crtcs[i].ptr || !state->crtcs[i].commit)
-+ struct __drm_crtcs_state *_state = &state->crtcs[i];
-+ struct vc4_crtc_state *vc4_crtc_state;
-+
-+ if (!_state->ptr || !_state->commit)
- continue;
-
-- vc4_crtc = to_vc4_crtc(state->crtcs[i].ptr);
-- vc4_hvs_mask_underrun(dev, vc4_crtc->channel);
-+ vc4_crtc = to_vc4_crtc(_state->ptr);
-+ vc4_crtc_state = to_vc4_crtc_state(_state->state);
-+ vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
- }
-
- drm_atomic_helper_wait_for_fences(dev, state, false);
-@@ -170,8 +243,10 @@ vc4_atomic_complete_commit(struct drm_at
-
- drm_atomic_helper_commit_modeset_disables(dev, state);
-
-- if (!vc4->firmware_kms)
-+ if (!vc4->firmware_kms) {
- vc4_ctm_commit(vc4, state);
-+ vc4_hvs_pv_muxing_commit(vc4, state);
-+ }
-
- drm_atomic_helper_commit_planes(dev, state, 0);
-
-@@ -380,8 +455,11 @@ vc4_ctm_atomic_check(struct drm_device *
-
- /* CTM is being enabled or the matrix changed. */
- if (new_crtc_state->ctm) {
-+ struct vc4_crtc_state *vc4_crtc_state =
-+ to_vc4_crtc_state(new_crtc_state);
-+
- /* fifo is 1-based since 0 disables CTM. */
-- int fifo = to_vc4_crtc(crtc)->channel + 1;
-+ int fifo = vc4_crtc_state->assigned_channel + 1;
-
- /* Check userland isn't trying to turn on CTM for more
- * than one CRTC at a time.
-@@ -494,10 +572,66 @@ static const struct drm_private_state_fu
- .atomic_destroy_state = vc4_load_tracker_destroy_state,
- };
-
-+#define NUM_OUTPUTS 6
-+#define NUM_CHANNELS 3
-+
- static int
- vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
- {
-- int ret;
-+ unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0);
-+ struct drm_crtc_state *crtc_state;
-+ struct drm_crtc *crtc;
-+ int i, ret;
-+
-+ for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
-+ struct vc4_crtc_state *vc4_crtc_state =
-+ to_vc4_crtc_state(crtc_state);
-+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
-+ bool is_assigned = false;
-+ unsigned int channel;
-+
-+ if (!crtc_state->active)
-+ continue;
-+
-+ /*
-+ * The problem we have to solve here is that we have
-+ * up to 7 encoders, connected to up to 6 CRTCs.
-+ *
-+ * Those CRTCs, depending on the instance, can be
-+ * routed to 1, 2 or 3 HVS FIFOs, and we need to set
-+ * the change the muxing between FIFOs and outputs in
-+ * the HVS accordingly.
-+ *
-+ * It would be pretty hard to come up with an
-+ * algorithm that would generically solve
-+ * this. However, the current routing trees we support
-+ * allow us to simplify a bit the problem.
-+ *
-+ * Indeed, with the current supported layouts, if we
-+ * try to assign in the ascending crtc index order the
-+ * FIFOs, we can't fall into the situation where an
-+ * earlier CRTC that had multiple routes is assigned
-+ * one that was the only option for a later CRTC.
-+ *
-+ * If the layout changes and doesn't give us that in
-+ * the future, we will need to have something smarter,
-+ * but it works so far.
-+ */
-+ for_each_set_bit(channel, &unassigned_channels,
-+ sizeof(unassigned_channels)) {
-+
-+ if (!(BIT(channel) & vc4_crtc->data->hvs_available_channels))
-+ continue;
-+
-+ vc4_crtc_state->assigned_channel = channel;
-+ unassigned_channels &= ~BIT(channel);
-+ is_assigned = true;
-+ break;
-+ }
-+
-+ if (!is_assigned)
-+ return -EINVAL;
-+ }
-
- ret = vc4_ctm_atomic_check(dev, state);
- if (ret < 0)
---- a/drivers/gpu/drm/vc4/vc4_regs.h
-+++ b/drivers/gpu/drm/vc4/vc4_regs.h
-@@ -287,9 +287,19 @@
-
- #define SCALER_DISPID 0x00000008
- #define SCALER_DISPECTRL 0x0000000c
-+# define SCALER_DISPECTRL_DSP2_MUX_SHIFT 31
-+# define SCALER_DISPECTRL_DSP2_MUX_MASK VC4_MASK(31, 31)
-+
- #define SCALER_DISPPROF 0x00000010
-+
- #define SCALER_DISPDITHER 0x00000014
-+# define SCALER_DISPDITHER_DSP5_MUX_SHIFT 30
-+# define SCALER_DISPDITHER_DSP5_MUX_MASK VC4_MASK(31, 30)
-+
- #define SCALER_DISPEOLN 0x00000018
-+# define SCALER_DISPEOLN_DSP4_MUX_SHIFT 30
-+# define SCALER_DISPEOLN_DSP4_MUX_MASK VC4_MASK(31, 30)
-+
- #define SCALER_DISPLIST0 0x00000020
- #define SCALER_DISPLIST1 0x00000024
- #define SCALER_DISPLIST2 0x00000028