diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 8b4a500347fb..641691fc92c8 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -12,7 +12,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -207,11 +210,41 @@ static void mxsfb_irq_uninstall(struct drm_device *dev) free_irq(mxsfb->irq, dev); } +static int mxsfb_of_bus_fmt(const struct device_node *ep, u32 *bus_format) +{ + u32 bus_width; + int ret; + + ret = of_property_read_u32(ep, "bus-width", &bus_width); + if (ret == -EINVAL) + return 0; + if (ret) + return ret; + + switch (bus_width) { + case 16: + *bus_format = MEDIA_BUS_FMT_RGB565_1X16; + break; + case 18: + *bus_format = MEDIA_BUS_FMT_RGB666_1X18; + break; + case 24: + *bus_format = MEDIA_BUS_FMT_RGB888_1X24; + break; + default: + return -EINVAL; + } + + return 0; +} + static int mxsfb_load(struct drm_device *drm, const struct mxsfb_devdata *devdata) { struct platform_device *pdev = to_platform_device(drm->dev); + struct device_node *np = pdev->dev.of_node; struct mxsfb_drm_private *mxsfb; + struct device_node *ep; int ret; mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL); @@ -238,6 +271,16 @@ static int mxsfb_load(struct drm_device *drm, if (IS_ERR(mxsfb->clk_disp_axi)) mxsfb->clk_disp_axi = NULL; + ep = of_graph_get_next_endpoint(np, NULL); + if (ep) { + ret = mxsfb_of_bus_fmt(ep, &mxsfb->bus_format); + of_node_put(ep); + if (ret) { + dev_err(drm->dev, "Invalid bus-width endpoint property\n"); + return ret; + } + } + ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h index d160d921b25f..bdc47ce5be79 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h @@ -46,6 +46,8 @@ struct mxsfb_drm_private { struct drm_connector *connector; struct drm_bridge *bridge; + u32 bus_format; + bool crc_active; }; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c index 6e82f8f76793..bbc2a2df9f16 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_kms.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c @@ -386,6 +386,18 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, if (!bus_format) bus_format = MEDIA_BUS_FMT_RGB888_1X24; + /* + * Prefer the bus format derived from the OF graph endpoint "bus-width" + * property when available. Otherwise, use the bus format reported by + * the downstream bridge or panel. + * + * This supports mismatched display and interface bus widths, such as + * a 24-bit panel connected through an 18-bit interface or an 18-bit + * panel connected through a 24-bit interface. + */ + if (mxsfb->bus_format) + bus_format = mxsfb->bus_format; + mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format); /* Write cur_buf as well to avoid an initial corrupt frame */