On 5/17/19 5:42 PM, Dariusz Marcinkiewicz wrote: > This patch makes dw-hdmi pass DRM connector info to a respective > CEC adapter. In order to be able to do that it delays creation of > the dw-hdmi-cec platform device until DRM connector is initialized. > > Requires testing. Testing this patch with the Khadas VIM2 board gives this kernel warning: [ 3.468499] meson-dw-hdmi c883a000.hdmi-tx: Detected HDMI TX controller v2.01a with HDCP (meson_dw_hdmi_phy) [ 3.473123] meson-dw-hdmi c883a000.hdmi-tx: registered DesignWare HDMI I2C bus driver [ 3.481151] WARNING: CPU: 4 PID: 66 at mm/page_alloc.c:4584 __alloc_pages_nodemask+0x7c8/0xb98 [ 3.488962] Modules linked in: [ 3.491984] CPU: 4 PID: 66 Comm: kworker/4:1 Not tainted 5.1.0-rc1-arm64 #26 [ 3.498965] Hardware name: Khadas VIM2 (DT) [ 3.503114] Workqueue: events deferred_probe_work_func [ 3.508197] pstate: 20000005 (nzCv daif -PAN -UAO) [ 3.512941] pc : __alloc_pages_nodemask+0x7c8/0xb98 [ 3.517771] lr : alloc_pages_current+0x80/0xf0 [ 3.522167] sp : ffff0000119db680 [ 3.525444] x29: ffff0000119db680 x28: 0000000000000000 [ 3.530705] x27: ffff000010c0d108 x26: ffff8000be900cf0 [ 3.535966] x25: 0000000000000001 x24: ffff8000be93d400 [ 3.541228] x23: ffff00001119cd90 x22: ffff8000be900c80 [ 3.546489] x21: 0000000000000000 x20: 000000000000001a [ 3.551750] x19: 0000000000040cc0 x18: 0000000000000001 [ 3.557011] x17: 0000000000000001 x16: 0000000000000019 [ 3.562273] x15: ffffffffffffffff x14: ffff00001103d6c8 [ 3.567534] x13: ffff8000be529e09 x12: 0000000000000018 [ 3.572795] x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f [ 3.578056] x9 : 0000000000000000 x8 : ffff8000bdb4f000 [ 3.583317] x7 : ffff8000bdb4ecf0 x6 : 0000000000000041 [ 3.588579] x5 : 0000000000000000 x4 : ffff00001103d6c8 [ 3.593840] x3 : 0000000000000000 x2 : 0000000000000000 [ 3.599101] x1 : 000000000000001a x0 : 0000000000040cc0 [ 3.604363] Call trace: [ 3.606781] __alloc_pages_nodemask+0x7c8/0xb98 [ 3.611264] alloc_pages_current+0x80/0xf0 [ 3.615320] kmalloc_order+0x14/0x38 [ 3.618857] __kmalloc_track_caller+0x1c8/0x220 [ 3.623341] kmemdup+0x28/0x50 [ 3.626360] platform_device_add_resources+0x30/0x68 [ 3.631275] platform_device_register_full+0xa8/0x130 [ 3.636279] dw_hdmi_bridge_attach+0xc4/0xd0 [ 3.640507] drm_bridge_attach+0x64/0xc0 [ 3.644384] dw_hdmi_bind+0x4c/0x98 [ 3.647838] meson_dw_hdmi_bind+0x424/0x568 [ 3.651975] component_bind_all+0x110/0x238 [ 3.656116] meson_drv_bind_master+0x308/0x488 [ 3.660514] meson_drv_bind+0x10/0x18 [ 3.664136] try_to_bring_up_master+0x164/0x1c0 [ 3.668621] component_master_add_with_match+0xbc/0xf8 [ 3.673710] meson_drv_probe+0xd0/0x120 [ 3.677505] platform_drv_probe+0x50/0xa8 [ 3.681472] really_probe+0x1c8/0x2a0 [ 3.685094] driver_probe_device+0x54/0xf0 [ 3.689148] __device_attach_driver+0x80/0xb8 [ 3.693463] bus_for_each_drv+0x78/0xc8 [ 3.697255] __device_attach+0xd4/0x130 [ 3.701051] device_initial_probe+0x10/0x18 [ 3.705190] bus_probe_device+0x90/0x98 [ 3.708986] deferred_probe_work_func+0x6c/0xa0 [ 3.713473] process_one_work+0x1e0/0x330 [ 3.717439] worker_thread+0x240/0x448 [ 3.721150] kthread+0x120/0x128 [ 3.724340] ret_from_fork+0x10/0x1c [ 3.727874] ---[ end trace 729b3a53d3f3eac1 ]--- [ 3.732510] meson-drm d0100000.vpu: bound c883a000.hdmi-tx (ops meson_dw_hdmi_ops) [ 3.740366] [drm] Initialized meson 1.0.0 20161109 for d0100000.vpu on minor 0 [ 3.747158] [drm] Cannot find any crtc or sizes [ 3.752380] libphy: mdio_mux: probed [ 3.755243] [drm] Cannot find any crtc or sizes If I revert this patch, then it's fine again. I get this even if CONFIG_DRM_DW_HDMI_CEC is not set. The Khadas VIM2 board uses dw-hdmi for the HDMI support, but it uses its own CEC meson driver. I do have other HW that uses dw-hdmi for CEC, but won't have access to it until next week. Regards, Hans > > Signed-off-by: Dariusz Marcinkiewicz <darekm@xxxxxxxxxx> > --- > drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 5 +- > drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.h | 2 + > drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 82 +++++++++++-------- > 3 files changed, 52 insertions(+), 37 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c > index 84fb7b6a0a5e0..cf879629e0726 100644 > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c > @@ -232,6 +232,7 @@ static void dw_hdmi_cec_del(void *data) > static int dw_hdmi_cec_probe(struct platform_device *pdev) > { > struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev); > + struct cec_connector_info conn_info; > struct dw_hdmi_cec *cec; > int ret; > > @@ -258,10 +259,12 @@ static int dw_hdmi_cec_probe(struct platform_device *pdev) > dw_hdmi_write(cec, ~0, HDMI_IH_MUTE_CEC_STAT0); > dw_hdmi_write(cec, 0, HDMI_CEC_POLARITY); > > + cec_fill_connector_info(&conn_info, data->connector); > + > cec->adap = cec_allocate_adapter(&dw_hdmi_cec_ops, cec, "dw_hdmi", > CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | > CEC_CAP_RC | CEC_CAP_PASSTHROUGH, > - CEC_MAX_LOG_ADDRS, NULL); > + CEC_MAX_LOG_ADDRS, &conn_info); > if (IS_ERR(cec->adap)) > return PTR_ERR(cec->adap); > > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.h > index cf4dc121a2c43..a2ac91ec845ed 100644 > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.h > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.h > @@ -1,6 +1,7 @@ > #ifndef DW_HDMI_CEC_H > #define DW_HDMI_CEC_H > > +struct drm_connector; > struct dw_hdmi; > > struct dw_hdmi_cec_ops { > @@ -13,6 +14,7 @@ struct dw_hdmi_cec_ops { > struct dw_hdmi_cec_data { > struct dw_hdmi *hdmi; > const struct dw_hdmi_cec_ops *ops; > + const struct drm_connector *connector; > int irq; > }; > > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c > index ab7968c8f6a29..1275cb74299a8 100644 > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c > @@ -138,6 +138,8 @@ struct dw_hdmi { > struct drm_connector connector; > struct drm_bridge bridge; > > + int irq; > + > unsigned int version; > > struct platform_device *audio; > @@ -189,6 +191,7 @@ struct dw_hdmi { > void (*enable_audio)(struct dw_hdmi *hdmi); > void (*disable_audio)(struct dw_hdmi *hdmi); > > + bool cec_configured; > struct cec_notifier *cec_notifier; > }; > > @@ -2113,6 +2116,29 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = > .get_modes = dw_hdmi_connector_get_modes, > }; > > +static void dw_hdmi_cec_enable(struct dw_hdmi *hdmi) > +{ > + mutex_lock(&hdmi->mutex); > + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; > + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); > + mutex_unlock(&hdmi->mutex); > +} > + > +static void dw_hdmi_cec_disable(struct dw_hdmi *hdmi) > +{ > + mutex_lock(&hdmi->mutex); > + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; > + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); > + mutex_unlock(&hdmi->mutex); > +} > + > +static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = { > + .write = hdmi_writeb, > + .read = hdmi_readb, > + .enable = dw_hdmi_cec_enable, > + .disable = dw_hdmi_cec_disable, > +}; > + > static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) > { > struct dw_hdmi *hdmi = bridge->driver_private; > @@ -2129,6 +2155,23 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) > > drm_connector_attach_encoder(connector, encoder); > > + if (hdmi->cec_configured) { > + struct platform_device_info pdevinfo; > + struct dw_hdmi_cec_data cec; > + > + cec.hdmi = hdmi; > + cec.ops = &dw_hdmi_cec_ops; > + cec.irq = hdmi->irq; > + cec.connector = connector; > + > + pdevinfo.name = "dw-hdmi-cec"; > + pdevinfo.data = &cec; > + pdevinfo.size_data = sizeof(cec); > + pdevinfo.dma_mask = 0; > + > + hdmi->cec = platform_device_register_full(&pdevinfo); > + } > + > return 0; > } > > @@ -2398,29 +2441,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) > return -ENODEV; > } > > -static void dw_hdmi_cec_enable(struct dw_hdmi *hdmi) > -{ > - mutex_lock(&hdmi->mutex); > - hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE; > - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); > - mutex_unlock(&hdmi->mutex); > -} > - > -static void dw_hdmi_cec_disable(struct dw_hdmi *hdmi) > -{ > - mutex_lock(&hdmi->mutex); > - hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE; > - hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); > - mutex_unlock(&hdmi->mutex); > -} > - > -static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = { > - .write = hdmi_writeb, > - .read = hdmi_readb, > - .enable = dw_hdmi_cec_enable, > - .disable = dw_hdmi_cec_disable, > -}; > - > static const struct regmap_config hdmi_regmap_8bit_config = { > .reg_bits = 32, > .val_bits = 8, > @@ -2443,7 +2463,6 @@ __dw_hdmi_probe(struct platform_device *pdev, > struct device_node *np = dev->of_node; > struct platform_device_info pdevinfo; > struct device_node *ddc_node; > - struct dw_hdmi_cec_data cec; > struct dw_hdmi *hdmi; > struct resource *iores = NULL; > int irq; > @@ -2593,6 +2612,7 @@ __dw_hdmi_probe(struct platform_device *pdev, > ret = irq; > goto err_iahb; > } > + hdmi->irq = irq; > > ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq, > dw_hdmi_irq, IRQF_SHARED, > @@ -2668,18 +2688,8 @@ __dw_hdmi_probe(struct platform_device *pdev, > hdmi->audio = platform_device_register_full(&pdevinfo); > } > > - if (config0 & HDMI_CONFIG0_CEC) { > - cec.hdmi = hdmi; > - cec.ops = &dw_hdmi_cec_ops; > - cec.irq = irq; > - > - pdevinfo.name = "dw-hdmi-cec"; > - pdevinfo.data = &cec; > - pdevinfo.size_data = sizeof(cec); > - pdevinfo.dma_mask = 0; > - > - hdmi->cec = platform_device_register_full(&pdevinfo); > - } > + if (config0 & HDMI_CONFIG0_CEC) > + hdmi->cec_configured = true; > > /* Reset HDMI DDC I2C master controller and mute I2CM interrupts */ > if (hdmi->i2c) >