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 |
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); > } > > /* ----------------------------------------------------------------------------- >
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); > > } > > > > /* ----------------------------------------------------------------------------- > > >
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 --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); } /* -----------------------------------------------------------------------------
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(-)