]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drm/msm: convert to drm_bridge
[karo-tx-linux.git] / drivers / gpu / drm / msm / hdmi / hdmi_bridge.c
1 /*
2  * Copyright (C) 2013 Red Hat
3  * Author: Rob Clark <robdclark@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "hdmi.h"
19
20 struct hdmi_bridge {
21         struct drm_bridge base;
22
23         struct hdmi *hdmi;
24
25         unsigned long int pixclock;
26 };
27 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
28
29 static void hdmi_bridge_destroy(struct drm_bridge *bridge)
30 {
31         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
32         hdmi_unreference(hdmi_bridge->hdmi);
33         drm_bridge_cleanup(bridge);
34         kfree(hdmi_bridge);
35 }
36
37 static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
38 {
39         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
40         struct hdmi *hdmi = hdmi_bridge->hdmi;
41         struct hdmi_phy *phy = hdmi->phy;
42
43         DBG("power up");
44         phy->funcs->powerup(phy, hdmi_bridge->pixclock);
45         hdmi_set_mode(hdmi, true);
46 }
47
48 static void hdmi_bridge_enable(struct drm_bridge *bridge)
49 {
50 }
51
52 static void hdmi_bridge_disable(struct drm_bridge *bridge)
53 {
54 }
55
56 static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
57 {
58         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
59         struct hdmi *hdmi = hdmi_bridge->hdmi;
60         struct hdmi_phy *phy = hdmi->phy;
61
62         DBG("power down");
63         hdmi_set_mode(hdmi, false);
64         phy->funcs->powerdown(phy);
65 }
66
67 static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
68                  struct drm_display_mode *mode,
69                  struct drm_display_mode *adjusted_mode)
70 {
71         struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
72         struct hdmi *hdmi = hdmi_bridge->hdmi;
73         int hstart, hend, vstart, vend;
74         uint32_t frame_ctrl;
75
76         mode = adjusted_mode;
77
78         hdmi_bridge->pixclock = mode->clock * 1000;
79
80         hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
81
82         hstart = mode->htotal - mode->hsync_start;
83         hend   = mode->htotal - mode->hsync_start + mode->hdisplay;
84
85         vstart = mode->vtotal - mode->vsync_start - 1;
86         vend   = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
87
88         DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
89                         mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
90
91         hdmi_write(hdmi, REG_HDMI_TOTAL,
92                         HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
93                         HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
94
95         hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
96                         HDMI_ACTIVE_HSYNC_START(hstart) |
97                         HDMI_ACTIVE_HSYNC_END(hend));
98         hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
99                         HDMI_ACTIVE_VSYNC_START(vstart) |
100                         HDMI_ACTIVE_VSYNC_END(vend));
101
102         if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
103                 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
104                                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
105                 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
106                                 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
107                                 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
108         } else {
109                 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
110                                 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
111                 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
112                                 HDMI_VSYNC_ACTIVE_F2_START(0) |
113                                 HDMI_VSYNC_ACTIVE_F2_END(0));
114         }
115
116         frame_ctrl = 0;
117         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
118                 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
119         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
120                 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
121         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
122                 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
123         DBG("frame_ctrl=%08x", frame_ctrl);
124         hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
125
126         // TODO until we have audio, this might be safest:
127         if (hdmi->hdmi_mode)
128                 hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
129 }
130
131 static const struct drm_bridge_funcs hdmi_bridge_funcs = {
132                 .pre_enable = hdmi_bridge_pre_enable,
133                 .enable = hdmi_bridge_enable,
134                 .disable = hdmi_bridge_disable,
135                 .post_disable = hdmi_bridge_post_disable,
136                 .mode_set = hdmi_bridge_mode_set,
137                 .destroy = hdmi_bridge_destroy,
138 };
139
140
141 /* initialize bridge */
142 struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
143 {
144         struct drm_bridge *bridge = NULL;
145         struct hdmi_bridge *hdmi_bridge;
146         int ret;
147
148         hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
149         if (!hdmi_bridge) {
150                 ret = -ENOMEM;
151                 goto fail;
152         }
153
154         hdmi_bridge->hdmi = hdmi_reference(hdmi);
155
156         bridge = &hdmi_bridge->base;
157
158         drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
159
160         return bridge;
161
162 fail:
163         if (bridge)
164                 hdmi_bridge_destroy(bridge);
165
166         return ERR_PTR(ret);
167 }