diff options
author | Hai Li <hali@codeaurora.org> | 2015-01-08 00:47:44 +0100 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2015-02-01 21:30:37 +0100 |
commit | ab5b0107ccf3821a6837b0f2819270d6fa0b278f (patch) | |
tree | 87422469e4f1afaac11592f967ce246163cf7bf3 /drivers/gpu/drm/msm/edp/edp_connector.c | |
parent | drm/msm/mdp4: add YUV format support (diff) | |
download | linux-ab5b0107ccf3821a6837b0f2819270d6fa0b278f.tar.xz linux-ab5b0107ccf3821a6837b0f2819270d6fa0b278f.zip |
drm/msm: Initial add eDP support in msm drm driver (v5)
This change adds a new eDP connector in msm drm driver. With this
change, eDP panel can work with msm platform under drm framework.
v1: Initial change
v2: Address Rob's comments
Use generated header file for register definitions
Change to devm_* APIs
v3: Address Thierry's comments and rebase on top of atomic changes
Remove edp_bridge_mode_fixup
Remove backlight control code and rely on pwm-backlight
Remove continuous splash screen support for now
Change to gpiod_* APIs
v4: Fix kbuild test issue
Signed-off-by: Hai Li <hali@codeaurora.org>
[robclark: v5: rebase on drm_bridge changes in drm-next]
Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/msm/edp/edp_connector.c')
-rw-r--r-- | drivers/gpu/drm/msm/edp/edp_connector.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c new file mode 100644 index 000000000000..d8812e84da54 --- /dev/null +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "drm/drm_edid.h" +#include "msm_kms.h" +#include "edp.h" + +struct edp_connector { + struct drm_connector base; + struct msm_edp *edp; +}; +#define to_edp_connector(x) container_of(x, struct edp_connector, base) + +static enum drm_connector_status edp_connector_detect( + struct drm_connector *connector, bool force) +{ + struct edp_connector *edp_connector = to_edp_connector(connector); + struct msm_edp *edp = edp_connector->edp; + + DBG(""); + return msm_edp_ctrl_panel_connected(edp->ctrl) ? + connector_status_connected : connector_status_disconnected; +} + +static void edp_connector_destroy(struct drm_connector *connector) +{ + struct edp_connector *edp_connector = to_edp_connector(connector); + + DBG(""); + drm_connector_unregister(connector); + drm_connector_cleanup(connector); + + kfree(edp_connector); +} + +static int edp_connector_get_modes(struct drm_connector *connector) +{ + struct edp_connector *edp_connector = to_edp_connector(connector); + struct msm_edp *edp = edp_connector->edp; + + struct edid *drm_edid = NULL; + int ret = 0; + + DBG(""); + ret = msm_edp_ctrl_get_panel_info(edp->ctrl, connector, &drm_edid); + if (ret) + return ret; + + drm_mode_connector_update_edid_property(connector, drm_edid); + if (drm_edid) + ret = drm_add_edid_modes(connector, drm_edid); + + return ret; +} + +static int edp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct edp_connector *edp_connector = to_edp_connector(connector); + struct msm_edp *edp = edp_connector->edp; + struct msm_drm_private *priv = connector->dev->dev_private; + struct msm_kms *kms = priv->kms; + long actual, requested; + + requested = 1000 * mode->clock; + actual = kms->funcs->round_pixclk(kms, + requested, edp_connector->edp->encoder); + + DBG("requested=%ld, actual=%ld", requested, actual); + if (actual != requested) + return MODE_CLOCK_RANGE; + + if (!msm_edp_ctrl_pixel_clock_valid( + edp->ctrl, mode->clock, NULL, NULL)) + return MODE_CLOCK_RANGE; + + /* Invalidate all modes if color format is not supported */ + if (connector->display_info.bpc > 8) + return MODE_BAD; + + return MODE_OK; +} + +static struct drm_encoder * +edp_connector_best_encoder(struct drm_connector *connector) +{ + struct edp_connector *edp_connector = to_edp_connector(connector); + + DBG(""); + return edp_connector->edp->encoder; +} + +static const struct drm_connector_funcs edp_connector_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = edp_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = edp_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 edp_connector_helper_funcs = { + .get_modes = edp_connector_get_modes, + .mode_valid = edp_connector_mode_valid, + .best_encoder = edp_connector_best_encoder, +}; + +/* initialize connector */ +struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) +{ + struct drm_connector *connector = NULL; + struct edp_connector *edp_connector; + int ret; + + edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL); + if (!edp_connector) { + ret = -ENOMEM; + goto fail; + } + + edp_connector->edp = edp; + + connector = &edp_connector->base; + + ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs, + DRM_MODE_CONNECTOR_eDP); + if (ret) + goto fail; + + drm_connector_helper_add(connector, &edp_connector_helper_funcs); + + /* We don't support HPD, so only poll status until connected. */ + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + + /* Display driver doesn't support interlace now. */ + connector->interlace_allowed = false; + connector->doublescan_allowed = false; + + ret = drm_connector_register(connector); + if (ret) + goto fail; + + return connector; + +fail: + if (connector) + edp_connector_destroy(connector); + + return ERR_PTR(ret); +} |