diff options
Diffstat (limited to 'drivers/gpu/drm/imx')
-rw-r--r-- | drivers/gpu/drm/imx/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-ldb.c | 224 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/imx-tve.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-crtc.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/parallel-display.c | 18 |
10 files changed, 230 insertions, 132 deletions
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index 33cdddf..2b81a41 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig @@ -36,6 +36,7 @@ config DRM_IMX_TVE config DRM_IMX_LDB tristate "Support for LVDS displays" depends on DRM_IMX && MFD_SYSCON + select DRM_PANEL 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/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 1032c07..a3ecf10 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = { 118800000, { 0x091c, 0x091c, 0x06dc }, }, { 216000000, { 0x06dc, 0x0b5c, 0x091c }, - } + }, { + ~0UL, { 0x0000, 0x0000, 0x0000 }, + }, }; static const struct dw_hdmi_phy_config imx_phy_config[] = { @@ -121,7 +123,7 @@ static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder) static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder) { - imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); + imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_RGB888_1X24); } static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { @@ -136,18 +138,42 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con, + struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + if (mode->clock > 266000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con, + struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + if (mode->clock > 270000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { .mpll_cfg = imx_mpll_cfg, .cur_ctr = imx_cur_ctr, .phy_config = imx_phy_config, .dev_type = IMX6Q_HDMI, + .mode_valid = imx6q_hdmi_mode_valid, }; static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { - .mpll_cfg = imx_mpll_cfg, - .cur_ctr = imx_cur_ctr, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, .phy_config = imx_phy_config, - .dev_type = IMX6DL_HDMI, + .dev_type = IMX6DL_HDMI, + .mode_valid = imx6dl_hdmi_mode_valid, }; static const struct of_device_id dw_hdmi_imx_dt_ids[] = { diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index a002f53..74f505b 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -103,8 +103,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) return NULL; } -int imx_drm_panel_format_pins(struct drm_encoder *encoder, - u32 interface_pix_fmt, int hsync_pin, int vsync_pin) +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, + int hsync_pin, int vsync_pin) { struct imx_drm_crtc_helper_funcs *helper; struct imx_drm_crtc *imx_crtc; @@ -116,16 +116,16 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder, helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) return helper->set_interface_pix_fmt(encoder->crtc, - interface_pix_fmt, hsync_pin, vsync_pin); + bus_format, hsync_pin, vsync_pin); return 0; } -EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins); -int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) +int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) { - return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); + return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3); } -EXPORT_SYMBOL_GPL(imx_drm_panel_format); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { @@ -431,15 +431,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm, } EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); -static struct device_node *imx_drm_of_get_next_endpoint( - const struct device_node *parent, struct device_node *prev) -{ - struct device_node *node = of_graph_get_next_endpoint(parent, prev); - - of_node_put(prev); - return node; -} - /* * @node: device tree node containing encoder input ports * @encoder: drm_encoder @@ -448,7 +439,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, struct drm_encoder *encoder) { struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); - struct device_node *ep = NULL; + struct device_node *ep; struct of_endpoint endpoint; struct device_node *port; int ret; @@ -456,18 +447,15 @@ int imx_drm_encoder_get_mux_id(struct device_node *node, if (!node || !imx_crtc) return -EINVAL; - do { - ep = imx_drm_of_get_next_endpoint(node, ep); - if (!ep) - break; - + for_each_endpoint_of_node(node, ep) { port = of_graph_get_remote_port(ep); of_node_put(port); if (port == imx_crtc->crtc->port) { ret = of_graph_parse_endpoint(ep, &endpoint); + of_node_put(ep); return ret ? ret : endpoint.port; } - } while (ep); + } return -EINVAL; } diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 3c559cc..28e776d 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); int (*set_interface_pix_fmt)(struct drm_crtc *crtc, - u32 pix_fmt, int hsync_pin, int vsync_pin); + u32 bus_format, int hsync_pin, int vsync_pin); const struct drm_crtc_helper_funcs *crtc_helper_funcs; const struct drm_crtc_funcs *crtc_funcs; }; @@ -40,10 +40,10 @@ void imx_drm_mode_config_init(struct drm_device *drm); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -int imx_drm_panel_format_pins(struct drm_encoder *encoder, - u32 interface_pix_fmt, int hsync_pin, int vsync_pin); -int imx_drm_panel_format(struct drm_encoder *encoder, - u32 interface_pix_fmt); +int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, + u32 bus_format, int hsync_pin, int vsync_pin); +int imx_drm_set_bus_format(struct drm_encoder *encoder, + u32 bus_format); int imx_drm_encoder_get_mux_id(struct device_node *node, struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 1b86aac..abacc8f 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -19,10 +19,11 @@ #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_panel.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> -#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <video/of_videomode.h> #include <linux/regmap.h> #include <linux/videodev2.h> @@ -55,12 +56,14 @@ struct imx_ldb_channel { struct imx_ldb *ldb; struct drm_connector connector; struct drm_encoder encoder; + struct drm_panel *panel; struct device_node *child; int chno; void *edid; int edid_len; struct drm_display_mode mode; int mode_valid; + int bus_format; }; struct bus_mux { @@ -75,6 +78,7 @@ struct imx_ldb { struct imx_ldb_channel channel[2]; struct clk *clk[2]; /* our own clock */ struct clk *clk_sel[4]; /* parent of display clock */ + struct clk *clk_parent[4]; /* original parent of clk_sel */ struct clk *clk_pll[2]; /* upstream clock we can adjust */ u32 ldb_ctrl; const struct bus_mux *lvds_mux; @@ -91,6 +95,17 @@ 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 = 0; + if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && + imx_ldb_ch->panel->funcs->get_modes) { + struct drm_display_info *di = &connector->display_info; + + num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); + if (!imx_ldb_ch->bus_format && di->num_bus_formats) + imx_ldb_ch->bus_format = di->bus_formats[0]; + if (num_modes > 0) + return num_modes; + } + if (imx_ldb_ch->edid) { drm_mode_connector_update_edid_property(connector, imx_ldb_ch->edid); @@ -163,39 +178,36 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) { struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; - struct drm_display_mode *mode = &encoder->crtc->hwmode; - u32 pixel_fmt; - unsigned long serial_clk; - unsigned long di_clk = mode->clock * 1000; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); - - if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { - /* dual channel LVDS mode */ - serial_clk = 3500UL * mode->clock; - imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); - imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); - } else { - serial_clk = 7000UL * mode->clock; - imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, - di_clk); - } + int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; + u32 bus_format; - switch (imx_ldb_ch->chno) { - case 0: - pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH0_24) ? - V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; + switch (imx_ldb_ch->bus_format) { + default: + dev_warn(ldb->dev, + "could not determine data mapping, default to 18-bit \"spwg\"\n"); + /* fallthrough */ + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + bus_format = MEDIA_BUS_FMT_RGB666_1X18; break; - case 1: - pixel_fmt = (ldb->ldb_ctrl & LDB_DATA_WIDTH_CH1_24) ? - V4L2_PIX_FMT_RGB24 : V4L2_PIX_FMT_BGR666; + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + if (imx_ldb_ch->chno == 0 || dual) + ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; + if (imx_ldb_ch->chno == 1 || dual) + ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; + break; + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + if (imx_ldb_ch->chno == 0 || dual) + ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | + LDB_BIT_MAP_CH0_JEIDA; + if (imx_ldb_ch->chno == 1 || dual) + ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | + LDB_BIT_MAP_CH1_JEIDA; break; - default: - dev_err(ldb->dev, "unable to config di%d panel format\n", - imx_ldb_ch->chno); - pixel_fmt = V4L2_PIX_FMT_RGB24; } - imx_drm_panel_format(encoder, pixel_fmt); + imx_drm_set_bus_format(encoder, bus_format); } static void imx_ldb_encoder_commit(struct drm_encoder *encoder) @@ -205,6 +217,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); + drm_panel_prepare(imx_ldb_ch->panel); + if (dual) { clk_prepare_enable(ldb->clk[0]); clk_prepare_enable(ldb->clk[1]); @@ -238,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) } regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl); + + drm_panel_enable(imx_ldb_ch->panel); } static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, @@ -247,6 +263,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; + unsigned long serial_clk; + unsigned long di_clk = mode->clock * 1000; + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (mode->clock > 170000) { dev_warn(ldb->dev, @@ -257,6 +276,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, "%s: mode exceeds 85 MHz pixel clock\n", __func__); } + if (dual) { + serial_clk = 3500UL * mode->clock; + imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); + imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); + } else { + serial_clk = 7000UL * mode->clock; + imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, + di_clk); + } + /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ if (imx_ldb_ch == &ldb->channel[0]) { if (mode->flags & DRM_MODE_FLAG_NVSYNC) @@ -276,6 +305,7 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) { struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; + int mux, ret; /* * imx_ldb_encoder_disable is called by @@ -289,6 +319,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0) return; + drm_panel_disable(imx_ldb_ch->panel); + if (imx_ldb_ch == &ldb->channel[0]) ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK; else if (imx_ldb_ch == &ldb->channel[1]) @@ -300,6 +332,30 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) clk_disable_unprepare(ldb->clk[0]); clk_disable_unprepare(ldb->clk[1]); } + + if (ldb->lvds_mux) { + const struct bus_mux *lvds_mux = NULL; + + if (imx_ldb_ch == &ldb->channel[0]) + lvds_mux = &ldb->lvds_mux[0]; + else if (imx_ldb_ch == &ldb->channel[1]) + lvds_mux = &ldb->lvds_mux[1]; + + regmap_read(ldb->regmap, lvds_mux->reg, &mux); + mux &= lvds_mux->mask; + mux >>= lvds_mux->shift; + } else { + mux = (imx_ldb_ch == &ldb->channel[0]) ? 0 : 1; + } + + /* set display clock mux back to original input clock */ + ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk_parent[mux]); + if (ret) + dev_err(ldb->dev, + "unable to set di%d parent clock to original parent\n", + mux); + + drm_panel_unprepare(imx_ldb_ch->panel); } static struct drm_connector_funcs imx_ldb_connector_funcs = { @@ -373,6 +429,9 @@ static int imx_ldb_register(struct drm_device *drm, drm_connector_init(drm, &imx_ldb_ch->connector, &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); + if (imx_ldb_ch->panel) + drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); + drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, &imx_ldb_ch->encoder); @@ -384,25 +443,39 @@ enum { LVDS_BIT_MAP_JEIDA }; -static const char * const imx_ldb_bit_mappings[] = { - [LVDS_BIT_MAP_SPWG] = "spwg", - [LVDS_BIT_MAP_JEIDA] = "jeida", +struct imx_ldb_bit_mapping { + u32 bus_format; + u32 datawidth; + const char * const mapping; +}; + +static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = { + { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" }, + { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" }, + { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" }, }; -static const int of_get_data_mapping(struct device_node *np) +static u32 of_get_bus_format(struct device *dev, struct device_node *np) { const char *bm; + u32 datawidth = 0; int ret, i; ret = of_property_read_string(np, "fsl,data-mapping", &bm); if (ret < 0) return ret; - for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) - if (!strcasecmp(bm, imx_ldb_bit_mappings[i])) - return i; + of_property_read_u32(np, "fsl,data-width", &datawidth); + + for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) { + if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) && + datawidth == imx_ldb_bit_mappings[i].datawidth) + return imx_ldb_bit_mappings[i].bus_format; + } - return -EINVAL; + dev_err(dev, "invalid data mapping: %d-bit \"%s\"\n", datawidth, bm); + + return -ENOENT; } static struct bus_mux imx6q_lvds_mux[2] = { @@ -439,8 +512,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) struct device_node *child; const u8 *edidp; struct imx_ldb *imx_ldb; - int datawidth; - int mapping; int dual; int ret; int i; @@ -481,12 +552,15 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) imx_ldb->clk_sel[i] = NULL; break; } + + imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]); } if (i == 0) return ret; for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; + struct device_node *port; ret = of_property_read_u32(child, "reg", &i); if (ret || i < 0 || i > 1) @@ -505,49 +579,53 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) channel->chno = i; channel->child = child; + /* + * The output port is port@4 with an external 4-port mux or + * port@2 with the internal 2-port mux. + */ + port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); + if (port) { + struct device_node *endpoint, *remote; + + endpoint = of_get_child_by_name(port, "endpoint"); + if (endpoint) { + remote = of_graph_get_remote_port_parent(endpoint); + if (remote) + channel->panel = of_drm_find_panel(remote); + else + return -EPROBE_DEFER; + if (!channel->panel) { + dev_err(dev, "panel not found: %s\n", + remote->full_name); + return -EPROBE_DEFER; + } + } + } + edidp = of_get_property(child, "edid", &channel->edid_len); if (edidp) { channel->edid = kmemdup(edidp, channel->edid_len, GFP_KERNEL); - } else { + } else if (!channel->panel) { ret = of_get_drm_display_mode(child, &channel->mode, 0); if (!ret) channel->mode_valid = 1; } - ret = of_property_read_u32(child, "fsl,data-width", &datawidth); - if (ret) - datawidth = 0; - else if (datawidth != 18 && datawidth != 24) - return -EINVAL; - - mapping = of_get_data_mapping(child); - switch (mapping) { - case LVDS_BIT_MAP_SPWG: - if (datawidth == 24) { - if (i == 0 || dual) - imx_ldb->ldb_ctrl |= - LDB_DATA_WIDTH_CH0_24; - if (i == 1 || dual) - imx_ldb->ldb_ctrl |= - LDB_DATA_WIDTH_CH1_24; - } - break; - case LVDS_BIT_MAP_JEIDA: - if (datawidth == 18) { - dev_err(dev, "JEIDA standard only supported in 24 bit\n"); - return -EINVAL; - } - if (i == 0 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | - LDB_BIT_MAP_CH0_JEIDA; - if (i == 1 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | - LDB_BIT_MAP_CH1_JEIDA; - break; - default: - dev_err(dev, "data mapping not specified or invalid\n"); - return -EINVAL; + channel->bus_format = of_get_bus_format(dev, child); + if (channel->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) + channel->bus_format = 0; + } + if (channel->bus_format < 0) { + dev_err(dev, "could not determine data mapping: %d\n", + channel->bus_format); + return channel->bus_format; } ret = imx_ldb_register(drm, channel); diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index 4216e47..214ecee 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -301,11 +301,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) switch (tve->mode) { case TVE_MODE_VGA: - imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24, - tve->hsync_pin, tve->vsync_pin); + imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24, + tve->hsync_pin, tve->vsync_pin); break; case TVE_MODE_TVOUT: - imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444); + imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); break; } } diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 98551e3..7bc8301 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -45,7 +45,7 @@ struct ipu_crtc { struct drm_pending_vblank_event *page_flip_event; struct drm_framebuffer *newfb; int irq; - u32 interface_pix_fmt; + u32 bus_format; int di_hsync_pin; int di_vsync_pin; }; @@ -145,7 +145,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct ipu_di_signal_cfg sig_cfg = {}; unsigned long encoder_types = 0; - u32 out_pixel_fmt; int ret; dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, @@ -161,21 +160,21 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, __func__, encoder_types); /* - * If we have DAC, TVDAC or LDB, then we need the IPU DI clock - * to be the same as the LDB DI clock. + * If we have DAC or LDB, then we need the IPU DI clock to be + * the same as the LDB DI clock. For TVDAC, derive the IPU DI + * clock from 27 MHz TVE_DI clock, but allow to divide it. */ if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) | - BIT(DRM_MODE_ENCODER_TVDAC) | BIT(DRM_MODE_ENCODER_LVDS))) sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; + else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC)) + sig_cfg.clkflags = IPU_DI_CLKMODE_EXT; else sig_cfg.clkflags = 0; - out_pixel_fmt = ipu_crtc->interface_pix_fmt; - sig_cfg.enable_pol = 1; sig_cfg.clk_pol = 0; - sig_cfg.pixel_fmt = out_pixel_fmt; + sig_cfg.bus_format = ipu_crtc->bus_format; sig_cfg.v_to_h_sync = 0; sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin; @@ -184,7 +183,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, - out_pixel_fmt, mode->hdisplay); + ipu_crtc->bus_format, mode->hdisplay); if (ret) { dev_err(ipu_crtc->dev, "initializing display controller failed with %d\n", @@ -202,7 +201,8 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, - x, y, mode->hdisplay, mode->vdisplay); + x, y, mode->hdisplay, mode->vdisplay, + mode->flags & DRM_MODE_FLAG_INTERLACE); } static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) @@ -291,11 +291,11 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) } static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, - u32 pixfmt, int hsync_pin, int vsync_pin) + u32 bus_format, int hsync_pin, int vsync_pin) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); - ipu_crtc->interface_pix_fmt = pixfmt; + ipu_crtc->bus_format = bus_format; ipu_crtc->di_hsync_pin = hsync_pin; ipu_crtc->di_vsync_pin = vsync_pin; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 6987e16..878a643 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -99,7 +99,7 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, bool interlaced) { struct device *dev = ipu_plane->base.dev->dev; int ret; @@ -213,6 +213,8 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y); if (ret < 0) return ret; + if (interlaced) + ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]); ipu_plane->w = src_w; ipu_plane->h = src_h; @@ -312,7 +314,8 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16); + src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16, + false); if (ret < 0) { ipu_plane_put_resources(ipu_plane); return ret; diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h index af125fb..9b5eff1 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.h +++ b/drivers/gpu/drm/imx/ipuv3-plane.h @@ -42,7 +42,7 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, - uint32_t src_h); + uint32_t src_h, bool interlaced); void ipu_plane_enable(struct ipu_plane *plane); void ipu_plane_disable(struct ipu_plane *plane); diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 5e83e00..74a9ce4 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -33,7 +33,7 @@ struct imx_parallel_display { struct device *dev; void *edid; int edid_len; - u32 interface_pix_fmt; + u32 bus_format; int mode_valid; struct drm_display_mode mode; struct drm_panel *panel; @@ -118,7 +118,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - imx_drm_panel_format(encoder, imxpd->interface_pix_fmt); + imx_drm_set_bus_format(encoder, imxpd->bus_format); } static void imx_pd_encoder_commit(struct drm_encoder *encoder) @@ -225,19 +225,21 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ret = of_property_read_string(np, "interface-pix-fmt", &fmt); if (!ret) { if (!strcmp(fmt, "rgb24")) - imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24; + imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24; else if (!strcmp(fmt, "rgb565")) - imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; + imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; else if (!strcmp(fmt, "bgr666")) - imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; + imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; else if (!strcmp(fmt, "lvds666")) - imxpd->interface_pix_fmt = - v4l2_fourcc('L', 'V', 'D', '6'); + imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; } panel_node = of_parse_phandle(np, "fsl,panel", 0); - if (panel_node) + if (panel_node) { imxpd->panel = of_drm_find_panel(panel_node); + if (!imxpd->panel) + return -EPROBE_DEFER; + } imxpd->dev = dev; |