diff options
author | Mark Brown <broonie@kernel.org> | 2016-11-04 12:16:38 -0600 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-11-04 12:16:38 -0600 |
commit | cc9b94029e9ef51787af908e9856b1eed314bc00 (patch) | |
tree | 9675310b89d0f6fb1f7bd9423f0638c4ee5226fd /drivers/gpu/drm/imx/parallel-display.c | |
parent | 13bed58ce8748d430a26e353a09b89f9d613a71f (diff) | |
parent | 1b5b42216469b05ef4b5916cb40b127dfab1da88 (diff) |
Merge branch 'topic/error' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator into regulator-fixed
Diffstat (limited to 'drivers/gpu/drm/imx/parallel-display.c')
-rw-r--r-- | drivers/gpu/drm/imx/parallel-display.c | 183 |
1 files changed, 109 insertions, 74 deletions
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 363e2c7741e2..d796ada2a47a 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -16,6 +16,7 @@ #include <linux/component.h> #include <linux/module.h> #include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h> @@ -25,9 +26,6 @@ #include "imx-drm.h" -#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector) -#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder) - struct imx_parallel_display { struct drm_connector connector; struct drm_encoder encoder; @@ -35,11 +33,22 @@ struct imx_parallel_display { void *edid; int edid_len; u32 bus_format; - int mode_valid; + u32 bus_flags; struct drm_display_mode mode; struct drm_panel *panel; + 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, connector); +} + +static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e) +{ + return container_of(e, struct imx_parallel_display, encoder); +} + static enum drm_connector_status imx_pd_connector_detect( struct drm_connector *connector, bool force) { @@ -54,11 +63,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) if (imxpd->panel && imxpd->panel->funcs && imxpd->panel->funcs->get_modes) { - struct drm_display_info *di = &connector->display_info; - num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); - if (!imxpd->bus_format && di->num_bus_formats) - imxpd->bus_format = di->bus_formats[0]; if (num_modes > 0) return num_modes; } @@ -68,23 +73,19 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) num_modes = drm_add_edid_modes(connector, imxpd->edid); } - if (imxpd->mode_valid) { + if (np) { struct drm_display_mode *mode = drm_mode_create(connector->dev); + int ret; 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) { - struct drm_display_mode *mode = drm_mode_create(connector->dev); + ret = of_get_drm_display_mode(np, &imxpd->mode, + &imxpd->bus_flags, + OF_USE_NATIVE_MODE); + if (ret) + return ret; - if (!mode) - return -EINVAL; - of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE); drm_mode_copy(mode, &imxpd->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, drm_mode_probed_add(connector, mode); @@ -102,50 +103,51 @@ static struct drm_encoder *imx_pd_connector_best_encoder( return &imxpd->encoder; } -static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) +static void imx_pd_encoder_enable(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - if (mode != DRM_MODE_DPMS_ON) - drm_panel_disable(imxpd->panel); - else - drm_panel_enable(imxpd->panel); + drm_panel_prepare(imxpd->panel); + drm_panel_enable(imxpd->panel); } -static void imx_pd_encoder_prepare(struct drm_encoder *encoder) +static void imx_pd_encoder_disable(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - imx_drm_set_bus_format(encoder, imxpd->bus_format); + drm_panel_disable(imxpd->panel); + drm_panel_unprepare(imxpd->panel); } -static void imx_pd_encoder_commit(struct drm_encoder *encoder) +static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { + 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 = enc_to_imxpd(encoder); - drm_panel_prepare(imxpd->panel); - drm_panel_enable(imxpd->panel); -} - -static void imx_pd_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *orig_mode, - struct drm_display_mode *mode) -{ -} - -static void imx_pd_encoder_disable(struct drm_encoder *encoder) -{ - struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + if (!imxpd->bus_format && di->num_bus_formats) { + imx_crtc_state->bus_flags = di->bus_flags; + imx_crtc_state->bus_format = di->bus_formats[0]; + } else { + imx_crtc_state->bus_flags = imxpd->bus_flags; + imx_crtc_state->bus_format = imxpd->bus_format; + } + imx_crtc_state->di_hsync_pin = 2; + imx_crtc_state->di_vsync_pin = 3; - drm_panel_disable(imxpd->panel); - drm_panel_unprepare(imxpd->panel); + return 0; } static const struct drm_connector_funcs imx_pd_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_pd_connector_detect, .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_pd_connector_helper_funcs = { @@ -158,20 +160,18 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = { }; static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { - .dpms = imx_pd_encoder_dpms, - .prepare = imx_pd_encoder_prepare, - .commit = imx_pd_encoder_commit, - .mode_set = imx_pd_encoder_mode_set, + .enable = imx_pd_encoder_enable, .disable = imx_pd_encoder_disable, + .atomic_check = imx_pd_encoder_atomic_check, }; static int imx_pd_register(struct drm_device *drm, struct imx_parallel_display *imxpd) { + struct drm_encoder *encoder = &imxpd->encoder; int ret; - ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder, - imxpd->dev->of_node); + ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node); if (ret) return ret; @@ -182,19 +182,33 @@ static int imx_pd_register(struct drm_device *drm, */ imxpd->connector.dpms = DRM_MODE_DPMS_OFF; - drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); - drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs, + drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs); + drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); - drm_connector_helper_add(&imxpd->connector, - &imx_pd_connector_helper_funcs); - drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs, - DRM_MODE_CONNECTOR_VGA); + if (!imxpd->bridge) { + drm_connector_helper_add(&imxpd->connector, + &imx_pd_connector_helper_funcs); + drm_connector_init(drm, &imxpd->connector, + &imx_pd_connector_funcs, + DRM_MODE_CONNECTOR_VGA); + } if (imxpd->panel) drm_panel_attach(imxpd->panel, &imxpd->connector); - drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); + if (imxpd->bridge) { + imxpd->bridge->encoder = encoder; + encoder->bridge = imxpd->bridge; + ret = drm_bridge_attach(drm, imxpd->bridge); + if (ret < 0) { + dev_err(imxpd->dev, "failed to attach bridge: %d\n", + ret); + return ret; + } + } else { + drm_mode_connector_attach_encoder(&imxpd->connector, encoder); + } return 0; } @@ -203,10 +217,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; struct device_node *np = dev->of_node; - struct device_node *port; + struct device_node *ep; const u8 *edidp; struct imx_parallel_display *imxpd; int ret; + u32 bus_format = 0; const char *fmt; imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); @@ -220,28 +235,46 @@ 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->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + bus_format = MEDIA_BUS_FMT_RGB888_1X24; else if (!strcmp(fmt, "rgb565")) - imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; + bus_format = MEDIA_BUS_FMT_RGB565_1X16; else if (!strcmp(fmt, "bgr666")) - imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; + bus_format = MEDIA_BUS_FMT_RGB666_1X18; else if (!strcmp(fmt, "lvds666")) - imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; + bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; } + imxpd->bus_format = bus_format; /* port@1 is the output port */ - port = of_graph_get_port_by_id(np, 1); - 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) - imxpd->panel = of_drm_find_panel(remote); - if (!imxpd->panel) - return -EPROBE_DEFER; + ep = of_graph_get_endpoint_by_regs(np, 1, -1); + if (ep) { + struct device_node *remote; + + remote = of_graph_get_remote_port_parent(ep); + if (!remote) { + dev_warn(dev, "endpoint %s not connected\n", + ep->full_name); + of_node_put(ep); + return -ENODEV; + } + of_node_put(ep); + + imxpd->panel = of_drm_find_panel(remote); + if (imxpd->panel) { + dev_dbg(dev, "found panel %s\n", remote->full_name); + } else { + imxpd->bridge = of_drm_find_bridge(remote); + if (imxpd->bridge) + dev_dbg(dev, "found bridge %s\n", + remote->full_name); } + if (!imxpd->panel && !imxpd->bridge) { + dev_dbg(dev, "waiting for panel or bridge %s\n", + remote->full_name); + of_node_put(remote); + return -EPROBE_DEFER; + } + of_node_put(remote); } imxpd->dev = dev; @@ -260,8 +293,10 @@ static void imx_pd_unbind(struct device *dev, struct device *master, { struct imx_parallel_display *imxpd = dev_get_drvdata(dev); - imxpd->encoder.funcs->destroy(&imxpd->encoder); - imxpd->connector.funcs->destroy(&imxpd->connector); + if (imxpd->bridge) + drm_bridge_detach(imxpd->bridge); + if (imxpd->panel) + drm_panel_detach(imxpd->panel); kfree(imxpd->edid); } |