| /* |
| * 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 "edp.h" |
| |
| struct edp_bridge { |
| struct drm_bridge base; |
| struct msm_edp *edp; |
| }; |
| #define to_edp_bridge(x) container_of(x, struct edp_bridge, base) |
| |
| void edp_bridge_destroy(struct drm_bridge *bridge) |
| { |
| } |
| |
| static void edp_bridge_pre_enable(struct drm_bridge *bridge) |
| { |
| struct edp_bridge *edp_bridge = to_edp_bridge(bridge); |
| struct msm_edp *edp = edp_bridge->edp; |
| |
| DBG(""); |
| msm_edp_ctrl_power(edp->ctrl, true); |
| } |
| |
| static void edp_bridge_enable(struct drm_bridge *bridge) |
| { |
| DBG(""); |
| } |
| |
| static void edp_bridge_disable(struct drm_bridge *bridge) |
| { |
| DBG(""); |
| } |
| |
| static void edp_bridge_post_disable(struct drm_bridge *bridge) |
| { |
| struct edp_bridge *edp_bridge = to_edp_bridge(bridge); |
| struct msm_edp *edp = edp_bridge->edp; |
| |
| DBG(""); |
| msm_edp_ctrl_power(edp->ctrl, false); |
| } |
| |
| static void edp_bridge_mode_set(struct drm_bridge *bridge, |
| struct drm_display_mode *mode, |
| struct drm_display_mode *adjusted_mode) |
| { |
| struct drm_device *dev = bridge->dev; |
| struct drm_connector *connector; |
| struct edp_bridge *edp_bridge = to_edp_bridge(bridge); |
| struct msm_edp *edp = edp_bridge->edp; |
| |
| DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", |
| mode->base.id, mode->name, |
| mode->vrefresh, mode->clock, |
| mode->hdisplay, mode->hsync_start, |
| mode->hsync_end, mode->htotal, |
| mode->vdisplay, mode->vsync_start, |
| mode->vsync_end, mode->vtotal, |
| mode->type, mode->flags); |
| |
| list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
| if ((connector->encoder != NULL) && |
| (connector->encoder->bridge == bridge)) { |
| msm_edp_ctrl_timing_cfg(edp->ctrl, |
| adjusted_mode, &connector->display_info); |
| break; |
| } |
| } |
| } |
| |
| static const struct drm_bridge_funcs edp_bridge_funcs = { |
| .pre_enable = edp_bridge_pre_enable, |
| .enable = edp_bridge_enable, |
| .disable = edp_bridge_disable, |
| .post_disable = edp_bridge_post_disable, |
| .mode_set = edp_bridge_mode_set, |
| }; |
| |
| /* initialize bridge */ |
| struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp) |
| { |
| struct drm_bridge *bridge = NULL; |
| struct edp_bridge *edp_bridge; |
| int ret; |
| |
| edp_bridge = devm_kzalloc(edp->dev->dev, |
| sizeof(*edp_bridge), GFP_KERNEL); |
| if (!edp_bridge) { |
| ret = -ENOMEM; |
| goto fail; |
| } |
| |
| edp_bridge->edp = edp; |
| |
| bridge = &edp_bridge->base; |
| bridge->funcs = &edp_bridge_funcs; |
| |
| ret = drm_bridge_attach(edp->encoder, bridge, NULL); |
| if (ret) |
| goto fail; |
| |
| return bridge; |
| |
| fail: |
| if (bridge) |
| edp_bridge_destroy(bridge); |
| |
| return ERR_PTR(ret); |
| } |