/* * 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); }