mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	Also removes random module and switches to new bcm2711 thermal driver. Boot tested on RPi 4B v1.1 4G. Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
		
			
				
	
	
		
			460 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			460 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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
 |