diff options
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.patch | 459 |
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 |