diff mbox series

[v2,44/50] drm/omap: dpi: Register a drm_bridge

Message ID 20190820011721.30136-45-laurent.pinchart@ideasonboard.com (mailing list archive)
State New, archived
Headers show
Series drm/omap: Replace custom display drivers with drm_bridge and drm_panel | expand

Commit Message

Laurent Pinchart Aug. 20, 2019, 1:17 a.m. UTC
In order to integrate with a chain of drm_bridge, the internal DPI
output has to expose its operations through the drm_bridge API.
Register a bridge at initialisation time to do so and remove the
omap_dss_device operations that are now unused.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/gpu/drm/omapdrm/dss/dpi.c | 205 ++++++++++++++++++------------
 1 file changed, 122 insertions(+), 83 deletions(-)

Comments

Hans Verkuil Aug. 27, 2019, 9:07 a.m. UTC | #1
Hi Laurent,

I tried this series with my Pandaboard, but it broke my Pandaboard. After
doing a git bisect it ended up with this patch as the culprit.

If I boot my Pandaboard I get this:

[    3.271881] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
[    3.285369] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
[   24.286773] rcu: INFO: rcu_sched self-detected stall on CPU
[   24.292388] rcu:     0-...!: (1306 ticks this GP) idle=6b6/1/0x40000002 softirq=85/85 fqs=19
[   24.300689]  (t=2100 jiffies g=-1063 q=10)
[   24.304809] rcu: rcu_sched kthread starved for 2058 jiffies! g-1063 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=1
[   24.315124] rcu: RCU grace-period kthread stack dump:
[   24.315124] rcu_sched       I    0    10      2 0x00000000
[   24.325805] [<c09b7130>] (__schedule) from [<c09b73a8>] (schedule+0x40/0xc0)
[   24.332885] [<c09b73a8>] (schedule) from [<c09ba9d0>] (schedule_timeout+0x174/0x2a8)
[   24.340698] [<c09ba9d0>] (schedule_timeout) from [<c01943a4>] (rcu_gp_kthread+0x49c/0x9f4)
[   24.349121] [<c01943a4>] (rcu_gp_kthread) from [<c01559f8>] (kthread+0x13c/0x148)
[   24.356658] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
[   24.363922] Exception stack(0xe70a1fb0 to 0xe70a1ff8)
[   24.363922] 1fa0:                                     00000000 00000000 00000000 00000000
[   24.363922] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[   24.385437] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[   24.392089] NMI backtrace for cpu 0
[   24.392120] CPU: 0 PID: 105 Comm: kworker/0:2 Not tainted 5.3.0-rc3-arm #152
[   24.392120] Hardware name: Generic OMAP4 (Flattened Device Tree)
[   24.408721] Workqueue: events deferred_probe_work_func
[   24.408721] [<c010fd70>] (unwind_backtrace) from [<c010b7e8>] (show_stack+0x10/0x14)
[   24.421783] [<c010b7e8>] (show_stack) from [<c09a054c>] (dump_stack+0x84/0x9c)
[   24.429077] [<c09a054c>] (dump_stack) from [<c09a6ecc>] (nmi_cpu_backtrace+0x8c/0xc0)
[   24.436950] [<c09a6ecc>] (nmi_cpu_backtrace) from [<c09a7014>] (nmi_trigger_cpumask_backtrace+0x114/0x12c)
[   24.446655] [<c09a7014>] (nmi_trigger_cpumask_backtrace) from [<c01961e0>] (rcu_dump_cpu_stacks+0xa4/0xcc)
[   24.456359] [<c01961e0>] (rcu_dump_cpu_stacks) from [<c01952bc>] (rcu_sched_clock_irq+0x608/0x7f8)
[   24.465362] [<c01952bc>] (rcu_sched_clock_irq) from [<c019b21c>] (update_process_times+0x34/0x6c)
[   24.465362] [<c019b21c>] (update_process_times) from [<c01acfcc>] (tick_sched_timer+0x4c/0xa8)
[   24.483001] [<c01acfcc>] (tick_sched_timer) from [<c019c470>] (__hrtimer_run_queues+0x154/0x1fc)
[   24.491851] [<c019c470>] (__hrtimer_run_queues) from [<c019c84c>] (hrtimer_interrupt+0x11c/0x2ac)
[   24.500762] [<c019c84c>] (hrtimer_interrupt) from [<c010f3ac>] (twd_handler+0x30/0x38)
[   24.500762] [<c010f3ac>] (twd_handler) from [<c018959c>] (handle_percpu_devid_irq+0x78/0x138)
[   24.517333] [<c018959c>] (handle_percpu_devid_irq) from [<c0183a60>] (generic_handle_irq+0x24/0x34)
[   24.526458] [<c0183a60>] (generic_handle_irq) from [<c0184028>] (__handle_domain_irq+0x5c/0xb4)
[   24.526458] [<c0184028>] (__handle_domain_irq) from [<c03bbf2c>] (gic_handle_irq+0x58/0x9c)
[   24.526458] [<c03bbf2c>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
[   24.526458] Exception stack(0xe6439d68 to 0xe6439db0)
[   24.551177] 9d60:                   c0f783e8 00000000 00000000 efdb49d0 e647f2e8 efdb7f74
[   24.551177] 9d80: e647f2e8 00000000 e647f294 e647f2e8 00000000 efdb5a98 00000000 e6439db8
[   24.551177] 9da0: c04e9830 c04e9858 20000153 ffffffff
[   24.577789] [<c0101a8c>] (__irq_svc) from [<c04e9858>] (of_drm_find_bridge+0x40/0x84)
[   24.577789] [<c04e9858>] (of_drm_find_bridge) from [<c0526608>] (omapdss_device_init_output+0x38/0x140)
[   24.595153] [<c0526608>] (omapdss_device_init_output) from [<c0530294>] (dpi_init_port+0x208/0x294)
[   24.604248] [<c0530294>] (dpi_init_port) from [<c05278c4>] (dss_probe+0x2b4/0x550)
[   24.604248] [<c05278c4>] (dss_probe) from [<c0576c1c>] (platform_drv_probe+0x48/0x98)
[   24.604248] [<c0576c1c>] (platform_drv_probe) from [<c0574eb0>] (really_probe+0xf0/0x2c4)
[   24.627990] [<c0574eb0>] (really_probe) from [<c057520c>] (driver_probe_device+0x60/0x168)
[   24.627990] [<c057520c>] (driver_probe_device) from [<c0573410>] (bus_for_each_drv+0x84/0xc8)
[   24.644866] [<c0573410>] (bus_for_each_drv) from [<c0574d4c>] (__device_attach+0xd4/0x140)
[   24.644866] [<c0574d4c>] (__device_attach) from [<c05740f8>] (bus_probe_device+0x84/0x8c)
[   24.661376] [<c05740f8>] (bus_probe_device) from [<c057456c>] (deferred_probe_work_func+0x64/0x90)
[   24.670379] [<c057456c>] (deferred_probe_work_func) from [<c014f960>] (process_one_work+0x204/0x41c)
[   24.670410] [<c014f960>] (process_one_work) from [<c01510d4>] (worker_thread+0x2a8/0x5bc)
[   24.687805] [<c01510d4>] (worker_thread) from [<c01559f8>] (kthread+0x13c/0x148)
[   24.687805] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
[   24.702484] Exception stack(0xe6439fb0 to 0xe6439ff8)
[   24.702484] 9fa0:                                     00000000 00000000 00000000 00000000
[   24.702484] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[   24.723999] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000

I can send my .config upon request if needed.

CONFIG_OMAP2_DSS_DPI is 'y', but there is nothing connected to the DPI port.

Regards,

	Hans

On 8/20/19 3:17 AM, Laurent Pinchart wrote:
> In order to integrate with a chain of drm_bridge, the internal DPI
> output has to expose its operations through the drm_bridge API.
> Register a bridge at initialisation time to do so and remove the
> omap_dss_device operations that are now unused.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  drivers/gpu/drm/omapdrm/dss/dpi.c | 205 ++++++++++++++++++------------
>  1 file changed, 122 insertions(+), 83 deletions(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
> index c167bd1116ec..3874e6b6ec49 100644
> --- a/drivers/gpu/drm/omapdrm/dss/dpi.c
> +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
> @@ -21,6 +21,8 @@
>  #include <linux/string.h>
>  #include <linux/sys_soc.h>
>  
> +#include <drm/drm_bridge.h>
> +
>  #include "dss.h"
>  #include "omapdss.h"
>  
> @@ -41,12 +43,10 @@ struct dpi_data {
>  	int data_lines;
>  
>  	struct omap_dss_device output;
> +	struct drm_bridge bridge;
>  };
>  
> -static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
> -{
> -	return container_of(dssdev, struct dpi_data, output);
> -}
> +#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
>  
>  /* -----------------------------------------------------------------------------
>   * Clock Handling and PLL
> @@ -354,6 +354,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
>  	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
>  }
>  
> +static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
> +{
> +	int lck_div, pck_div;
> +	unsigned long fck;
> +	struct dpi_clk_calc_ctx ctx;
> +
> +	if (dpi->pll) {
> +		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
> +			return -EINVAL;
> +
> +		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
> +	} else {
> +		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
> +			return -EINVAL;
> +
> +		fck = ctx.fck;
> +	}
> +
> +	lck_div = ctx.dispc_cinfo.lck_div;
> +	pck_div = ctx.dispc_cinfo.pck_div;
> +
> +	*clock = fck / lck_div / pck_div;
> +
> +	return 0;
> +}
> +
>  static int dpi_verify_pll(struct dss_pll *pll)
>  {
>  	int r;
> @@ -391,29 +417,76 @@ static void dpi_init_pll(struct dpi_data *dpi)
>  }
>  
>  /* -----------------------------------------------------------------------------
> - * omap_dss_device Operations
> + * DRM Bridge Operations
>   */
>  
> -static int dpi_connect(struct omap_dss_device *src,
> -		       struct omap_dss_device *dst)
> +static int dpi_bridge_attach(struct drm_bridge *bridge,
> +			     enum drm_bridge_attach_flags flags)
>  {
> -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> +
> +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
> +		return -EINVAL;
>  
>  	dpi_init_pll(dpi);
>  
> -	return omapdss_device_connect(dst->dss, dst, dst->next);
> +	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
> +				 bridge, flags);
>  }
>  
> -static void dpi_disconnect(struct omap_dss_device *src,
> -			   struct omap_dss_device *dst)
> +static enum drm_mode_status
> +dpi_bridge_mode_valid(struct drm_bridge *bridge,
> +		       const struct drm_display_mode *mode)
>  {
> -	omapdss_device_disconnect(dst, dst->next);
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> +	unsigned long clock = mode->clock * 1000;
> +	int ret;
> +
> +	if (mode->hdisplay % 8 != 0)
> +		return MODE_BAD_WIDTH;
> +
> +	if (mode->clock == 0)
> +		return MODE_NOCLOCK;
> +
> +	ret = dpi_clock_update(dpi, &clock);
> +	if (ret < 0)
> +		return MODE_CLOCK_RANGE;
> +
> +	return MODE_OK;
> +}
> +
> +static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
> +				   const struct drm_display_mode *mode,
> +				   struct drm_display_mode *adjusted_mode)
> +{
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> +	unsigned long clock = mode->clock * 1000;
> +	int ret;
> +
> +	ret = dpi_clock_update(dpi, &clock);
> +	if (ret < 0)
> +		return false;
> +
> +	adjusted_mode->clock = clock / 1000;
> +
> +	return true;
> +}
> +
> +static void dpi_bridge_mode_set(struct drm_bridge *bridge,
> +				 const struct drm_display_mode *mode,
> +				 const struct drm_display_mode *adjusted_mode)
> +{
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> +
> +	mutex_lock(&dpi->lock);
> +	dpi->pixelclock = adjusted_mode->clock * 1000;
> +	mutex_unlock(&dpi->lock);
>  }
>  
> -static void dpi_display_enable(struct omap_dss_device *dssdev)
> +static void dpi_bridge_enable(struct drm_bridge *bridge,
> +			       struct drm_atomic_state *state)
>  {
> -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> -	struct omap_dss_device *out = &dpi->output;
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
>  	int r;
>  
>  	mutex_lock(&dpi->lock);
> @@ -428,7 +501,7 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
>  	if (r)
>  		goto err_get_dispc;
>  
> -	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
> +	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
>  	if (r)
>  		goto err_src_sel;
>  
> @@ -468,9 +541,10 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
>  	mutex_unlock(&dpi->lock);
>  }
>  
> -static void dpi_display_disable(struct omap_dss_device *dssdev)
> +static void dpi_bridge_disable(struct drm_bridge *bridge,
> +				struct drm_atomic_state *state)
>  {
> -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
>  
>  	mutex_lock(&dpi->lock);
>  
> @@ -490,71 +564,33 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
>  	mutex_unlock(&dpi->lock);
>  }
>  
> -static int dpi_check_timings(struct omap_dss_device *dssdev,
> -			     struct drm_display_mode *mode)
> -{
> -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> -	int lck_div, pck_div;
> -	unsigned long fck;
> -	unsigned long pck;
> -	struct dpi_clk_calc_ctx ctx;
> -	bool ok;
> -
> -	if (mode->hdisplay % 8 != 0)
> -		return -EINVAL;
> -
> -	if (mode->clock == 0)
> -		return -EINVAL;
> -
> -	if (dpi->pll) {
> -		ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
> -		if (!ok)
> -			return -EINVAL;
> -
> -		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
> -	} else {
> -		ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
> -		if (!ok)
> -			return -EINVAL;
> -
> -		fck = ctx.fck;
> -	}
> -
> -	lck_div = ctx.dispc_cinfo.lck_div;
> -	pck_div = ctx.dispc_cinfo.pck_div;
> -
> -	pck = fck / lck_div / pck_div;
> -
> -	mode->clock = pck / 1000;
> -
> -	return 0;
> -}
> -
> -static void dpi_set_timings(struct omap_dss_device *dssdev,
> -			    const struct drm_display_mode *mode)
> -{
> -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> -
> -	DSSDBG("dpi_set_timings\n");
> -
> -	mutex_lock(&dpi->lock);
> -
> -	dpi->pixelclock = mode->clock * 1000;
> -
> -	mutex_unlock(&dpi->lock);
> -}
> -
> -static const struct omap_dss_device_ops dpi_ops = {
> -	.connect = dpi_connect,
> -	.disconnect = dpi_disconnect,
> -
> -	.enable = dpi_display_enable,
> -	.disable = dpi_display_disable,
> -
> -	.check_timings = dpi_check_timings,
> -	.set_timings = dpi_set_timings,
> +static const struct drm_bridge_funcs dpi_bridge_funcs = {
> +	.attach = dpi_bridge_attach,
> +	.mode_valid = dpi_bridge_mode_valid,
> +	.mode_fixup = dpi_bridge_mode_fixup,
> +	.mode_set = dpi_bridge_mode_set,
> +	.atomic_enable = dpi_bridge_enable,
> +	.atomic_disable = dpi_bridge_disable,
>  };
>  
> +static void dpi_bridge_init(struct dpi_data *dpi)
> +{
> +	dpi->bridge.funcs = &dpi_bridge_funcs;
> +	dpi->bridge.of_node = dpi->pdev->dev.of_node;
> +	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
> +
> +	drm_bridge_add(&dpi->bridge);
> +}
> +
> +static void dpi_bridge_cleanup(struct dpi_data *dpi)
> +{
> +	drm_bridge_remove(&dpi->bridge);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Initialisation and Cleanup
> + */
> +
>  /*
>   * Return a hardcoded channel for the DPI output. This should work for
>   * current use cases, but this can be later expanded to either resolve
> @@ -597,6 +633,8 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
>  	u32 port_num = 0;
>  	int r;
>  
> +	dpi_bridge_init(dpi);
> +
>  	of_property_read_u32(port, "reg", &port_num);
>  	dpi->id = port_num <= 2 ? port_num : 0;
>  
> @@ -618,10 +656,9 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
>  	out->type = OMAP_DISPLAY_TYPE_DPI;
>  	out->dispc_channel = dpi_get_channel(dpi);
>  	out->of_port = port_num;
> -	out->ops = &dpi_ops;
>  	out->owner = THIS_MODULE;
>  
> -	r = omapdss_device_init_output(out, NULL);
> +	r = omapdss_device_init_output(out, &dpi->bridge);
>  	if (r < 0)
>  		return r;
>  
> @@ -637,6 +674,8 @@ static void dpi_uninit_output_port(struct device_node *port)
>  
>  	omapdss_device_unregister(out);
>  	omapdss_device_cleanup_output(out);
> +
> +	dpi_bridge_cleanup(dpi);
>  }
>  
>  /* -----------------------------------------------------------------------------
>
Laurent Pinchart Aug. 27, 2019, 9:51 a.m. UTC | #2
Hi Hans,

On Tue, Aug 27, 2019 at 11:07:56AM +0200, Hans Verkuil wrote:
> Hi Laurent,
> 
> I tried this series with my Pandaboard, but it broke my Pandaboard. After
> doing a git bisect it ended up with this patch as the culprit.
> 
> If I boot my Pandaboard I get this:
> 
> [    3.271881] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
> [    3.285369] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
> [   24.286773] rcu: INFO: rcu_sched self-detected stall on CPU
> [   24.292388] rcu:     0-...!: (1306 ticks this GP) idle=6b6/1/0x40000002 softirq=85/85 fqs=19
> [   24.300689]  (t=2100 jiffies g=-1063 q=10)
> [   24.304809] rcu: rcu_sched kthread starved for 2058 jiffies! g-1063 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=1
> [   24.315124] rcu: RCU grace-period kthread stack dump:
> [   24.315124] rcu_sched       I    0    10      2 0x00000000
> [   24.325805] [<c09b7130>] (__schedule) from [<c09b73a8>] (schedule+0x40/0xc0)
> [   24.332885] [<c09b73a8>] (schedule) from [<c09ba9d0>] (schedule_timeout+0x174/0x2a8)
> [   24.340698] [<c09ba9d0>] (schedule_timeout) from [<c01943a4>] (rcu_gp_kthread+0x49c/0x9f4)
> [   24.349121] [<c01943a4>] (rcu_gp_kthread) from [<c01559f8>] (kthread+0x13c/0x148)
> [   24.356658] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
> [   24.363922] Exception stack(0xe70a1fb0 to 0xe70a1ff8)
> [   24.363922] 1fa0:                                     00000000 00000000 00000000 00000000
> [   24.363922] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> [   24.385437] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
> [   24.392089] NMI backtrace for cpu 0
> [   24.392120] CPU: 0 PID: 105 Comm: kworker/0:2 Not tainted 5.3.0-rc3-arm #152
> [   24.392120] Hardware name: Generic OMAP4 (Flattened Device Tree)
> [   24.408721] Workqueue: events deferred_probe_work_func
> [   24.408721] [<c010fd70>] (unwind_backtrace) from [<c010b7e8>] (show_stack+0x10/0x14)
> [   24.421783] [<c010b7e8>] (show_stack) from [<c09a054c>] (dump_stack+0x84/0x9c)
> [   24.429077] [<c09a054c>] (dump_stack) from [<c09a6ecc>] (nmi_cpu_backtrace+0x8c/0xc0)
> [   24.436950] [<c09a6ecc>] (nmi_cpu_backtrace) from [<c09a7014>] (nmi_trigger_cpumask_backtrace+0x114/0x12c)
> [   24.446655] [<c09a7014>] (nmi_trigger_cpumask_backtrace) from [<c01961e0>] (rcu_dump_cpu_stacks+0xa4/0xcc)
> [   24.456359] [<c01961e0>] (rcu_dump_cpu_stacks) from [<c01952bc>] (rcu_sched_clock_irq+0x608/0x7f8)
> [   24.465362] [<c01952bc>] (rcu_sched_clock_irq) from [<c019b21c>] (update_process_times+0x34/0x6c)
> [   24.465362] [<c019b21c>] (update_process_times) from [<c01acfcc>] (tick_sched_timer+0x4c/0xa8)
> [   24.483001] [<c01acfcc>] (tick_sched_timer) from [<c019c470>] (__hrtimer_run_queues+0x154/0x1fc)
> [   24.491851] [<c019c470>] (__hrtimer_run_queues) from [<c019c84c>] (hrtimer_interrupt+0x11c/0x2ac)
> [   24.500762] [<c019c84c>] (hrtimer_interrupt) from [<c010f3ac>] (twd_handler+0x30/0x38)
> [   24.500762] [<c010f3ac>] (twd_handler) from [<c018959c>] (handle_percpu_devid_irq+0x78/0x138)
> [   24.517333] [<c018959c>] (handle_percpu_devid_irq) from [<c0183a60>] (generic_handle_irq+0x24/0x34)
> [   24.526458] [<c0183a60>] (generic_handle_irq) from [<c0184028>] (__handle_domain_irq+0x5c/0xb4)
> [   24.526458] [<c0184028>] (__handle_domain_irq) from [<c03bbf2c>] (gic_handle_irq+0x58/0x9c)
> [   24.526458] [<c03bbf2c>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
> [   24.526458] Exception stack(0xe6439d68 to 0xe6439db0)
> [   24.551177] 9d60:                   c0f783e8 00000000 00000000 efdb49d0 e647f2e8 efdb7f74
> [   24.551177] 9d80: e647f2e8 00000000 e647f294 e647f2e8 00000000 efdb5a98 00000000 e6439db8
> [   24.551177] 9da0: c04e9830 c04e9858 20000153 ffffffff
> [   24.577789] [<c0101a8c>] (__irq_svc) from [<c04e9858>] (of_drm_find_bridge+0x40/0x84)
> [   24.577789] [<c04e9858>] (of_drm_find_bridge) from [<c0526608>] (omapdss_device_init_output+0x38/0x140)
> [   24.595153] [<c0526608>] (omapdss_device_init_output) from [<c0530294>] (dpi_init_port+0x208/0x294)
> [   24.604248] [<c0530294>] (dpi_init_port) from [<c05278c4>] (dss_probe+0x2b4/0x550)
> [   24.604248] [<c05278c4>] (dss_probe) from [<c0576c1c>] (platform_drv_probe+0x48/0x98)
> [   24.604248] [<c0576c1c>] (platform_drv_probe) from [<c0574eb0>] (really_probe+0xf0/0x2c4)
> [   24.627990] [<c0574eb0>] (really_probe) from [<c057520c>] (driver_probe_device+0x60/0x168)
> [   24.627990] [<c057520c>] (driver_probe_device) from [<c0573410>] (bus_for_each_drv+0x84/0xc8)
> [   24.644866] [<c0573410>] (bus_for_each_drv) from [<c0574d4c>] (__device_attach+0xd4/0x140)
> [   24.644866] [<c0574d4c>] (__device_attach) from [<c05740f8>] (bus_probe_device+0x84/0x8c)
> [   24.661376] [<c05740f8>] (bus_probe_device) from [<c057456c>] (deferred_probe_work_func+0x64/0x90)
> [   24.670379] [<c057456c>] (deferred_probe_work_func) from [<c014f960>] (process_one_work+0x204/0x41c)
> [   24.670410] [<c014f960>] (process_one_work) from [<c01510d4>] (worker_thread+0x2a8/0x5bc)
> [   24.687805] [<c01510d4>] (worker_thread) from [<c01559f8>] (kthread+0x13c/0x148)
> [   24.687805] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
> [   24.702484] Exception stack(0xe6439fb0 to 0xe6439ff8)
> [   24.702484] 9fa0:                                     00000000 00000000 00000000 00000000
> [   24.702484] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> [   24.723999] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
> 
> I can send my .config upon request if needed.
> 
> CONFIG_OMAP2_DSS_DPI is 'y', but there is nothing connected to the DPI port.

I've retested this on my pandaboard and couldn't reproduce the issue. As
I suspected a problem related to the kernel configuration, I tried
building the drivers in the kernel image instead of using modules, and I
then got a similar looking crash. I'm investigating it now.

> On 8/20/19 3:17 AM, Laurent Pinchart wrote:
> > In order to integrate with a chain of drm_bridge, the internal DPI
> > output has to expose its operations through the drm_bridge API.
> > Register a bridge at initialisation time to do so and remove the
> > omap_dss_device operations that are now unused.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  drivers/gpu/drm/omapdrm/dss/dpi.c | 205 ++++++++++++++++++------------
> >  1 file changed, 122 insertions(+), 83 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
> > index c167bd1116ec..3874e6b6ec49 100644
> > --- a/drivers/gpu/drm/omapdrm/dss/dpi.c
> > +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
> > @@ -21,6 +21,8 @@
> >  #include <linux/string.h>
> >  #include <linux/sys_soc.h>
> >  
> > +#include <drm/drm_bridge.h>
> > +
> >  #include "dss.h"
> >  #include "omapdss.h"
> >  
> > @@ -41,12 +43,10 @@ struct dpi_data {
> >  	int data_lines;
> >  
> >  	struct omap_dss_device output;
> > +	struct drm_bridge bridge;
> >  };
> >  
> > -static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
> > -{
> > -	return container_of(dssdev, struct dpi_data, output);
> > -}
> > +#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
> >  
> >  /* -----------------------------------------------------------------------------
> >   * Clock Handling and PLL
> > @@ -354,6 +354,32 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
> >  	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
> >  }
> >  
> > +static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
> > +{
> > +	int lck_div, pck_div;
> > +	unsigned long fck;
> > +	struct dpi_clk_calc_ctx ctx;
> > +
> > +	if (dpi->pll) {
> > +		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
> > +			return -EINVAL;
> > +
> > +		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
> > +	} else {
> > +		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
> > +			return -EINVAL;
> > +
> > +		fck = ctx.fck;
> > +	}
> > +
> > +	lck_div = ctx.dispc_cinfo.lck_div;
> > +	pck_div = ctx.dispc_cinfo.pck_div;
> > +
> > +	*clock = fck / lck_div / pck_div;
> > +
> > +	return 0;
> > +}
> > +
> >  static int dpi_verify_pll(struct dss_pll *pll)
> >  {
> >  	int r;
> > @@ -391,29 +417,76 @@ static void dpi_init_pll(struct dpi_data *dpi)
> >  }
> >  
> >  /* -----------------------------------------------------------------------------
> > - * omap_dss_device Operations
> > + * DRM Bridge Operations
> >   */
> >  
> > -static int dpi_connect(struct omap_dss_device *src,
> > -		       struct omap_dss_device *dst)
> > +static int dpi_bridge_attach(struct drm_bridge *bridge,
> > +			     enum drm_bridge_attach_flags flags)
> >  {
> > -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> > +
> > +	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
> > +		return -EINVAL;
> >  
> >  	dpi_init_pll(dpi);
> >  
> > -	return omapdss_device_connect(dst->dss, dst, dst->next);
> > +	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
> > +				 bridge, flags);
> >  }
> >  
> > -static void dpi_disconnect(struct omap_dss_device *src,
> > -			   struct omap_dss_device *dst)
> > +static enum drm_mode_status
> > +dpi_bridge_mode_valid(struct drm_bridge *bridge,
> > +		       const struct drm_display_mode *mode)
> >  {
> > -	omapdss_device_disconnect(dst, dst->next);
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> > +	unsigned long clock = mode->clock * 1000;
> > +	int ret;
> > +
> > +	if (mode->hdisplay % 8 != 0)
> > +		return MODE_BAD_WIDTH;
> > +
> > +	if (mode->clock == 0)
> > +		return MODE_NOCLOCK;
> > +
> > +	ret = dpi_clock_update(dpi, &clock);
> > +	if (ret < 0)
> > +		return MODE_CLOCK_RANGE;
> > +
> > +	return MODE_OK;
> > +}
> > +
> > +static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
> > +				   const struct drm_display_mode *mode,
> > +				   struct drm_display_mode *adjusted_mode)
> > +{
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> > +	unsigned long clock = mode->clock * 1000;
> > +	int ret;
> > +
> > +	ret = dpi_clock_update(dpi, &clock);
> > +	if (ret < 0)
> > +		return false;
> > +
> > +	adjusted_mode->clock = clock / 1000;
> > +
> > +	return true;
> > +}
> > +
> > +static void dpi_bridge_mode_set(struct drm_bridge *bridge,
> > +				 const struct drm_display_mode *mode,
> > +				 const struct drm_display_mode *adjusted_mode)
> > +{
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> > +
> > +	mutex_lock(&dpi->lock);
> > +	dpi->pixelclock = adjusted_mode->clock * 1000;
> > +	mutex_unlock(&dpi->lock);
> >  }
> >  
> > -static void dpi_display_enable(struct omap_dss_device *dssdev)
> > +static void dpi_bridge_enable(struct drm_bridge *bridge,
> > +			       struct drm_atomic_state *state)
> >  {
> > -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> > -	struct omap_dss_device *out = &dpi->output;
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> >  	int r;
> >  
> >  	mutex_lock(&dpi->lock);
> > @@ -428,7 +501,7 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
> >  	if (r)
> >  		goto err_get_dispc;
> >  
> > -	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
> > +	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
> >  	if (r)
> >  		goto err_src_sel;
> >  
> > @@ -468,9 +541,10 @@ static void dpi_display_enable(struct omap_dss_device *dssdev)
> >  	mutex_unlock(&dpi->lock);
> >  }
> >  
> > -static void dpi_display_disable(struct omap_dss_device *dssdev)
> > +static void dpi_bridge_disable(struct drm_bridge *bridge,
> > +				struct drm_atomic_state *state)
> >  {
> > -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> > +	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
> >  
> >  	mutex_lock(&dpi->lock);
> >  
> > @@ -490,71 +564,33 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
> >  	mutex_unlock(&dpi->lock);
> >  }
> >  
> > -static int dpi_check_timings(struct omap_dss_device *dssdev,
> > -			     struct drm_display_mode *mode)
> > -{
> > -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> > -	int lck_div, pck_div;
> > -	unsigned long fck;
> > -	unsigned long pck;
> > -	struct dpi_clk_calc_ctx ctx;
> > -	bool ok;
> > -
> > -	if (mode->hdisplay % 8 != 0)
> > -		return -EINVAL;
> > -
> > -	if (mode->clock == 0)
> > -		return -EINVAL;
> > -
> > -	if (dpi->pll) {
> > -		ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
> > -		if (!ok)
> > -			return -EINVAL;
> > -
> > -		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
> > -	} else {
> > -		ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
> > -		if (!ok)
> > -			return -EINVAL;
> > -
> > -		fck = ctx.fck;
> > -	}
> > -
> > -	lck_div = ctx.dispc_cinfo.lck_div;
> > -	pck_div = ctx.dispc_cinfo.pck_div;
> > -
> > -	pck = fck / lck_div / pck_div;
> > -
> > -	mode->clock = pck / 1000;
> > -
> > -	return 0;
> > -}
> > -
> > -static void dpi_set_timings(struct omap_dss_device *dssdev,
> > -			    const struct drm_display_mode *mode)
> > -{
> > -	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
> > -
> > -	DSSDBG("dpi_set_timings\n");
> > -
> > -	mutex_lock(&dpi->lock);
> > -
> > -	dpi->pixelclock = mode->clock * 1000;
> > -
> > -	mutex_unlock(&dpi->lock);
> > -}
> > -
> > -static const struct omap_dss_device_ops dpi_ops = {
> > -	.connect = dpi_connect,
> > -	.disconnect = dpi_disconnect,
> > -
> > -	.enable = dpi_display_enable,
> > -	.disable = dpi_display_disable,
> > -
> > -	.check_timings = dpi_check_timings,
> > -	.set_timings = dpi_set_timings,
> > +static const struct drm_bridge_funcs dpi_bridge_funcs = {
> > +	.attach = dpi_bridge_attach,
> > +	.mode_valid = dpi_bridge_mode_valid,
> > +	.mode_fixup = dpi_bridge_mode_fixup,
> > +	.mode_set = dpi_bridge_mode_set,
> > +	.atomic_enable = dpi_bridge_enable,
> > +	.atomic_disable = dpi_bridge_disable,
> >  };
> >  
> > +static void dpi_bridge_init(struct dpi_data *dpi)
> > +{
> > +	dpi->bridge.funcs = &dpi_bridge_funcs;
> > +	dpi->bridge.of_node = dpi->pdev->dev.of_node;
> > +	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
> > +
> > +	drm_bridge_add(&dpi->bridge);
> > +}
> > +
> > +static void dpi_bridge_cleanup(struct dpi_data *dpi)
> > +{
> > +	drm_bridge_remove(&dpi->bridge);
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Initialisation and Cleanup
> > + */
> > +
> >  /*
> >   * Return a hardcoded channel for the DPI output. This should work for
> >   * current use cases, but this can be later expanded to either resolve
> > @@ -597,6 +633,8 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
> >  	u32 port_num = 0;
> >  	int r;
> >  
> > +	dpi_bridge_init(dpi);
> > +
> >  	of_property_read_u32(port, "reg", &port_num);
> >  	dpi->id = port_num <= 2 ? port_num : 0;
> >  
> > @@ -618,10 +656,9 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
> >  	out->type = OMAP_DISPLAY_TYPE_DPI;
> >  	out->dispc_channel = dpi_get_channel(dpi);
> >  	out->of_port = port_num;
> > -	out->ops = &dpi_ops;
> >  	out->owner = THIS_MODULE;
> >  
> > -	r = omapdss_device_init_output(out, NULL);
> > +	r = omapdss_device_init_output(out, &dpi->bridge);
> >  	if (r < 0)
> >  		return r;
> >  
> > @@ -637,6 +674,8 @@ static void dpi_uninit_output_port(struct device_node *port)
> >  
> >  	omapdss_device_unregister(out);
> >  	omapdss_device_cleanup_output(out);
> > +
> > +	dpi_bridge_cleanup(dpi);
> >  }
> >  
> >  /* -----------------------------------------------------------------------------
> > 
>
Laurent Pinchart Aug. 27, 2019, 10:48 a.m. UTC | #3
Hi Hans,

On Tue, Aug 27, 2019 at 12:51:08PM +0300, Laurent Pinchart wrote:
> On Tue, Aug 27, 2019 at 11:07:56AM +0200, Hans Verkuil wrote:
> > Hi Laurent,
> > 
> > I tried this series with my Pandaboard, but it broke my Pandaboard. After
> > doing a git bisect it ended up with this patch as the culprit.
> > 
> > If I boot my Pandaboard I get this:
> > 
> > [    3.271881] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
> > [    3.285369] omapdss_dss 58000000.dss: 58000000.dss supply vdda_video not found, using dummy regulator
> > [   24.286773] rcu: INFO: rcu_sched self-detected stall on CPU
> > [   24.292388] rcu:     0-...!: (1306 ticks this GP) idle=6b6/1/0x40000002 softirq=85/85 fqs=19
> > [   24.300689]  (t=2100 jiffies g=-1063 q=10)
> > [   24.304809] rcu: rcu_sched kthread starved for 2058 jiffies! g-1063 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=1
> > [   24.315124] rcu: RCU grace-period kthread stack dump:
> > [   24.315124] rcu_sched       I    0    10      2 0x00000000
> > [   24.325805] [<c09b7130>] (__schedule) from [<c09b73a8>] (schedule+0x40/0xc0)
> > [   24.332885] [<c09b73a8>] (schedule) from [<c09ba9d0>] (schedule_timeout+0x174/0x2a8)
> > [   24.340698] [<c09ba9d0>] (schedule_timeout) from [<c01943a4>] (rcu_gp_kthread+0x49c/0x9f4)
> > [   24.349121] [<c01943a4>] (rcu_gp_kthread) from [<c01559f8>] (kthread+0x13c/0x148)
> > [   24.356658] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
> > [   24.363922] Exception stack(0xe70a1fb0 to 0xe70a1ff8)
> > [   24.363922] 1fa0:                                     00000000 00000000 00000000 00000000
> > [   24.363922] 1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> > [   24.385437] 1fe0: 00000000 00000000 00000000 00000000 00000013 00000000
> > [   24.392089] NMI backtrace for cpu 0
> > [   24.392120] CPU: 0 PID: 105 Comm: kworker/0:2 Not tainted 5.3.0-rc3-arm #152
> > [   24.392120] Hardware name: Generic OMAP4 (Flattened Device Tree)
> > [   24.408721] Workqueue: events deferred_probe_work_func
> > [   24.408721] [<c010fd70>] (unwind_backtrace) from [<c010b7e8>] (show_stack+0x10/0x14)
> > [   24.421783] [<c010b7e8>] (show_stack) from [<c09a054c>] (dump_stack+0x84/0x9c)
> > [   24.429077] [<c09a054c>] (dump_stack) from [<c09a6ecc>] (nmi_cpu_backtrace+0x8c/0xc0)
> > [   24.436950] [<c09a6ecc>] (nmi_cpu_backtrace) from [<c09a7014>] (nmi_trigger_cpumask_backtrace+0x114/0x12c)
> > [   24.446655] [<c09a7014>] (nmi_trigger_cpumask_backtrace) from [<c01961e0>] (rcu_dump_cpu_stacks+0xa4/0xcc)
> > [   24.456359] [<c01961e0>] (rcu_dump_cpu_stacks) from [<c01952bc>] (rcu_sched_clock_irq+0x608/0x7f8)
> > [   24.465362] [<c01952bc>] (rcu_sched_clock_irq) from [<c019b21c>] (update_process_times+0x34/0x6c)
> > [   24.465362] [<c019b21c>] (update_process_times) from [<c01acfcc>] (tick_sched_timer+0x4c/0xa8)
> > [   24.483001] [<c01acfcc>] (tick_sched_timer) from [<c019c470>] (__hrtimer_run_queues+0x154/0x1fc)
> > [   24.491851] [<c019c470>] (__hrtimer_run_queues) from [<c019c84c>] (hrtimer_interrupt+0x11c/0x2ac)
> > [   24.500762] [<c019c84c>] (hrtimer_interrupt) from [<c010f3ac>] (twd_handler+0x30/0x38)
> > [   24.500762] [<c010f3ac>] (twd_handler) from [<c018959c>] (handle_percpu_devid_irq+0x78/0x138)
> > [   24.517333] [<c018959c>] (handle_percpu_devid_irq) from [<c0183a60>] (generic_handle_irq+0x24/0x34)
> > [   24.526458] [<c0183a60>] (generic_handle_irq) from [<c0184028>] (__handle_domain_irq+0x5c/0xb4)
> > [   24.526458] [<c0184028>] (__handle_domain_irq) from [<c03bbf2c>] (gic_handle_irq+0x58/0x9c)
> > [   24.526458] [<c03bbf2c>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
> > [   24.526458] Exception stack(0xe6439d68 to 0xe6439db0)
> > [   24.551177] 9d60:                   c0f783e8 00000000 00000000 efdb49d0 e647f2e8 efdb7f74
> > [   24.551177] 9d80: e647f2e8 00000000 e647f294 e647f2e8 00000000 efdb5a98 00000000 e6439db8
> > [   24.551177] 9da0: c04e9830 c04e9858 20000153 ffffffff
> > [   24.577789] [<c0101a8c>] (__irq_svc) from [<c04e9858>] (of_drm_find_bridge+0x40/0x84)
> > [   24.577789] [<c04e9858>] (of_drm_find_bridge) from [<c0526608>] (omapdss_device_init_output+0x38/0x140)
> > [   24.595153] [<c0526608>] (omapdss_device_init_output) from [<c0530294>] (dpi_init_port+0x208/0x294)
> > [   24.604248] [<c0530294>] (dpi_init_port) from [<c05278c4>] (dss_probe+0x2b4/0x550)
> > [   24.604248] [<c05278c4>] (dss_probe) from [<c0576c1c>] (platform_drv_probe+0x48/0x98)
> > [   24.604248] [<c0576c1c>] (platform_drv_probe) from [<c0574eb0>] (really_probe+0xf0/0x2c4)
> > [   24.627990] [<c0574eb0>] (really_probe) from [<c057520c>] (driver_probe_device+0x60/0x168)
> > [   24.627990] [<c057520c>] (driver_probe_device) from [<c0573410>] (bus_for_each_drv+0x84/0xc8)
> > [   24.644866] [<c0573410>] (bus_for_each_drv) from [<c0574d4c>] (__device_attach+0xd4/0x140)
> > [   24.644866] [<c0574d4c>] (__device_attach) from [<c05740f8>] (bus_probe_device+0x84/0x8c)
> > [   24.661376] [<c05740f8>] (bus_probe_device) from [<c057456c>] (deferred_probe_work_func+0x64/0x90)
> > [   24.670379] [<c057456c>] (deferred_probe_work_func) from [<c014f960>] (process_one_work+0x204/0x41c)
> > [   24.670410] [<c014f960>] (process_one_work) from [<c01510d4>] (worker_thread+0x2a8/0x5bc)
> > [   24.687805] [<c01510d4>] (worker_thread) from [<c01559f8>] (kthread+0x13c/0x148)
> > [   24.687805] [<c01559f8>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
> > [   24.702484] Exception stack(0xe6439fb0 to 0xe6439ff8)
> > [   24.702484] 9fa0:                                     00000000 00000000 00000000 00000000
> > [   24.702484] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
> > [   24.723999] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
> > 
> > I can send my .config upon request if needed.
> > 
> > CONFIG_OMAP2_DSS_DPI is 'y', but there is nothing connected to the DPI port.
> 
> I've retested this on my pandaboard and couldn't reproduce the issue. As
> I suspected a problem related to the kernel configuration, I tried
> building the drivers in the kernel image instead of using modules, and I
> then got a similar looking crash. I'm investigating it now.

Fix pushed to

	git://linuxtv.org/pinchartl/media.git omapdrm/bridge/devel

The issue was caused by incorrect cleanup on probe deferral, fixed by a
combination of "drm/omap: dss: Cleanup DSS ports on initialisation
failure" (new patch) and changes to "drm/omap: dpi: Register a
drm_bridge" and "drm/omap: spi: Register a drm_bridge".
diff mbox series

Patch

diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index c167bd1116ec..3874e6b6ec49 100644
--- a/drivers/gpu/drm/omapdrm/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -21,6 +21,8 @@ 
 #include <linux/string.h>
 #include <linux/sys_soc.h>
 
+#include <drm/drm_bridge.h>
+
 #include "dss.h"
 #include "omapdss.h"
 
@@ -41,12 +43,10 @@  struct dpi_data {
 	int data_lines;
 
 	struct omap_dss_device output;
+	struct drm_bridge bridge;
 };
 
-static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
-{
-	return container_of(dssdev, struct dpi_data, output);
-}
+#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
 
 /* -----------------------------------------------------------------------------
  * Clock Handling and PLL
@@ -354,6 +354,32 @@  static void dpi_config_lcd_manager(struct dpi_data *dpi)
 	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
 }
 
+static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
+{
+	int lck_div, pck_div;
+	unsigned long fck;
+	struct dpi_clk_calc_ctx ctx;
+
+	if (dpi->pll) {
+		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
+			return -EINVAL;
+
+		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
+	} else {
+		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
+			return -EINVAL;
+
+		fck = ctx.fck;
+	}
+
+	lck_div = ctx.dispc_cinfo.lck_div;
+	pck_div = ctx.dispc_cinfo.pck_div;
+
+	*clock = fck / lck_div / pck_div;
+
+	return 0;
+}
+
 static int dpi_verify_pll(struct dss_pll *pll)
 {
 	int r;
@@ -391,29 +417,76 @@  static void dpi_init_pll(struct dpi_data *dpi)
 }
 
 /* -----------------------------------------------------------------------------
- * omap_dss_device Operations
+ * DRM Bridge Operations
  */
 
-static int dpi_connect(struct omap_dss_device *src,
-		       struct omap_dss_device *dst)
+static int dpi_bridge_attach(struct drm_bridge *bridge,
+			     enum drm_bridge_attach_flags flags)
 {
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+
+	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
+		return -EINVAL;
 
 	dpi_init_pll(dpi);
 
-	return omapdss_device_connect(dst->dss, dst, dst->next);
+	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
+				 bridge, flags);
 }
 
-static void dpi_disconnect(struct omap_dss_device *src,
-			   struct omap_dss_device *dst)
+static enum drm_mode_status
+dpi_bridge_mode_valid(struct drm_bridge *bridge,
+		       const struct drm_display_mode *mode)
 {
-	omapdss_device_disconnect(dst, dst->next);
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+	unsigned long clock = mode->clock * 1000;
+	int ret;
+
+	if (mode->hdisplay % 8 != 0)
+		return MODE_BAD_WIDTH;
+
+	if (mode->clock == 0)
+		return MODE_NOCLOCK;
+
+	ret = dpi_clock_update(dpi, &clock);
+	if (ret < 0)
+		return MODE_CLOCK_RANGE;
+
+	return MODE_OK;
+}
+
+static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
+				   const struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+	unsigned long clock = mode->clock * 1000;
+	int ret;
+
+	ret = dpi_clock_update(dpi, &clock);
+	if (ret < 0)
+		return false;
+
+	adjusted_mode->clock = clock / 1000;
+
+	return true;
+}
+
+static void dpi_bridge_mode_set(struct drm_bridge *bridge,
+				 const struct drm_display_mode *mode,
+				 const struct drm_display_mode *adjusted_mode)
+{
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
+
+	mutex_lock(&dpi->lock);
+	dpi->pixelclock = adjusted_mode->clock * 1000;
+	mutex_unlock(&dpi->lock);
 }
 
-static void dpi_display_enable(struct omap_dss_device *dssdev)
+static void dpi_bridge_enable(struct drm_bridge *bridge,
+			       struct drm_atomic_state *state)
 {
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-	struct omap_dss_device *out = &dpi->output;
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
 	int r;
 
 	mutex_lock(&dpi->lock);
@@ -428,7 +501,7 @@  static void dpi_display_enable(struct omap_dss_device *dssdev)
 	if (r)
 		goto err_get_dispc;
 
-	r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
+	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
 	if (r)
 		goto err_src_sel;
 
@@ -468,9 +541,10 @@  static void dpi_display_enable(struct omap_dss_device *dssdev)
 	mutex_unlock(&dpi->lock);
 }
 
-static void dpi_display_disable(struct omap_dss_device *dssdev)
+static void dpi_bridge_disable(struct drm_bridge *bridge,
+				struct drm_atomic_state *state)
 {
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
 
 	mutex_lock(&dpi->lock);
 
@@ -490,71 +564,33 @@  static void dpi_display_disable(struct omap_dss_device *dssdev)
 	mutex_unlock(&dpi->lock);
 }
 
-static int dpi_check_timings(struct omap_dss_device *dssdev,
-			     struct drm_display_mode *mode)
-{
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-	int lck_div, pck_div;
-	unsigned long fck;
-	unsigned long pck;
-	struct dpi_clk_calc_ctx ctx;
-	bool ok;
-
-	if (mode->hdisplay % 8 != 0)
-		return -EINVAL;
-
-	if (mode->clock == 0)
-		return -EINVAL;
-
-	if (dpi->pll) {
-		ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
-		if (!ok)
-			return -EINVAL;
-
-		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
-	} else {
-		ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
-		if (!ok)
-			return -EINVAL;
-
-		fck = ctx.fck;
-	}
-
-	lck_div = ctx.dispc_cinfo.lck_div;
-	pck_div = ctx.dispc_cinfo.pck_div;
-
-	pck = fck / lck_div / pck_div;
-
-	mode->clock = pck / 1000;
-
-	return 0;
-}
-
-static void dpi_set_timings(struct omap_dss_device *dssdev,
-			    const struct drm_display_mode *mode)
-{
-	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
-
-	DSSDBG("dpi_set_timings\n");
-
-	mutex_lock(&dpi->lock);
-
-	dpi->pixelclock = mode->clock * 1000;
-
-	mutex_unlock(&dpi->lock);
-}
-
-static const struct omap_dss_device_ops dpi_ops = {
-	.connect = dpi_connect,
-	.disconnect = dpi_disconnect,
-
-	.enable = dpi_display_enable,
-	.disable = dpi_display_disable,
-
-	.check_timings = dpi_check_timings,
-	.set_timings = dpi_set_timings,
+static const struct drm_bridge_funcs dpi_bridge_funcs = {
+	.attach = dpi_bridge_attach,
+	.mode_valid = dpi_bridge_mode_valid,
+	.mode_fixup = dpi_bridge_mode_fixup,
+	.mode_set = dpi_bridge_mode_set,
+	.atomic_enable = dpi_bridge_enable,
+	.atomic_disable = dpi_bridge_disable,
 };
 
+static void dpi_bridge_init(struct dpi_data *dpi)
+{
+	dpi->bridge.funcs = &dpi_bridge_funcs;
+	dpi->bridge.of_node = dpi->pdev->dev.of_node;
+	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
+
+	drm_bridge_add(&dpi->bridge);
+}
+
+static void dpi_bridge_cleanup(struct dpi_data *dpi)
+{
+	drm_bridge_remove(&dpi->bridge);
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialisation and Cleanup
+ */
+
 /*
  * Return a hardcoded channel for the DPI output. This should work for
  * current use cases, but this can be later expanded to either resolve
@@ -597,6 +633,8 @@  static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
 	u32 port_num = 0;
 	int r;
 
+	dpi_bridge_init(dpi);
+
 	of_property_read_u32(port, "reg", &port_num);
 	dpi->id = port_num <= 2 ? port_num : 0;
 
@@ -618,10 +656,9 @@  static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
 	out->type = OMAP_DISPLAY_TYPE_DPI;
 	out->dispc_channel = dpi_get_channel(dpi);
 	out->of_port = port_num;
-	out->ops = &dpi_ops;
 	out->owner = THIS_MODULE;
 
-	r = omapdss_device_init_output(out, NULL);
+	r = omapdss_device_init_output(out, &dpi->bridge);
 	if (r < 0)
 		return r;
 
@@ -637,6 +674,8 @@  static void dpi_uninit_output_port(struct device_node *port)
 
 	omapdss_device_unregister(out);
 	omapdss_device_cleanup_output(out);
+
+	dpi_bridge_cleanup(dpi);
 }
 
 /* -----------------------------------------------------------------------------