diff options
Diffstat (limited to 'drivers/gpu/drm/imx/ipuv3')
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/imx-drm-core.c | 56 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/imx-drm.h | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/imx-ldb.c | 218 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/imx-tve.c | 45 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 27 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/ipuv3/parallel-display.c | 167 |
9 files changed, 181 insertions, 378 deletions
diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig index bb278a369575..acaf25089001 100644 --- a/drivers/gpu/drm/imx/ipuv3/Kconfig +++ b/drivers/gpu/drm/imx/ipuv3/Kconfig @@ -1,18 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_IMX tristate "DRM Support for Freescale i.MX" + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select VIDEOMODE_HELPERS select DRM_GEM_DMA_HELPER - depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST) + depends on DRM && (ARCH_MXC || COMPILE_TEST) depends on IMX_IPUV3_CORE help enable i.MX graphics support config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" - select DRM_PANEL depends on DRM_IMX + select DRM_BRIDGE + select DRM_BRIDGE_CONNECTOR + select DRM_IMX_LEGACY_BRIDGE + select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS config DRM_IMX_TVE @@ -26,9 +30,13 @@ config DRM_IMX_TVE config DRM_IMX_LDB tristate "Support for LVDS displays" - depends on DRM_IMX && MFD_SYSCON + depends on DRM_IMX depends on COMMON_CLK - select DRM_PANEL + select MFD_SYSCON + select DRM_BRIDGE + select DRM_BRIDGE_CONNECTOR + select DRM_PANEL_BRIDGE + select DRM_IMX_LEGACY_BRIDGE help Choose this to enable the internal LVDS Display Bridge (LDB) found on i.MX53 and i.MX6 processors. diff --git a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c index a2277a0d6d06..07e5f96202d4 100644 --- a/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c @@ -255,14 +255,12 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) return ret; } -static int dw_hdmi_imx_remove(struct platform_device *pdev) +static void dw_hdmi_imx_remove(struct platform_device *pdev) { struct imx_hdmi *hdmi = platform_get_drvdata(pdev); component_del(&pdev->dev, &dw_hdmi_imx_ops); dw_hdmi_remove(hdmi->hdmi); - - return 0; } static struct platform_driver dw_hdmi_imx_platform_driver = { @@ -280,4 +278,3 @@ MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>"); MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:dwhdmi-imx"); diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c index e060fa6cbcb9..eddb471119c6 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c @@ -13,10 +13,13 @@ #include <video/imx-ipu-v3.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fbdev_generic.h> +#include <drm/drm_dumb_buffers.h> +#include <drm/drm_fbdev_dma.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> @@ -34,13 +37,6 @@ module_param(legacyfb_depth, int, 0444); DEFINE_DRM_GEM_DMA_FOPS(imx_drm_driver_fops); -void imx_drm_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} -EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); - static int imx_drm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -147,28 +143,45 @@ static int imx_drm_dumb_create(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args) { - u32 width = args->width; + u32 fourcc; + u64 pitch_align; int ret; - args->width = ALIGN(width, 8); - - ret = drm_gem_dma_dumb_create(file_priv, drm, args); + /* + * Hardware requires the framebuffer width to be aligned to + * multiples of 8. The mode-setting code handles this, but + * the buffer pitch has to be aligned as well. Set the pitch + * alignment accordingly, so that the each scanline fits into + * the allocated buffer. + */ + fourcc = drm_driver_color_mode_format(drm, args->bpp); + if (fourcc != DRM_FORMAT_INVALID) { + const struct drm_format_info *info = drm_format_info(fourcc); + + if (!info) + return -EINVAL; + pitch_align = drm_format_info_min_pitch(info, 0, 8); + } else { + pitch_align = DIV_ROUND_UP(args->bpp, SZ_8) * 8; + } + if (!pitch_align || pitch_align > U32_MAX) + return -EINVAL; + ret = drm_mode_size_dumb(drm, args, pitch_align, 0); if (ret) return ret; - args->width = width; - return ret; + return drm_gem_dma_dumb_create(file_priv, drm, args); } static const struct drm_driver imx_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, .ioctls = imx_drm_ioctls, .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), .fops = &imx_drm_driver_fops, .name = "imx-drm", .desc = "i.MX DRM graphics", - .date = "20120507", .major = 1, .minor = 0, .patchlevel = 0, @@ -249,7 +262,7 @@ static int imx_drm_bind(struct device *dev) if (ret) goto err_poll_fini; - drm_fbdev_generic_setup(drm, legacyfb_depth); + drm_client_setup_with_color_mode(drm, legacyfb_depth); return 0; @@ -257,6 +270,7 @@ err_poll_fini: drm_kms_helper_poll_fini(drm); component_unbind_all(drm->dev, drm); err_kms: + dev_set_drvdata(dev, NULL); drm_dev_put(drm); return ret; @@ -269,6 +283,7 @@ static void imx_drm_unbind(struct device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); + drm_atomic_helper_shutdown(drm); component_unbind_all(drm->dev, drm); @@ -292,10 +307,14 @@ static int imx_drm_platform_probe(struct platform_device *pdev) return ret; } -static int imx_drm_platform_remove(struct platform_device *pdev) +static void imx_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &imx_drm_ops); - return 0; +} + +static void imx_drm_platform_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); } #ifdef CONFIG_PM_SLEEP @@ -325,6 +344,7 @@ MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); static struct platform_driver imx_drm_pdrv = { .probe = imx_drm_platform_probe, .remove = imx_drm_platform_remove, + .shutdown = imx_drm_platform_shutdown, .driver = { .name = "imx-drm", .pm = &imx_drm_pm_ops, diff --git a/drivers/gpu/drm/imx/ipuv3/imx-drm.h b/drivers/gpu/drm/imx/ipuv3/imx-drm.h index e721bebda2bd..0c85bf83ffbf 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-drm.h +++ b/drivers/gpu/drm/imx/ipuv3/imx-drm.h @@ -3,14 +3,9 @@ #define _IMX_DRM_H_ struct device_node; -struct drm_crtc; struct drm_connector; struct drm_device; -struct drm_display_mode; struct drm_encoder; -struct drm_framebuffer; -struct drm_plane; -struct platform_device; struct imx_crtc_state { struct drm_crtc_state base; @@ -24,21 +19,12 @@ static inline struct imx_crtc_state *to_imx_crtc_state(struct drm_crtc_state *s) { return container_of(s, struct imx_crtc_state, base); } -int imx_drm_init_drm(struct platform_device *pdev, - int preferred_bpp); -int imx_drm_exit_drm(void); extern struct platform_driver ipu_drm_driver; -void imx_drm_mode_config_init(struct drm_device *drm); - -struct drm_gem_dma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); - int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np); -void imx_drm_connector_destroy(struct drm_connector *connector); - int ipu_planes_assign_pre(struct drm_device *dev, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index c45fc8f4744d..626d410d9150 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -12,24 +12,23 @@ #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/videodev2.h> -#include <video/of_display_timing.h> -#include <video/of_videomode.h> - #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> -#include <drm/drm_edid.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_managed.h> #include <drm/drm_of.h> -#include <drm/drm_panel.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> +#include <drm/bridge/imx.h> #include "imx-drm.h" @@ -53,7 +52,6 @@ struct imx_ldb_channel; struct imx_ldb_encoder { - struct drm_connector connector; struct drm_encoder encoder; struct imx_ldb_channel *channel; }; @@ -63,25 +61,13 @@ struct imx_ldb; struct imx_ldb_channel { struct imx_ldb *ldb; - /* Defines what is connected to the ldb, only one at a time */ - struct drm_panel *panel; struct drm_bridge *bridge; struct device_node *child; - struct i2c_adapter *ddc; int chno; - void *edid; - struct drm_display_mode mode; - int mode_valid; u32 bus_format; - u32 bus_flags; }; -static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c) -{ - return container_of(c, struct imx_ldb_encoder, connector)->channel; -} - static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e) { return container_of(e, struct imx_ldb_encoder, encoder)->channel; @@ -131,38 +117,6 @@ static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch, } } -static int imx_ldb_connector_get_modes(struct drm_connector *connector) -{ - struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); - int num_modes; - - num_modes = drm_panel_get_modes(imx_ldb_ch->panel, connector); - if (num_modes > 0) - return num_modes; - - if (!imx_ldb_ch->edid && imx_ldb_ch->ddc) - imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); - - if (imx_ldb_ch->edid) { - drm_connector_update_edid_property(connector, - imx_ldb_ch->edid); - num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid); - } - - if (imx_ldb_ch->mode_valid) { - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &imx_ldb_ch->mode); - if (!mode) - return -EINVAL; - mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - num_modes++; - } - - return num_modes; -} - static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, unsigned long serial_clk, unsigned long di_clk) { @@ -203,8 +157,6 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder) return; } - drm_panel_prepare(imx_ldb_ch->panel); - if (dual) { clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]); clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]); @@ -243,8 +195,6 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder) } regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); - - drm_panel_enable(imx_ldb_ch->panel); } static void @@ -321,8 +271,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; int mux, ret; - drm_panel_disable(imx_ldb_ch->panel); - if (imx_ldb_ch == &ldb->channel[0] || dual) ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; if (imx_ldb_ch == &ldb->channel[1] || dual) @@ -356,8 +304,6 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) dev_err(ldb->dev, "unable to set di%d parent clock to original parent\n", mux); - - drm_panel_unprepare(imx_ldb_ch->panel); } static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder, @@ -372,11 +318,12 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder, /* Bus format description in DT overrides connector display info. */ if (!bus_format && di->num_bus_formats) { bus_format = di->bus_formats[0]; - imx_crtc_state->bus_flags = di->bus_flags; } else { bus_format = imx_ldb_ch->bus_format; - imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags; } + + imx_crtc_state->bus_flags = di->bus_flags; + switch (bus_format) { case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18; @@ -396,18 +343,6 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder, } -static const struct drm_connector_funcs imx_ldb_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = imx_drm_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { - .get_modes = imx_ldb_connector_get_modes, -}; - static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { .atomic_mode_set = imx_ldb_encoder_atomic_mode_set, .enable = imx_ldb_encoder_enable, @@ -445,7 +380,6 @@ static int imx_ldb_register(struct drm_device *drm, return PTR_ERR(ldb_encoder); ldb_encoder->channel = imx_ldb_ch; - connector = &ldb_encoder->connector; encoder = &ldb_encoder->encoder; ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child); @@ -464,25 +398,16 @@ static int imx_ldb_register(struct drm_device *drm, drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); - if (imx_ldb_ch->bridge) { - ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, 0); - if (ret) - return ret; - } else { - /* - * We want to add the connector whenever there is no bridge - * that brings its own, not only when there is a panel. For - * historical reasons, the ldb driver can also work without - * a panel. - */ - drm_connector_helper_add(connector, - &imx_ldb_connector_helper_funcs); - drm_connector_init_with_ddc(drm, connector, - &imx_ldb_connector_funcs, - DRM_MODE_CONNECTOR_LVDS, - imx_ldb_ch->ddc); - drm_connector_attach_encoder(connector, encoder); - } + ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; + + connector = drm_bridge_connector_init(drm, encoder); + if (IS_ERR(connector)) + return PTR_ERR(connector); + + drm_connector_attach_encoder(connector, encoder); return 0; } @@ -547,47 +472,6 @@ static const struct of_device_id imx_ldb_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); -static int imx_ldb_panel_ddc(struct device *dev, - struct imx_ldb_channel *channel, struct device_node *child) -{ - struct device_node *ddc_node; - const u8 *edidp; - int ret; - - ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); - if (ddc_node) { - channel->ddc = of_find_i2c_adapter_by_node(ddc_node); - of_node_put(ddc_node); - if (!channel->ddc) { - dev_warn(dev, "failed to get ddc i2c adapter\n"); - return -EPROBE_DEFER; - } - } - - if (!channel->ddc) { - int edid_len; - - /* if no DDC available, fallback to hardcoded EDID */ - dev_dbg(dev, "no ddc available\n"); - - edidp = of_get_property(child, "edid", &edid_len); - if (edidp) { - channel->edid = kmemdup(edidp, edid_len, GFP_KERNEL); - if (!channel->edid) - return -ENOMEM; - } else if (!channel->panel) { - /* fallback to display-timings node */ - ret = of_get_drm_display_mode(child, - &channel->mode, - &channel->bus_flags, - OF_USE_NATIVE_MODE); - if (!ret) - channel->mode_valid = 1; - } - } - return 0; -} - static int imx_ldb_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; @@ -617,7 +501,6 @@ static int imx_ldb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev); struct device_node *child; struct imx_ldb *imx_ldb; int dual; @@ -638,9 +521,7 @@ static int imx_ldb_probe(struct platform_device *pdev) regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); imx_ldb->dev = dev; - - if (of_id) - imx_ldb->lvds_mux = of_id->data; + imx_ldb->lvds_mux = device_get_match_data(dev); dual = of_property_read_bool(np, "fsl,dual-channel"); if (dual) @@ -656,7 +537,7 @@ static int imx_ldb_probe(struct platform_device *pdev) for (i = 0; i < 4; i++) { char clkname[16]; - sprintf(clkname, "di%d_sel", i); + snprintf(clkname, sizeof(clkname), "di%d_sel", i); imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname); if (IS_ERR(imx_ldb->clk_sel[i])) { ret = PTR_ERR(imx_ldb->clk_sel[i]); @@ -695,29 +576,22 @@ static int imx_ldb_probe(struct platform_device *pdev) * The output port is port@4 with an external 4-port mux or * port@2 with the internal 2-port mux. */ - ret = drm_of_find_panel_or_bridge(child, - imx_ldb->lvds_mux ? 4 : 2, 0, - &channel->panel, &channel->bridge); - if (ret && ret != -ENODEV) - goto free_child; - - /* panel ddc only if there is no bridge */ - if (!channel->bridge) { - ret = imx_ldb_panel_ddc(dev, channel, child); - if (ret) + channel->bridge = devm_drm_of_get_bridge(dev, child, + imx_ldb->lvds_mux ? 4 : 2, 0); + if (IS_ERR(channel->bridge)) { + ret = PTR_ERR(channel->bridge); + if (ret != -ENODEV) goto free_child; + channel->bridge = NULL; } bus_format = of_get_bus_format(dev, child); - if (bus_format == -EINVAL) { - /* - * If no bus format was specified in the device tree, - * we can still get it from the connected panel later. - */ - if (channel->panel && channel->panel->funcs && - channel->panel->funcs->get_modes) - bus_format = 0; - } + /* + * If no bus format was specified in the device tree, + * we can still get it from the connected panel later. + */ + if (bus_format == -EINVAL && channel->bridge) + bus_format = 0; if (bus_format < 0) { dev_err(dev, "could not determine data mapping: %d\n", bus_format); @@ -725,6 +599,20 @@ static int imx_ldb_probe(struct platform_device *pdev) goto free_child; } channel->bus_format = bus_format; + + /* + * legacy bridge doesn't handle bus_format, so create it after + * checking the bus_format property. + */ + if (!channel->bridge) { + channel->bridge = devm_imx_drm_legacy_bridge(dev, child, + DRM_MODE_CONNECTOR_LVDS); + if (IS_ERR(channel->bridge)) { + ret = PTR_ERR(channel->bridge); + goto free_child; + } + } + channel->child = child; } @@ -737,20 +625,9 @@ free_child: return ret; } -static int imx_ldb_remove(struct platform_device *pdev) +static void imx_ldb_remove(struct platform_device *pdev) { - struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < 2; i++) { - struct imx_ldb_channel *channel = &imx_ldb->channel[i]; - - kfree(channel->edid); - i2c_put_adapter(channel->ddc); - } - component_del(&pdev->dev, &imx_ldb_ops); - return 0; } static struct platform_driver imx_ldb_driver = { @@ -767,4 +644,3 @@ module_platform_driver(imx_ldb_driver); MODULE_DESCRIPTION("i.MX LVDS driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/imx/ipuv3/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c index d6832f506322..c5c6e070cc06 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-tve.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c @@ -201,25 +201,23 @@ static int tve_setup_vga(struct imx_tve *tve) static int imx_tve_connector_get_modes(struct drm_connector *connector) { struct imx_tve *tve = con_to_tve(connector); - struct edid *edid; - int ret = 0; + const struct drm_edid *drm_edid; + int ret; if (!tve->ddc) return 0; - edid = drm_get_edid(connector, tve->ddc); - if (edid) { - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } + drm_edid = drm_edid_read_ddc(connector, tve->ddc); + drm_edid_connector_update(connector, drm_edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } static enum drm_mode_status imx_tve_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { struct imx_tve *tve = con_to_tve(connector); unsigned long rate; @@ -307,9 +305,15 @@ static int imx_tve_atomic_check(struct drm_encoder *encoder, return 0; } +static void imx_tve_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + static const struct drm_connector_funcs imx_tve_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = imx_drm_connector_destroy, + .destroy = imx_tve_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, @@ -364,17 +368,20 @@ static unsigned long clk_tve_di_recalc_rate(struct clk_hw *hw, return 0; } -static long clk_tve_di_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +static int clk_tve_di_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { unsigned long div; - div = *prate / rate; + div = req->best_parent_rate / req->rate; if (div >= 4) - return *prate / 4; + req->rate = req->best_parent_rate / 4; else if (div >= 2) - return *prate / 2; - return *prate; + req->rate = req->best_parent_rate / 2; + else + req->rate = req->best_parent_rate; + + return 0; } static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate, @@ -405,7 +412,7 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate, } static const struct clk_ops clk_tve_di_ops = { - .round_rate = clk_tve_di_round_rate, + .determine_rate = clk_tve_di_determine_rate, .set_rate = clk_tve_di_set_rate, .recalc_rate = clk_tve_di_recalc_rate, }; @@ -645,10 +652,9 @@ static int imx_tve_probe(struct platform_device *pdev) return component_add(dev, &imx_tve_ops); } -static int imx_tve_remove(struct platform_device *pdev) +static void imx_tve_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_tve_ops); - return 0; } static const struct of_device_id imx_tve_dt_ids[] = { @@ -671,4 +677,3 @@ module_platform_driver(imx_tve_driver); MODULE_DESCRIPTION("i.MX Television Encoder driver"); MODULE_AUTHOR("Philipp Zabel, Pengutronix"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-tve"); diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c index 5f26090b0c98..cf7b02b2d52c 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c @@ -310,7 +310,7 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) dev_warn(ipu_crtc->dev, "8-pixel align hactive %d -> %d\n", sig_cfg.mode.hactive, new_hactive); - sig_cfg.mode.hfront_porch = new_hactive - sig_cfg.mode.hactive; + sig_cfg.mode.hfront_porch -= new_hactive - sig_cfg.mode.hactive; sig_cfg.mode.hactive = new_hactive; } @@ -410,14 +410,12 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data) } ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); - ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0, - "imx_drm", ipu_crtc); + ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, + IRQF_NO_AUTOEN, "imx_drm", ipu_crtc); if (ret < 0) { dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); return ret; } - /* Only enable IRQ when we actually need it to trigger work. */ - disable_irq(ipu_crtc->irq); return 0; } @@ -441,10 +439,9 @@ static int ipu_drm_probe(struct platform_device *pdev) return component_add(dev, &ipu_crtc_ops); } -static int ipu_drm_remove(struct platform_device *pdev) +static void ipu_drm_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ipu_crtc_ops); - return 0; } struct platform_driver ipu_drm_driver = { diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index 80142d9a4a55..db50eccea0ca 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -14,6 +14,7 @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_print.h> #include <video/imx-ipu-v3.h> @@ -386,8 +387,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, return -EINVAL; crtc_state = - drm_atomic_get_existing_crtc_state(state, - new_state->crtc); + drm_atomic_get_new_crtc_state(state, new_state->crtc); if (WARN_ON(!crtc_state)) return -EINVAL; @@ -618,6 +618,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, width = ipu_src_rect_width(new_state); else width = drm_rect_width(&new_state->src) >> 16; + height = drm_rect_height(&new_state->src) >> 16; eba = drm_plane_state_to_eba(new_state, 0); @@ -628,9 +629,9 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, if (ipu_state->use_pre) { axi_id = ipu_chan_assign_axi_id(ipu_plane->dma); ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, width, - drm_rect_height(&new_state->src) >> 16, - fb->pitches[0], fb->format->format, - fb->modifier, &eba); + height, fb->pitches[0], + fb->format->format, fb->modifier, + &eba); } if (!old_state->fb || @@ -684,7 +685,6 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_dmfc_config_wait4eot(ipu_plane->dmfc, width); - height = drm_rect_height(&new_state->src) >> 16; info = drm_format_info(fb->format->format); ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], &burstsize, &num_bursts); @@ -747,8 +747,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16); ipu_cpmem_zero(ipu_plane->alpha_ch); - ipu_cpmem_set_resolution(ipu_plane->alpha_ch, width, - drm_rect_height(&new_state->src) >> 16); + ipu_cpmem_set_resolution(ipu_plane->alpha_ch, width, height); ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8); ipu_cpmem_set_high_priority(ipu_plane->alpha_ch); ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1); @@ -774,6 +773,13 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { .atomic_update = ipu_plane_atomic_update, }; +static const struct drm_plane_helper_funcs ipu_primary_plane_helper_funcs = { + .atomic_check = ipu_plane_atomic_check, + .atomic_disable = ipu_plane_atomic_disable, + .atomic_update = ipu_plane_atomic_update, + .get_scanout_buffer = drm_fb_dma_get_scanout_buffer, +}; + bool ipu_plane_atomic_update_pending(struct drm_plane *plane) { struct ipu_plane *ipu_plane = to_ipu_plane(plane); @@ -917,7 +923,10 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ipu_plane->dma = dma; ipu_plane->dp_flow = dp; - drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(&ipu_plane->base, &ipu_primary_plane_helper_funcs); + else + drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) ret = drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c index 0fa0b590830b..6fbf505d2801 100644 --- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c +++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c @@ -12,99 +12,31 @@ #include <linux/platform_device.h> #include <linux/videodev2.h> -#include <video/of_display_timing.h> - #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> -#include <drm/drm_edid.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_managed.h> #include <drm/drm_of.h> -#include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> +#include <drm/bridge/imx.h> #include "imx-drm.h" struct imx_parallel_display_encoder { - struct drm_connector connector; struct drm_encoder encoder; - struct drm_bridge bridge; - struct imx_parallel_display *pd; }; struct imx_parallel_display { struct device *dev; - void *edid; u32 bus_format; - u32 bus_flags; - struct drm_display_mode mode; - struct drm_panel *panel; struct drm_bridge *next_bridge; + struct drm_bridge bridge; }; -static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c) -{ - return container_of(c, struct imx_parallel_display_encoder, connector)->pd; -} - static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b) { - return container_of(b, struct imx_parallel_display_encoder, bridge)->pd; -} - -static int imx_pd_connector_get_modes(struct drm_connector *connector) -{ - struct imx_parallel_display *imxpd = con_to_imxpd(connector); - struct device_node *np = imxpd->dev->of_node; - int num_modes; - - num_modes = drm_panel_get_modes(imxpd->panel, connector); - if (num_modes > 0) - return num_modes; - - if (imxpd->edid) { - drm_connector_update_edid_property(connector, imxpd->edid); - num_modes = drm_add_edid_modes(connector, imxpd->edid); - } - - if (np) { - struct drm_display_mode *mode = drm_mode_create(connector->dev); - int ret; - - if (!mode) - return -EINVAL; - - ret = of_get_drm_display_mode(np, &imxpd->mode, - &imxpd->bus_flags, - OF_USE_NATIVE_MODE); - if (ret) { - drm_mode_destroy(connector->dev, mode); - return ret; - } - - drm_mode_copy(mode, &imxpd->mode); - mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - num_modes++; - } - - return num_modes; -} - -static void imx_pd_bridge_enable(struct drm_bridge *bridge) -{ - struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); - - drm_panel_prepare(imxpd->panel); - drm_panel_enable(imxpd->panel); -} - -static void imx_pd_bridge_disable(struct drm_bridge *bridge) -{ - struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); - - drm_panel_disable(imxpd->panel); - drm_panel_unprepare(imxpd->panel); + return container_of(b, struct imx_parallel_display, bridge); } static const u32 imx_pd_bus_fmts[] = { @@ -200,22 +132,19 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, { struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); struct drm_display_info *di = &conn_state->connector->display_info; - struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); struct drm_bridge_state *next_bridge_state = NULL; - struct drm_bridge *next_bridge; u32 bus_flags, bus_fmt; - next_bridge = drm_bridge_get_next_bridge(bridge); + struct drm_bridge *next_bridge __free(drm_bridge_put) = drm_bridge_get_next_bridge(bridge); + if (next_bridge) next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, next_bridge); if (next_bridge_state) bus_flags = next_bridge_state->input_bus_cfg.flags; - else if (di->num_bus_formats) - bus_flags = di->bus_flags; else - bus_flags = imxpd->bus_flags; + bus_flags = di->bus_flags; bus_fmt = bridge_state->input_bus_cfg.format; if (!imx_pd_format_supported(bus_fmt)) @@ -231,21 +160,17 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, return 0; } -static const struct drm_connector_funcs imx_pd_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = imx_drm_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; +static int imx_pd_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); -static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { - .get_modes = imx_pd_connector_get_modes, -}; + return drm_bridge_attach(encoder, imxpd->next_bridge, bridge, flags); +} static const struct drm_bridge_funcs imx_pd_bridge_funcs = { - .enable = imx_pd_bridge_enable, - .disable = imx_pd_bridge_disable, + .attach = imx_pd_bridge_attach, .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -269,37 +194,20 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(imxpd_encoder)) return PTR_ERR(imxpd_encoder); - imxpd_encoder->pd = imxpd; - connector = &imxpd_encoder->connector; encoder = &imxpd_encoder->encoder; - bridge = &imxpd_encoder->bridge; + bridge = &imxpd->bridge; ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node); if (ret) return ret; - /* set the connector's dpms to OFF so that - * drm_helper_connector_dpms() won't return - * immediately since the current state is ON - * at this point. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - - bridge->funcs = &imx_pd_bridge_funcs; - drm_bridge_attach(encoder, bridge, NULL, 0); - - if (imxpd->next_bridge) { - ret = drm_bridge_attach(encoder, imxpd->next_bridge, bridge, 0); - if (ret < 0) - return ret; - } else { - drm_connector_helper_add(connector, - &imx_pd_connector_helper_funcs); - drm_connector_init(drm, connector, &imx_pd_connector_funcs, - DRM_MODE_CONNECTOR_DPI); - - drm_connector_attach_encoder(connector, encoder); - } + drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + + connector = drm_bridge_connector_init(drm, encoder); + if (IS_ERR(connector)) + return PTR_ERR(connector); + + drm_connector_attach_encoder(connector, encoder); return 0; } @@ -312,26 +220,24 @@ static int imx_pd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const u8 *edidp; struct imx_parallel_display *imxpd; - int edid_len; int ret; u32 bus_format = 0; const char *fmt; - imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); - if (!imxpd) - return -ENOMEM; + imxpd = devm_drm_bridge_alloc(dev, struct imx_parallel_display, bridge, + &imx_pd_bridge_funcs); + if (IS_ERR(imxpd)) + return PTR_ERR(imxpd); /* port@1 is the output port */ - ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, - &imxpd->next_bridge); - if (ret && ret != -ENODEV) + imxpd->next_bridge = devm_drm_of_get_bridge(dev, np, 1, 0); + if (imxpd->next_bridge == ERR_PTR(-ENODEV)) + imxpd->next_bridge = devm_imx_drm_legacy_bridge(dev, np, DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(imxpd->next_bridge)) { + ret = PTR_ERR(imxpd->next_bridge); return ret; - - edidp = of_get_property(np, "edid", &edid_len); - if (edidp) - imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL); + } ret = of_property_read_string(np, "interface-pix-fmt", &fmt); if (!ret) { @@ -350,14 +256,14 @@ static int imx_pd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxpd); + devm_drm_bridge_add(dev, &imxpd->bridge); + return component_add(dev, &imx_pd_ops); } -static int imx_pd_remove(struct platform_device *pdev) +static void imx_pd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &imx_pd_ops); - - return 0; } static const struct of_device_id imx_pd_dt_ids[] = { @@ -380,4 +286,3 @@ module_platform_driver(imx_pd_driver); MODULE_DESCRIPTION("i.MX parallel display driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-parallel-display"); |
