diff options
| author | Dave Airlie <airlied@redhat.com> | 2019-07-04 14:08:07 +1000 | 
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2019-07-04 14:09:50 +1000 | 
| commit | f07b56e7d0b21b49d809b301837c6ba39c27309a (patch) | |
| tree | e3a5dbe293772c5e79415317f069a5e668ede8c3 /drivers/gpu/drm/armada | |
| parent | a22719cce54bc18001a7c8be9c713ba629f5801c (diff) | |
| parent | 837567c1e9d587c0b438263c9cfd32de46640e16 (diff) | |
| download | linux-f07b56e7d0b21b49d809b301837c6ba39c27309a.tar.bz2 | |
Merge tag 'for-airlie-armada' of git://git.armlinux.org.uk/~rmk/linux-arm into drm-next
Armada DRM updates:
- Fix interlace support.
- use __drm_atomic_helper_plane_reset in overlay reset.
- since the overlay and video planes use essentially the same format
  registers, precompute their values while validating.
- fix a long-standing deficiency with overlay planes and interlace modes
- calculate plane starting address at atomic_check stage rather than
  when we're programming the registers.
- add gamma support.
- ensure mode adjustments made by other components are properly handled
  in the driver and applied to the CRTC-programmed mode.
- add and use register definitions for the "REG4F" register.
- use drm_atomic_helper_shutdown() when tearing down to ensure that the
  hardware is properly shutdown.
- add CRTC-level mode validation to ensure that we don't allow a mode
  that the CRTC-level hardware can not support.
- improve the clocking selection for Armada 510 support.
- move CRTC debugfs files into the crtc-specific directory, using the
  DRM helper to create these files.
- patch from Lubomir Rintel to replace a simple framebuffer.
- use the OF graph walker rather than open-coding this.
- eliminate a useless check for the availability of the remote's parent
  which isn't required.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Russell King <rmk@armlinux.org.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20190702091313.GA23442@rmk-PC.armlinux.org.uk
Diffstat (limited to 'drivers/gpu/drm/armada')
| -rw-r--r-- | drivers/gpu/drm/armada/armada_510.c | 130 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.c | 214 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_crtc.h | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_debugfs.c | 98 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_drm.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_drv.c | 38 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_hw.h | 29 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_overlay.c | 56 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_plane.c | 124 | ||||
| -rw-r--r-- | drivers/gpu/drm/armada/armada_plane.h | 23 | 
10 files changed, 522 insertions, 212 deletions
| diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 0e91d27921bd..6f8ad8fb19f1 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -14,18 +14,62 @@  #include "armada_drm.h"  #include "armada_hw.h" +struct armada510_variant_data { +	struct clk *clks[4]; +	struct clk *sel_clk; +}; +  static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)  { +	struct armada510_variant_data *v;  	struct clk *clk; +	int idx; + +	v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); +	if (!v) +		return -ENOMEM; + +	dcrtc->variant_data = v; + +	if (dev->of_node) { +		struct property *prop; +		const char *s; + +		of_property_for_each_string(dev->of_node, "clock-names", prop, +					    s) { +			if (!strcmp(s, "ext_ref_clk0")) +				idx = 0; +			else if (!strcmp(s, "ext_ref_clk1")) +				idx = 1; +			else if (!strcmp(s, "plldivider")) +				idx = 2; +			else if (!strcmp(s, "axibus")) +				idx = 3; +			else +				continue; + +			clk = devm_clk_get(dev, s); +			if (IS_ERR(clk)) +				return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : +					PTR_ERR(clk); +			v->clks[idx] = clk; +		} +	} else { +		clk = devm_clk_get(dev, "ext_ref_clk1"); +		if (IS_ERR(clk)) +			return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : +				PTR_ERR(clk); + +		v->clks[1] = clk; +	} -	clk = devm_clk_get(dev, "ext_ref_clk1"); -	if (IS_ERR(clk)) -		return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk); - -	dcrtc->extclk[0] = clk; - -	/* Lower the watermark so to eliminate jitter at higher bandwidths */ -	armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); +	/* +	 * Lower the watermark so to eliminate jitter at higher bandwidths. +	 * Disable SRAM read wait state to avoid system hang with external +	 * clock. +	 */ +	armada_updatel(CFG_DMA_WM(0x20), CFG_SRAM_WAIT | CFG_DMA_WM_MASK, +		       dcrtc->base + LCD_CFG_RDREG4F);  	/* Initialise SPU register */  	writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, @@ -34,65 +78,77 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)  	return 0;  } +static const u32 armada510_clk_sels[] = { +	SCLK_510_EXTCLK0, +	SCLK_510_EXTCLK1, +	SCLK_510_PLL, +	SCLK_510_AXI, +}; + +static const struct armada_clocking_params armada510_clocking = { +	/* HDMI requires -0.6%..+0.5% */ +	.permillage_min = 994, +	.permillage_max = 1005, +	.settable = BIT(0) | BIT(1), +	.div_max = SCLK_510_INT_DIV_MASK, +}; +  /*   * Armada510 specific SCLK register selection.   * This gets called with sclk = NULL to test whether the mode is   * supportable, and again with sclk != NULL to set the clocks up for   * that.  The former can return an error, but the latter is expected   * not to. - * - * We currently are pretty rudimentary here, always selecting - * EXT_REF_CLK_1 for LCD0 and erroring LCD1.  This needs improvement!   */  static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,  	const struct drm_display_mode *mode, uint32_t *sclk)  { -	struct clk *clk = dcrtc->extclk[0]; -	int ret; +	struct armada510_variant_data *v = dcrtc->variant_data; +	unsigned long desired_khz = mode->crtc_clock; +	struct armada_clk_result res; +	int ret, idx; -	if (dcrtc->num == 1) -		return -EINVAL; +	idx = armada_crtc_select_clock(dcrtc, &res, &armada510_clocking, +				       v->clks, ARRAY_SIZE(v->clks), +				       desired_khz); +	if (idx < 0) +		return idx; -	if (IS_ERR(clk)) -		return PTR_ERR(clk); - -	if (dcrtc->clk != clk) { -		ret = clk_prepare_enable(clk); -		if (ret) -			return ret; -		dcrtc->clk = clk; -	} +	ret = clk_prepare_enable(res.clk); +	if (ret) +		return ret;  	if (sclk) { -		uint32_t rate, ref, div; +		clk_set_rate(res.clk, res.desired_clk_hz); -		rate = mode->clock * 1000; -		ref = clk_round_rate(clk, rate); -		div = DIV_ROUND_UP(ref, rate); -		if (div < 1) -			div = 1; +		*sclk = res.div | armada510_clk_sels[idx]; -		clk_set_rate(clk, ref); -		*sclk = div | SCLK_510_EXTCLK1; +		/* We are now using this clock */ +		v->sel_clk = res.clk; +		swap(dcrtc->clk, res.clk);  	} +	clk_disable_unprepare(res.clk); +  	return 0;  }  static void armada510_crtc_disable(struct armada_crtc *dcrtc)  { -	if (!IS_ERR(dcrtc->clk)) { +	if (dcrtc->clk) {  		clk_disable_unprepare(dcrtc->clk); -		dcrtc->clk = ERR_PTR(-EINVAL); +		dcrtc->clk = NULL;  	}  }  static void armada510_crtc_enable(struct armada_crtc *dcrtc,  	const struct drm_display_mode *mode)  { -	if (IS_ERR(dcrtc->clk)) { -		dcrtc->clk = dcrtc->extclk[0]; -		WARN_ON(clk_prepare_enable(dcrtc->clk)); +	struct armada510_variant_data *v = dcrtc->variant_data; + +	if (!dcrtc->clk && v->sel_clk) { +		if (!WARN_ON(clk_prepare_enable(v->sel_clk))) +			dcrtc->clk = v->sel_clk;  	}  } diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index ba4a3fab7745..2e17d7e72eeb 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -130,6 +130,70 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)  	}  } +static void armada_drm_update_gamma(struct drm_crtc *crtc) +{ +	struct drm_property_blob *blob = crtc->state->gamma_lut; +	void __iomem *base = drm_to_armada_crtc(crtc)->base; +	int i; + +	if (blob) { +		struct drm_color_lut *lut = blob->data; + +		armada_updatel(CFG_CSB_256x8, CFG_CSB_256x8 | CFG_PDWN256x8, +			       base + LCD_SPU_SRAM_PARA1); + +		for (i = 0; i < 256; i++) { +			writel_relaxed(drm_color_lut_extract(lut[i].red, 8), +				       base + LCD_SPU_SRAM_WRDAT); +			writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR, +				       base + LCD_SPU_SRAM_CTRL); +			readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); +			writel_relaxed(drm_color_lut_extract(lut[i].green, 8), +				       base + LCD_SPU_SRAM_WRDAT); +			writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG, +				       base + LCD_SPU_SRAM_CTRL); +			readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); +			writel_relaxed(drm_color_lut_extract(lut[i].blue, 8), +				       base + LCD_SPU_SRAM_WRDAT); +			writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB, +				       base + LCD_SPU_SRAM_CTRL); +			readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); +		} +		armada_updatel(CFG_GAMMA_ENA, CFG_GAMMA_ENA, +			       base + LCD_SPU_DMA_CTRL0); +	} else { +		armada_updatel(0, CFG_GAMMA_ENA, base + LCD_SPU_DMA_CTRL0); +		armada_updatel(CFG_PDWN256x8, CFG_CSB_256x8 | CFG_PDWN256x8, +			       base + LCD_SPU_SRAM_PARA1); +	} +} + +static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc, +	const struct drm_display_mode *mode) +{ +	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + +	if (mode->vscan > 1) +		return MODE_NO_VSCAN; + +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN) +		return MODE_NO_DBLESCAN; + +	if (mode->flags & DRM_MODE_FLAG_HSKEW) +		return MODE_H_ILLEGAL; + +	/* We can't do interlaced modes if we don't have the SPU_ADV_REG */ +	if (!dcrtc->variant->has_spu_adv_reg && +	    mode->flags & DRM_MODE_FLAG_INTERLACE) +		return MODE_NO_INTERLACE; + +	if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX | +			   DRM_MODE_FLAG_CLKDIV2)) +		return MODE_BAD; + +	return MODE_OK; +} +  /* The mode_config.mutex will be held for this call */  static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,  	const struct drm_display_mode *mode, struct drm_display_mode *adj) @@ -137,9 +201,18 @@ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,  	struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);  	int ret; -	/* We can't do interlaced modes if we don't have the SPU_ADV_REG */ -	if (!dcrtc->variant->has_spu_adv_reg && -	    adj->flags & DRM_MODE_FLAG_INTERLACE) +	/* +	 * Set CRTC modesetting parameters for the adjusted mode.  This is +	 * applied after the connectors, bridges, and encoders have fixed up +	 * this mode, as described above drm_atomic_helper_check_modeset(). +	 */ +	drm_mode_set_crtcinfo(adj, CRTC_INTERLACE_HALVE_V); + +	/* +	 * Validate the adjusted mode in case an encoder/bridge has set +	 * something we don't support. +	 */ +	if (armada_drm_crtc_mode_valid(crtc, adj) != MODE_OK)  		return false;  	/* Check whether the display mode is possible */ @@ -278,16 +351,9 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)  	armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV); -	if (interlaced ^ dcrtc->interlaced) { -		if (adj->flags & DRM_MODE_FLAG_INTERLACE) -			drm_crtc_vblank_get(&dcrtc->crtc); -		else -			drm_crtc_vblank_put(&dcrtc->crtc); -		dcrtc->interlaced = interlaced; -	} -  	spin_lock_irqsave(&dcrtc->irq_lock, flags); +	dcrtc->interlaced = interlaced;  	/* Even interlaced/progressive frame */  	dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 |  				    adj->crtc_htotal; @@ -345,6 +411,20 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)  	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);  } +static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc, +					struct drm_crtc_state *state) +{ +	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + +	if (state->gamma_lut && drm_color_lut_size(state->gamma_lut) != 256) +		return -EINVAL; + +	if (state->color_mgmt_changed) +		state->planes_changed = true; + +	return 0; +} +  static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,  					 struct drm_crtc_state *old_crtc_state)  { @@ -352,6 +432,9 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc,  	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); +	if (crtc->state->color_mgmt_changed) +		armada_drm_update_gamma(crtc); +  	dcrtc->regs_idx = 0;  	dcrtc->regs = dcrtc->atomic_regs;  } @@ -390,6 +473,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,  	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); +	if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) +		drm_crtc_vblank_put(crtc); +  	drm_crtc_vblank_off(crtc);  	armada_drm_crtc_update(dcrtc, false); @@ -434,12 +520,17 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc,  	armada_drm_crtc_update(dcrtc, true);  	drm_crtc_vblank_on(crtc); +	if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) +		WARN_ON(drm_crtc_vblank_get(crtc)); +  	armada_drm_crtc_queue_state_event(crtc);  }  static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { +	.mode_valid	= armada_drm_crtc_mode_valid,  	.mode_fixup	= armada_drm_crtc_mode_fixup,  	.mode_set_nofb	= armada_drm_crtc_mode_set_nofb, +	.atomic_check	= armada_drm_crtc_atomic_check,  	.atomic_begin	= armada_drm_crtc_atomic_begin,  	.atomic_flush	= armada_drm_crtc_atomic_flush,  	.atomic_disable	= armada_drm_crtc_atomic_disable, @@ -460,6 +551,13 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,  		for (x = 0; x < width; x++, p++) {  			uint32_t val = *p; +			/* +			 * In "ARGB888" (HWC32) mode, writing to the SRAM +			 * requires these bits to contain: +			 * 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red +			 * So, it's actually ABGR8888.  This is independent +			 * of the SWAPRB bits in DMA control register 0. +			 */  			val = (val & 0xff00ff00) |  			      (val & 0x000000ff) << 16 |  			      (val & 0x00ff0000) >> 16; @@ -676,6 +774,14 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)  	kfree(dcrtc);  } +static int armada_drm_crtc_late_register(struct drm_crtc *crtc) +{ +	if (IS_ENABLED(CONFIG_DEBUG_FS)) +		armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc)); + +	return 0; +} +  /* These are called under the vbl_lock. */  static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc)  { @@ -703,14 +809,93 @@ static const struct drm_crtc_funcs armada_crtc_funcs = {  	.cursor_set	= armada_drm_crtc_cursor_set,  	.cursor_move	= armada_drm_crtc_cursor_move,  	.destroy	= armada_drm_crtc_destroy, +	.gamma_set	= drm_atomic_helper_legacy_gamma_set,  	.set_config	= drm_atomic_helper_set_config,  	.page_flip	= drm_atomic_helper_page_flip,  	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,  	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +	.late_register	= armada_drm_crtc_late_register,  	.enable_vblank	= armada_drm_crtc_enable_vblank,  	.disable_vblank	= armada_drm_crtc_disable_vblank,  }; +int armada_crtc_select_clock(struct armada_crtc *dcrtc, +			     struct armada_clk_result *res, +			     const struct armada_clocking_params *params, +			     struct clk *clks[], size_t num_clks, +			     unsigned long desired_khz) +{ +	unsigned long desired_hz = desired_khz * 1000; +	unsigned long desired_clk_hz;	// requested clk input +	unsigned long real_clk_hz;	// actual clk input +	unsigned long real_hz;		// actual pixel clk +	unsigned long permillage; +	struct clk *clk; +	u32 div; +	int i; + +	DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n", +		      dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz); + +	for (i = 0; i < num_clks; i++) { +		clk = clks[i]; +		if (!clk) +			continue; + +		if (params->settable & BIT(i)) { +			real_clk_hz = clk_round_rate(clk, desired_hz); +			desired_clk_hz = desired_hz; +		} else { +			real_clk_hz = clk_get_rate(clk); +			desired_clk_hz = real_clk_hz; +		} + +		/* If the clock can do exactly the desired rate, we're done */ +		if (real_clk_hz == desired_hz) { +			real_hz = real_clk_hz; +			div = 1; +			goto found; +		} + +		/* Calculate the divider - if invalid, we can't do this rate */ +		div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz); +		if (div == 0 || div > params->div_max) +			continue; + +		/* Calculate the actual rate - HDMI requires -0.6%..+0.5% */ +		real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div); + +		DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n", +			dcrtc->crtc.base.id, dcrtc->crtc.name, +			i, real_clk_hz, div, real_hz); + +		/* Avoid repeated division */ +		if (real_hz < desired_hz) { +			permillage = real_hz / desired_khz; +			if (permillage < params->permillage_min) +				continue; +		} else { +			permillage = DIV_ROUND_UP(real_hz, desired_khz); +			if (permillage > params->permillage_max) +				continue; +		} +		goto found; +	} + +	return -ERANGE; + +found: +	DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n", +		dcrtc->crtc.base.id, dcrtc->crtc.name, +		i, real_clk_hz, div, real_hz); + +	res->desired_clk_hz = desired_clk_hz; +	res->clk = clk; +	res->div = div; + +	return i; +} +  static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	struct resource *res, int irq, const struct armada_variant *variant,  	struct device_node *port) @@ -737,7 +922,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	dcrtc->variant = variant;  	dcrtc->base = base;  	dcrtc->num = drm->mode_config.num_crtc; -	dcrtc->clk = ERR_PTR(-EINVAL);  	dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0;  	dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24;  	spin_lock_init(&dcrtc->irq_lock); @@ -794,6 +978,12 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,  	drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); +	ret = drm_mode_crtc_set_gamma_size(&dcrtc->crtc, 256); +	if (ret) +		return ret; + +	drm_crtc_enable_color_mgmt(&dcrtc->crtc, 0, false, 256); +  	return armada_overlay_plane_create(drm, 1 << dcrtc->num);  err_crtc_init: diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 08761ff01739..fb4aa48da60c 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -39,10 +39,10 @@ struct armada_variant;  struct armada_crtc {  	struct drm_crtc		crtc;  	const struct armada_variant *variant; +	void			*variant_data;  	unsigned		num;  	void __iomem		*base;  	struct clk		*clk; -	struct clk		*extclk[2];  	struct {  		uint32_t	spu_v_h_total;  		uint32_t	spu_v_porch; @@ -75,6 +75,25 @@ struct armada_crtc {  void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); +struct armada_clocking_params { +	unsigned long permillage_min; +	unsigned long permillage_max; +	u32 settable; +	u32 div_max; +}; + +struct armada_clk_result { +	unsigned long desired_clk_hz; +	struct clk *clk; +	u32 div; +}; + +int armada_crtc_select_clock(struct armada_crtc *dcrtc, +			     struct armada_clk_result *res, +			     const struct armada_clocking_params *params, +			     struct clk *clks[], size_t num_clks, +			     unsigned long desired_khz); +  extern struct platform_driver armada_lcd_platform_driver;  #endif diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c index 6758c3a83de2..4dcce002ea2a 100644 --- a/drivers/gpu/drm/armada/armada_debugfs.c +++ b/drivers/gpu/drm/armada/armada_debugfs.c @@ -28,50 +28,33 @@ static int armada_debugfs_gem_linear_show(struct seq_file *m, void *data)  	return 0;  } -static int armada_debugfs_reg_show(struct seq_file *m, void *data) +static int armada_debugfs_crtc_reg_show(struct seq_file *m, void *data)  { -	struct drm_device *dev = m->private; -	struct armada_private *priv = dev->dev_private; -	int n, i; - -	if (priv) { -		for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { -			struct armada_crtc *dcrtc = priv->dcrtc[n]; -			if (!dcrtc) -				continue; - -			for (i = 0x84; i <= 0x1c4; i += 4) { -				uint32_t v = readl_relaxed(dcrtc->base + i); -				seq_printf(m, "%u: 0x%04x: 0x%08x\n", n, i, v); -			} -		} +	struct armada_crtc *dcrtc = m->private; +	int i; + +	for (i = 0x84; i <= 0x1c4; i += 4) { +		u32 v = readl_relaxed(dcrtc->base + i); +		seq_printf(m, "0x%04x: 0x%08x\n", i, v);  	}  	return 0;  } -static int armada_debugfs_reg_r_open(struct inode *inode, struct file *file) +static int armada_debugfs_crtc_reg_open(struct inode *inode, struct file *file)  { -	return single_open(file, armada_debugfs_reg_show, inode->i_private); +	return single_open(file, armada_debugfs_crtc_reg_show, +			   inode->i_private);  } -static const struct file_operations fops_reg_r = { -	.owner = THIS_MODULE, -	.open = armada_debugfs_reg_r_open, -	.read = seq_read, -	.llseek = seq_lseek, -	.release = single_release, -}; - -static int armada_debugfs_write(struct file *file, const char __user *ptr, -	size_t len, loff_t *off) +static int armada_debugfs_crtc_reg_write(struct file *file, +	const char __user *ptr, size_t len, loff_t *off)  { -	struct drm_device *dev = file->private_data; -	struct armada_private *priv = dev->dev_private; -	struct armada_crtc *dcrtc = priv->dcrtc[0]; -	char buf[32], *p; -	uint32_t reg, val; +	struct armada_crtc *dcrtc; +	unsigned long reg, mask, val; +	char buf[32];  	int ret; +	u32 v;  	if (*off != 0)  		return 0; @@ -84,24 +67,35 @@ static int armada_debugfs_write(struct file *file, const char __user *ptr,  		return ret;  	buf[len] = '\0'; -	reg = simple_strtoul(buf, &p, 16); -	if (!isspace(*p)) +	if (sscanf(buf, "%lx %lx %lx", ®, &mask, &val) != 3)  		return -EINVAL; -	val = simple_strtoul(p + 1, NULL, 16); +	if (reg < 0x84 || reg > 0x1c4 || reg & 3) +		return -ERANGE; -	if (reg >= 0x84 && reg <= 0x1c4) -		writel(val, dcrtc->base + reg); +	dcrtc = ((struct seq_file *)file->private_data)->private; +	v = readl(dcrtc->base + reg); +	v &= ~mask; +	v |= val & mask; +	writel(v, dcrtc->base + reg);  	return len;  } -static const struct file_operations fops_reg_w = { +static const struct file_operations armada_debugfs_crtc_reg_fops = {  	.owner = THIS_MODULE, -	.open = simple_open, -	.write = armada_debugfs_write, -	.llseek = noop_llseek, +	.open = armada_debugfs_crtc_reg_open, +	.read = seq_read, +	.write = armada_debugfs_crtc_reg_write, +	.llseek = seq_lseek, +	.release = single_release,  }; +void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc) +{ +	debugfs_create_file("armada-regs", 0600, dcrtc->crtc.debugfs_entry, +			    dcrtc, &armada_debugfs_crtc_reg_fops); +} +  static struct drm_info_list armada_debugfs_list[] = {  	{ "gem_linear", armada_debugfs_gem_linear_show, 0 },  }; @@ -109,24 +103,8 @@ static struct drm_info_list armada_debugfs_list[] = {  int armada_drm_debugfs_init(struct drm_minor *minor)  { -	struct dentry *de; -	int ret; - -	ret = drm_debugfs_create_files(armada_debugfs_list, -				       ARMADA_DEBUGFS_ENTRIES, -				       minor->debugfs_root, minor); -	if (ret) -		return ret; - -	de = debugfs_create_file("reg", S_IFREG | S_IRUSR, -				 minor->debugfs_root, minor->dev, &fops_reg_r); -	if (!de) -		return -ENOMEM; - -	de = debugfs_create_file("reg_wr", S_IFREG | S_IWUSR, -				 minor->debugfs_root, minor->dev, &fops_reg_w); -	if (!de) -		return -ENOMEM; +	drm_debugfs_create_files(armada_debugfs_list, ARMADA_DEBUGFS_ENTRIES, +				 minor->debugfs_root, minor);  	return 0;  } diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index f09083ff15d3..b6307235f320 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -78,6 +78,7 @@ void armada_fbdev_fini(struct drm_device *);  int armada_overlay_plane_create(struct drm_device *, unsigned long); +void armada_drm_crtc_debugfs_init(struct armada_crtc *dcrtc);  int armada_drm_debugfs_init(struct drm_minor *);  #endif diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e660c5ca52ae..f1729398b1bd 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -100,6 +100,17 @@ static int armada_drm_bind(struct device *dev)  		return ret;  	} +	/* Remove early framebuffers */ +	ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, +							    "armada-drm-fb", +							    false); +	if (ret) { +		dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", +			__func__, ret); +		kfree(priv); +		return ret; +	} +  	priv->drm.dev_private = priv;  	dev_set_drvdata(dev, &priv->drm); @@ -171,6 +182,8 @@ static void armada_drm_unbind(struct device *dev)  	drm_dev_unregister(&priv->drm); +	drm_atomic_helper_shutdown(&priv->drm); +  	component_unbind_all(dev, &priv->drm);  	drm_mode_config_cleanup(&priv->drm); @@ -191,23 +204,15 @@ static int compare_dev_name(struct device *dev, void *data)  }  static void armada_add_endpoints(struct device *dev, -	struct component_match **match, struct device_node *port) +	struct component_match **match, struct device_node *dev_node)  {  	struct device_node *ep, *remote; -	for_each_child_of_node(port, ep) { +	for_each_endpoint_of_node(dev_node, ep) {  		remote = of_graph_get_remote_port_parent(ep); -		if (!remote || !of_device_is_available(remote)) { -			of_node_put(remote); -			continue; -		} else if (!of_device_is_available(remote->parent)) { -			dev_warn(dev, "parent device of %pOF is not available\n", -				 remote); -			of_node_put(remote); -			continue; -		} - -		drm_of_component_match_add(dev, match, compare_of, remote); +		if (remote && of_device_is_available(remote)) +			drm_of_component_match_add(dev, match, compare_of, +						   remote);  		of_node_put(remote);  	}  } @@ -229,7 +234,6 @@ static int armada_drm_probe(struct platform_device *pdev)  	if (dev->platform_data) {  		char **devices = dev->platform_data; -		struct device_node *port;  		struct device *d;  		int i; @@ -245,10 +249,8 @@ static int armada_drm_probe(struct platform_device *pdev)  		for (i = 0; devices[i]; i++) {  			d = bus_find_device_by_name(&platform_bus_type, NULL,  						    devices[i]); -			if (d && d->of_node) { -				for_each_child_of_node(d->of_node, port) -					armada_add_endpoints(dev, &match, port); -			} +			if (d && d->of_node) +				armada_add_endpoints(dev, &match, d->of_node);  			put_device(d);  		}  	} diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 277580b36758..5b1af0cc9f50 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -88,6 +88,16 @@ enum {  	ADV_VSYNC_H_OFF	= 0xfff << 0,  }; +/* LCD_CFG_RDREG4F - Armada 510 only */ +enum { +	CFG_SRAM_WAIT	= BIT(11), +	CFG_SMPN_FASTTX	= BIT(10), +	CFG_DMA_ARB	= BIT(9), +	CFG_DMA_WM_EN	= BIT(8), +	CFG_DMA_WM_MASK	= 0xff, +#define CFG_DMA_WM(x)	((x) & CFG_DMA_WM_MASK) +}; +  enum {  	CFG_565		= 0,  	CFG_1555	= 1, @@ -169,6 +179,10 @@ enum {  	SRAM_READ	= 0 << 14,  	SRAM_WRITE	= 2 << 14,  	SRAM_INIT	= 3 << 14, +	SRAM_GAMMA_YR	= 0x0 << 8, +	SRAM_GAMMA_UG	= 0x1 << 8, +	SRAM_GAMMA_VB	= 0x2 << 8, +	SRAM_PALETTE	= 0x3 << 8,  	SRAM_HWC32_RAM1	= 0xc << 8,  	SRAM_HWC32_RAM2	= 0xd << 8,  	SRAM_HWC32_RAMR	= SRAM_HWC32_RAM1, @@ -316,19 +330,4 @@ enum {  	PWRDN_IRQ_LEVEL		= 1 << 0,  }; -static inline u32 armada_rect_hw_fp(struct drm_rect *r) -{ -	return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16; -} - -static inline u32 armada_rect_hw(struct drm_rect *r) -{ -	return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff); -} - -static inline u32 armada_rect_yx(struct drm_rect *r) -{ -	return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff); -} -  #endif diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 8d770641fcc4..a79d6e940435 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -27,7 +27,7 @@  #define DEFAULT_ENCODING	DRM_COLOR_YCBCR_BT601  struct armada_overlay_state { -	struct drm_plane_state base; +	struct armada_plane_state base;  	u32 colorkey_yr;  	u32 colorkey_ug;  	u32 colorkey_vb; @@ -38,7 +38,7 @@ struct armada_overlay_state {  	u16 saturation;  };  #define drm_to_overlay_state(s) \ -	container_of(s, struct armada_overlay_state, base) +	container_of(s, struct armada_overlay_state, base.base)  static inline u32 armada_spu_contrast(struct drm_plane_state *state)  { @@ -94,41 +94,39 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,  		armada_reg_queue_mod(regs, idx,  				     0, CFG_PDWN16x66 | CFG_PDWN32x66,  				     LCD_SPU_SRAM_PARA1); -	val = armada_rect_hw_fp(&state->src); -	if (armada_rect_hw_fp(&old_state->src) != val) +	val = armada_src_hw(state); +	if (armada_src_hw(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); -	val = armada_rect_yx(&state->dst); -	if (armada_rect_yx(&old_state->dst) != val) +	val = armada_dst_yx(state); +	if (armada_dst_yx(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); -	val = armada_rect_hw(&state->dst); -	if (armada_rect_hw(&old_state->dst) != val) +	val = armada_dst_hw(state); +	if (armada_dst_hw(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);  	/* FIXME: overlay on an interlaced display */  	if (old_state->src.x1 != state->src.x1 ||  	    old_state->src.y1 != state->src.y1 || -	    old_state->fb != state->fb) { +	    old_state->fb != state->fb || +	    state->crtc->state->mode_changed) {  		const struct drm_format_info *format; -		u16 src_x, pitches[3]; -		u32 addrs[2][3]; +		u16 src_x; -		armada_drm_plane_calc(state, addrs, pitches, false); - -		armada_reg_queue_set(regs, idx, addrs[0][0], +		armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),  				     LCD_SPU_DMA_START_ADDR_Y0); -		armada_reg_queue_set(regs, idx, addrs[0][1], +		armada_reg_queue_set(regs, idx, armada_addr(state, 0, 1),  				     LCD_SPU_DMA_START_ADDR_U0); -		armada_reg_queue_set(regs, idx, addrs[0][2], +		armada_reg_queue_set(regs, idx, armada_addr(state, 0, 2),  				     LCD_SPU_DMA_START_ADDR_V0); -		armada_reg_queue_set(regs, idx, addrs[1][0], +		armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),  				     LCD_SPU_DMA_START_ADDR_Y1); -		armada_reg_queue_set(regs, idx, addrs[1][1], +		armada_reg_queue_set(regs, idx, armada_addr(state, 1, 1),  				     LCD_SPU_DMA_START_ADDR_U1); -		armada_reg_queue_set(regs, idx, addrs[1][2], +		armada_reg_queue_set(regs, idx, armada_addr(state, 1, 2),  				     LCD_SPU_DMA_START_ADDR_V1); -		val = pitches[0] << 16 | pitches[0]; +		val = armada_pitch(state, 0) << 16 | armada_pitch(state, 0);  		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); -		val = pitches[1] << 16 | pitches[2]; +		val = armada_pitch(state, 1) << 16 | armada_pitch(state, 2);  		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);  		cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | @@ -146,6 +144,8 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,  		src_x = state->src.x1 >> 16;  		if (format->num_planes == 1 && src_x & (format->hsub - 1))  			cfg ^= CFG_DMA_MOD(CFG_SWAPUV); +		if (to_armada_plane_state(state)->interlace) +			cfg |= CFG_DMA_FTOGGLE;  		cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |  			   CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |  				       CFG_SWAPYU | CFG_YUV2RGB) | @@ -307,13 +307,10 @@ static void armada_overlay_reset(struct drm_plane *plane)  	if (plane->state)  		__drm_atomic_helper_plane_destroy_state(plane->state);  	kfree(plane->state); +	plane->state = NULL;  	state = kzalloc(sizeof(*state), GFP_KERNEL);  	if (state) { -		state->base.plane = plane; -		state->base.color_encoding = DEFAULT_ENCODING; -		state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; -		state->base.rotation = DRM_MODE_ROTATE_0;  		state->colorkey_yr = 0xfefefe00;  		state->colorkey_ug = 0x01010100;  		state->colorkey_vb = 0x01010100; @@ -323,8 +320,10 @@ static void armada_overlay_reset(struct drm_plane *plane)  		state->brightness = DEFAULT_BRIGHTNESS;  		state->contrast = DEFAULT_CONTRAST;  		state->saturation = DEFAULT_SATURATION; +		__drm_atomic_helper_plane_reset(plane, &state->base.base); +		state->base.base.color_encoding = DEFAULT_ENCODING; +		state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;  	} -	plane->state = &state->base;  }  struct drm_plane_state * @@ -337,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)  	state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);  	if (state) -		__drm_atomic_helper_plane_duplicate_state(plane, &state->base); -	return &state->base; +		__drm_atomic_helper_plane_duplicate_state(plane, +							  &state->base.base); +	return &state->base.base;  }  static int armada_overlay_set_property(struct drm_plane *plane, diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 9f36423dd394..dbd4d52e8a32 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -79,23 +79,6 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],  	}  } -static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, -	struct armada_regs *regs, bool interlaced) -{ -	u16 pitches[3]; -	u32 addrs[2][3]; -	unsigned i = 0; - -	armada_drm_plane_calc(state, addrs, pitches, interlaced); - -	/* write offset, base, and pitch */ -	armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0); -	armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1); -	armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH); - -	return i; -} -  int armada_drm_plane_prepare_fb(struct drm_plane *plane,  	struct drm_plane_state *state)  { @@ -126,20 +109,50 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,  int armada_drm_plane_atomic_check(struct drm_plane *plane,  	struct drm_plane_state *state)  { -	if (state->fb && !WARN_ON(!state->crtc)) { -		struct drm_crtc *crtc = state->crtc; -		struct drm_crtc_state *crtc_state; - -		if (state->state) -			crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); -		else -			crtc_state = crtc->state; -		return drm_atomic_helper_check_plane_state(state, crtc_state, -							   0, INT_MAX, -							   true, false); -	} else { +	struct armada_plane_state *st = to_armada_plane_state(state); +	struct drm_crtc *crtc = state->crtc; +	struct drm_crtc_state *crtc_state; +	bool interlace; +	int ret; + +	if (!state->fb || WARN_ON(!state->crtc)) {  		state->visible = false; +		return 0; +	} + +	if (state->state) +		crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); +	else +		crtc_state = crtc->state; + +	ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0, +						  INT_MAX, true, false); +	if (ret) +		return ret; + +	interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE; +	if (interlace) { +		if ((state->dst.y1 | state->dst.y2) & 1) +			return -EINVAL; +		st->src_hw = drm_rect_height(&state->src) >> 17; +		st->dst_yx = state->dst.y1 >> 1; +		st->dst_hw = drm_rect_height(&state->dst) >> 1; +	} else { +		st->src_hw = drm_rect_height(&state->src) >> 16; +		st->dst_yx = state->dst.y1; +		st->dst_hw = drm_rect_height(&state->dst);  	} + +	st->src_hw <<= 16; +	st->src_hw |= drm_rect_width(&state->src) >> 16; +	st->dst_yx <<= 16; +	st->dst_yx |= state->dst.x1 & 0x0000ffff; +	st->dst_hw <<= 16; +	st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff; + +	armada_drm_plane_calc(state, st->addrs, st->pitches, interlace); +	st->interlace = interlace; +  	return 0;  } @@ -173,21 +186,25 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,  			val |= CFG_PDWN256x24;  		armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);  	} -	val = armada_rect_hw_fp(&state->src); -	if (armada_rect_hw_fp(&old_state->src) != val) +	val = armada_src_hw(state); +	if (armada_src_hw(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); -	val = armada_rect_yx(&state->dst); -	if (armada_rect_yx(&old_state->dst) != val) +	val = armada_dst_yx(state); +	if (armada_dst_yx(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); -	val = armada_rect_hw(&state->dst); -	if (armada_rect_hw(&old_state->dst) != val) +	val = armada_dst_hw(state); +	if (armada_dst_hw(old_state) != val)  		armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);  	if (old_state->src.x1 != state->src.x1 ||  	    old_state->src.y1 != state->src.y1 ||  	    old_state->fb != state->fb ||  	    state->crtc->state->mode_changed) { -		idx += armada_drm_crtc_calc_fb(state, regs + idx, -					       dcrtc->interlaced); +		armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0), +				     LCD_CFG_GRA_START_ADDR0); +		armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0), +				     LCD_CFG_GRA_START_ADDR1); +		armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff, +				     LCD_CFG_GRA_PITCH);  	}  	if (old_state->fb != state->fb ||  	    state->crtc->state->mode_changed) { @@ -197,7 +214,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,  			cfg |= CFG_PALETTE_ENA;  		if (state->visible)  			cfg |= CFG_GRA_ENA; -		if (dcrtc->interlaced) +		if (to_armada_plane_state(state)->interlace)  			cfg |= CFG_GRA_FTOGGLE;  		cfg_mask = CFG_GRAFORMAT |  			   CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | @@ -248,7 +265,7 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,  	/* Disable plane and power down most RAMs and FIFOs */  	armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);  	armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | -			     CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, +			     CFG_PDWN32x32 | CFG_PDWN64x66,  			     0, LCD_SPU_SRAM_PARA1);  	dcrtc->regs_idx += idx; @@ -262,12 +279,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {  	.atomic_disable	= armada_drm_primary_plane_atomic_disable,  }; +void armada_plane_reset(struct drm_plane *plane) +{ +	struct armada_plane_state *st; +	if (plane->state) +		__drm_atomic_helper_plane_destroy_state(plane->state); +	kfree(plane->state); +	st = kzalloc(sizeof(*st), GFP_KERNEL); +	if (st) +		__drm_atomic_helper_plane_reset(plane, &st->base); +} + +struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane) +{ +	struct armada_plane_state *st; + +	if (WARN_ON(!plane->state)) +		return NULL; + +	st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL); +	if (st) +		__drm_atomic_helper_plane_duplicate_state(plane, &st->base); + +	return &st->base; +} +  static const struct drm_plane_funcs armada_primary_plane_funcs = {  	.update_plane	= drm_atomic_helper_update_plane,  	.disable_plane	= drm_atomic_helper_disable_plane,  	.destroy	= drm_primary_helper_destroy, -	.reset		= drm_atomic_helper_plane_reset, -	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, +	.reset		= armada_plane_reset, +	.atomic_duplicate_state = armada_plane_duplicate_state,  	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,  }; diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index ff4281ba7fad..2707ec781941 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,6 +1,24 @@  #ifndef ARMADA_PLANE_H  #define ARMADA_PLANE_H +struct armada_plane_state { +	struct drm_plane_state base; +	u32 src_hw; +	u32 dst_yx; +	u32 dst_hw; +	u32 addrs[2][3]; +	u16 pitches[3]; +	bool interlace; +}; + +#define to_armada_plane_state(st) \ +	container_of(st, struct armada_plane_state, base) +#define armada_src_hw(state) to_armada_plane_state(state)->src_hw +#define armada_dst_yx(state) to_armada_plane_state(state)->dst_yx +#define armada_dst_hw(state) to_armada_plane_state(state)->dst_hw +#define armada_addr(state, f, p) to_armada_plane_state(state)->addrs[f][p] +#define armada_pitch(state, n) to_armada_plane_state(state)->pitches[n] +  void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],  	u16 pitches[3], bool interlaced);  int armada_drm_plane_prepare_fb(struct drm_plane *plane, @@ -9,6 +27,11 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,  	struct drm_plane_state *old_state);  int armada_drm_plane_atomic_check(struct drm_plane *plane,  	struct drm_plane_state *state); +void armada_plane_reset(struct drm_plane *plane); +struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane); +void armada_plane_destroy_state(struct drm_plane *plane, +				struct drm_plane_state *state); +  int armada_drm_primary_plane_init(struct drm_device *drm,  	struct drm_plane *primary); |