Commit b1602452 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-next-2016-06-01' of git://git.pengutronix.de/git/pza/linux into drm-fixes

imx-drm updates

- add support for reading LVDS panel EDID over DDC
- enable UYVY/VYUY support
- add support for pixel clock polarity configuration
- honor the native-mode DT property for LVDS
- various fixes and cleanups

* tag 'imx-drm-next-2016-06-01' of git://git.pengutronix.de/git/pza/linux:
  drm/imx: plane: Don't set plane->crtc in ipu_plane_update()
  drm/imx: ipuv3-plane: Constify ipu_plane_funcs
  drm/imx: imx-ldb: honor 'native-mode' property when selecting video mode from DT
  drm/imx: parallel-display: remove dead code
  drm/imx: use bus_flags for pixel clock polarity
  drm/imx: ipuv3-plane: enable UYVY and VYUY formats
  drm/imx: parallel-display: use of_graph_get_endpoint_by_regs helper
  drm/imx: imx-ldb: use of_graph_get_endpoint_by_regs helper
  dt-bindings: imx: ldb: Add ddc-i2c-bus property
  drm/imx: imx-ldb: Add DDC support
parents 35962eae 151787ba
...@@ -62,6 +62,7 @@ Required properties: ...@@ -62,6 +62,7 @@ Required properties:
display-timings are used instead. display-timings are used instead.
Optional properties (required if display-timings are used): Optional properties (required if display-timings are used):
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
- display-timings : A node that describes the display timings as defined in - display-timings : A node that describes the display timings as defined in
Documentation/devicetree/bindings/display/display-timing.txt. Documentation/devicetree/bindings/display/display-timing.txt.
- fsl,data-mapping : should be "spwg" or "jeida" - fsl,data-mapping : should be "spwg" or "jeida"
......
...@@ -97,8 +97,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) ...@@ -97,8 +97,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
return NULL; return NULL;
} }
int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format,
int hsync_pin, int vsync_pin) int hsync_pin, int vsync_pin, u32 bus_flags)
{ {
struct imx_drm_crtc_helper_funcs *helper; struct imx_drm_crtc_helper_funcs *helper;
struct imx_drm_crtc *imx_crtc; struct imx_drm_crtc *imx_crtc;
...@@ -110,14 +110,17 @@ int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, ...@@ -110,14 +110,17 @@ int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format,
helper = &imx_crtc->imx_drm_helper_funcs; helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt) if (helper->set_interface_pix_fmt)
return helper->set_interface_pix_fmt(encoder->crtc, return helper->set_interface_pix_fmt(encoder->crtc,
bus_format, hsync_pin, vsync_pin); bus_format, hsync_pin, vsync_pin,
bus_flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins); EXPORT_SYMBOL_GPL(imx_drm_set_bus_config);
int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format)
{ {
return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3); return imx_drm_set_bus_config(encoder, bus_format, 2, 3,
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_NEGEDGE);
} }
EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); EXPORT_SYMBOL_GPL(imx_drm_set_bus_format);
......
...@@ -19,7 +19,8 @@ struct imx_drm_crtc_helper_funcs { ...@@ -19,7 +19,8 @@ struct imx_drm_crtc_helper_funcs {
int (*enable_vblank)(struct drm_crtc *crtc); int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc);
int (*set_interface_pix_fmt)(struct drm_crtc *crtc, int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
u32 bus_format, int hsync_pin, int vsync_pin); u32 bus_format, int hsync_pin, int vsync_pin,
u32 bus_flags);
const struct drm_crtc_helper_funcs *crtc_helper_funcs; const struct drm_crtc_helper_funcs *crtc_helper_funcs;
const struct drm_crtc_funcs *crtc_funcs; const struct drm_crtc_funcs *crtc_funcs;
}; };
...@@ -41,8 +42,8 @@ void imx_drm_mode_config_init(struct drm_device *drm); ...@@ -41,8 +42,8 @@ void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format,
u32 bus_format, int hsync_pin, int vsync_pin); int hsync_pin, int vsync_pin, u32 bus_flags);
int imx_drm_set_bus_format(struct drm_encoder *encoder, int imx_drm_set_bus_format(struct drm_encoder *encoder,
u32 bus_format); u32 bus_format);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h> #include <video/of_videomode.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
...@@ -59,6 +60,7 @@ struct imx_ldb_channel { ...@@ -59,6 +60,7 @@ struct imx_ldb_channel {
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_panel *panel; struct drm_panel *panel;
struct device_node *child; struct device_node *child;
struct i2c_adapter *ddc;
int chno; int chno;
void *edid; void *edid;
int edid_len; int edid_len;
...@@ -107,6 +109,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) ...@@ -107,6 +109,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
return num_modes; 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) { if (imx_ldb_ch->edid) {
drm_mode_connector_update_edid_property(connector, drm_mode_connector_update_edid_property(connector,
imx_ldb_ch->edid); imx_ldb_ch->edid);
...@@ -553,7 +558,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -553,7 +558,8 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
struct imx_ldb_channel *channel; struct imx_ldb_channel *channel;
struct device_node *port; struct device_node *ddc_node;
struct device_node *ep;
ret = of_property_read_u32(child, "reg", &i); ret = of_property_read_u32(child, "reg", &i);
if (ret || i < 0 || i > 1) if (ret || i < 0 || i > 1)
...@@ -576,33 +582,54 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -576,33 +582,54 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
* The output port is port@4 with an external 4-port mux or * The output port is port@4 with an external 4-port mux or
* port@2 with the internal 2-port mux. * port@2 with the internal 2-port mux.
*/ */
port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); ep = of_graph_get_endpoint_by_regs(child,
if (port) { imx_ldb->lvds_mux ? 4 : 2,
struct device_node *endpoint, *remote; -1);
if (ep) {
endpoint = of_get_child_by_name(port, "endpoint"); struct device_node *remote;
if (endpoint) {
remote = of_graph_get_remote_port_parent(endpoint); remote = of_graph_get_remote_port_parent(ep);
if (remote) of_node_put(ep);
channel->panel = of_drm_find_panel(remote); if (remote)
else channel->panel = of_drm_find_panel(remote);
return -EPROBE_DEFER; else
if (!channel->panel) { return -EPROBE_DEFER;
dev_err(dev, "panel not found: %s\n", of_node_put(remote);
remote->full_name); if (!channel->panel) {
return -EPROBE_DEFER; dev_err(dev, "panel not found: %s\n",
} remote->full_name);
return -EPROBE_DEFER;
} }
} }
edidp = of_get_property(child, "edid", &channel->edid_len); ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
if (edidp) { if (ddc_node) {
channel->edid = kmemdup(edidp, channel->edid_len, channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
GFP_KERNEL); of_node_put(ddc_node);
} else if (!channel->panel) { if (!channel->ddc) {
ret = of_get_drm_display_mode(child, &channel->mode, 0); dev_warn(dev, "failed to get ddc i2c adapter\n");
if (!ret) return -EPROBE_DEFER;
channel->mode_valid = 1; }
}
if (!channel->ddc) {
/* if no DDC available, fallback to hardcoded EDID */
dev_dbg(dev, "no ddc available\n");
edidp = of_get_property(child, "edid",
&channel->edid_len);
if (edidp) {
channel->edid = kmemdup(edidp,
channel->edid_len,
GFP_KERNEL);
} else if (!channel->panel) {
/* fallback to display-timings node */
ret = of_get_drm_display_mode(child,
&channel->mode,
OF_USE_NATIVE_MODE);
if (!ret)
channel->mode_valid = 1;
}
} }
channel->bus_format = of_get_bus_format(dev, child); channel->bus_format = of_get_bus_format(dev, child);
...@@ -647,6 +674,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, ...@@ -647,6 +674,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
channel->encoder.funcs->destroy(&channel->encoder); channel->encoder.funcs->destroy(&channel->encoder);
kfree(channel->edid); kfree(channel->edid);
i2c_put_adapter(channel->ddc);
} }
} }
......
...@@ -294,8 +294,10 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) ...@@ -294,8 +294,10 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
switch (tve->mode) { switch (tve->mode) {
case TVE_MODE_VGA: case TVE_MODE_VGA:
imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_GBR888_1X24, imx_drm_set_bus_config(encoder, MEDIA_BUS_FMT_GBR888_1X24,
tve->hsync_pin, tve->vsync_pin); tve->hsync_pin, tve->vsync_pin,
DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_NEGEDGE);
break; break;
case TVE_MODE_TVOUT: case TVE_MODE_TVOUT:
imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24);
......
...@@ -66,6 +66,7 @@ struct ipu_crtc { ...@@ -66,6 +66,7 @@ struct ipu_crtc {
struct ipu_flip_work *flip_work; struct ipu_flip_work *flip_work;
int irq; int irq;
u32 bus_format; u32 bus_format;
u32 bus_flags;
int di_hsync_pin; int di_hsync_pin;
int di_vsync_pin; int di_vsync_pin;
}; };
...@@ -271,8 +272,10 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, ...@@ -271,8 +272,10 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
else else
sig_cfg.clkflags = 0; sig_cfg.clkflags = 0;
sig_cfg.enable_pol = 1; sig_cfg.enable_pol = !(ipu_crtc->bus_flags & DRM_BUS_FLAG_DE_LOW);
sig_cfg.clk_pol = 0; /* Default to driving pixel data on negative clock edges */
sig_cfg.clk_pol = !!(ipu_crtc->bus_flags &
DRM_BUS_FLAG_PIXDATA_POSEDGE);
sig_cfg.bus_format = ipu_crtc->bus_format; sig_cfg.bus_format = ipu_crtc->bus_format;
sig_cfg.v_to_h_sync = 0; sig_cfg.v_to_h_sync = 0;
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
...@@ -396,11 +399,12 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) ...@@ -396,11 +399,12 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
} }
static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
u32 bus_format, int hsync_pin, int vsync_pin) u32 bus_format, int hsync_pin, int vsync_pin, u32 bus_flags)
{ {
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
ipu_crtc->bus_format = bus_format; ipu_crtc->bus_format = bus_format;
ipu_crtc->bus_flags = bus_flags;
ipu_crtc->di_hsync_pin = hsync_pin; ipu_crtc->di_hsync_pin = hsync_pin;
ipu_crtc->di_vsync_pin = vsync_pin; ipu_crtc->di_vsync_pin = vsync_pin;
......
...@@ -38,6 +38,8 @@ static const uint32_t ipu_plane_formats[] = { ...@@ -38,6 +38,8 @@ static const uint32_t ipu_plane_formats[] = {
DRM_FORMAT_RGBX8888, DRM_FORMAT_RGBX8888,
DRM_FORMAT_BGRA8888, DRM_FORMAT_BGRA8888,
DRM_FORMAT_BGRA8888, DRM_FORMAT_BGRA8888,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_YUYV, DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU, DRM_FORMAT_YVYU,
DRM_FORMAT_YUV420, DRM_FORMAT_YUV420,
...@@ -428,7 +430,6 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, ...@@ -428,7 +430,6 @@ static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (crtc != plane->crtc) if (crtc != plane->crtc)
dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n", dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n",
plane->crtc, crtc); plane->crtc, crtc);
plane->crtc = crtc;
if (!ipu_plane->enabled) if (!ipu_plane->enabled)
ipu_plane_enable(ipu_plane); ipu_plane_enable(ipu_plane);
...@@ -461,7 +462,7 @@ static void ipu_plane_destroy(struct drm_plane *plane) ...@@ -461,7 +462,7 @@ static void ipu_plane_destroy(struct drm_plane *plane)
kfree(ipu_plane); kfree(ipu_plane);
} }
static struct drm_plane_funcs ipu_plane_funcs = { static const struct drm_plane_funcs ipu_plane_funcs = {
.update_plane = ipu_update_plane, .update_plane = ipu_update_plane,
.disable_plane = ipu_disable_plane, .disable_plane = ipu_disable_plane,
.destroy = ipu_plane_destroy, .destroy = ipu_plane_destroy,
......
...@@ -35,7 +35,6 @@ struct imx_parallel_display { ...@@ -35,7 +35,6 @@ struct imx_parallel_display {
void *edid; void *edid;
int edid_len; int edid_len;
u32 bus_format; u32 bus_format;
int mode_valid;
struct drm_display_mode mode; struct drm_display_mode mode;
struct drm_panel *panel; struct drm_panel *panel;
}; };
...@@ -68,17 +67,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) ...@@ -68,17 +67,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
num_modes = drm_add_edid_modes(connector, imxpd->edid); num_modes = drm_add_edid_modes(connector, imxpd->edid);
} }
if (imxpd->mode_valid) {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
if (!mode)
return -EINVAL;
drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
drm_mode_probed_add(connector, mode);
num_modes++;
}
if (np) { if (np) {
struct drm_display_mode *mode = drm_mode_create(connector->dev); struct drm_display_mode *mode = drm_mode_create(connector->dev);
...@@ -115,8 +103,8 @@ static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) ...@@ -115,8 +103,8 @@ static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
static void imx_pd_encoder_prepare(struct drm_encoder *encoder) static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{ {
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
imx_drm_set_bus_config(encoder, imxpd->bus_format, 2, 3,
imx_drm_set_bus_format(encoder, imxpd->bus_format); imxpd->connector.display_info.bus_flags);
} }
static void imx_pd_encoder_commit(struct drm_encoder *encoder) static void imx_pd_encoder_commit(struct drm_encoder *encoder)
...@@ -203,7 +191,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -203,7 +191,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{ {
struct drm_device *drm = data; struct drm_device *drm = data;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *port; struct device_node *ep;
const u8 *edidp; const u8 *edidp;
struct imx_parallel_display *imxpd; struct imx_parallel_display *imxpd;
int ret; int ret;
...@@ -230,18 +218,18 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -230,18 +218,18 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
} }
/* port@1 is the output port */ /* port@1 is the output port */
port = of_graph_get_port_by_id(np, 1); ep = of_graph_get_endpoint_by_regs(np, 1, -1);
if (port) { if (ep) {
struct device_node *endpoint, *remote; struct device_node *remote;
endpoint = of_get_child_by_name(port, "endpoint"); remote = of_graph_get_remote_port_parent(ep);
if (endpoint) { of_node_put(ep);
remote = of_graph_get_remote_port_parent(endpoint); if (remote) {
if (remote) imxpd->panel = of_drm_find_panel(remote);
imxpd->panel = of_drm_find_panel(remote); of_node_put(remote);
if (!imxpd->panel)
return -EPROBE_DEFER;
} }
if (!imxpd->panel)
return -EPROBE_DEFER;
} }
imxpd->dev = dev; imxpd->dev = dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment