dt-bindings: mtd: ingenic: Use standard ecc-engine property
[linux/fpc-iii.git] / drivers / gpu / drm / msm / hdmi / hdmi_bridge.c
blob03197b8959ba640e73f63b0201797edebb9e941e
1 /*
2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
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.
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.
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/>.
18 #include "hdmi.h"
20 struct hdmi_bridge {
21 struct drm_bridge base;
22 struct hdmi *hdmi;
24 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
26 void msm_hdmi_bridge_destroy(struct drm_bridge *bridge)
30 static void msm_hdmi_power_on(struct drm_bridge *bridge)
32 struct drm_device *dev = bridge->dev;
33 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
34 struct hdmi *hdmi = hdmi_bridge->hdmi;
35 const struct hdmi_platform_config *config = hdmi->config;
36 int i, ret;
38 pm_runtime_get_sync(&hdmi->pdev->dev);
40 for (i = 0; i < config->pwr_reg_cnt; i++) {
41 ret = regulator_enable(hdmi->pwr_regs[i]);
42 if (ret) {
43 DRM_DEV_ERROR(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
44 config->pwr_reg_names[i], ret);
48 if (config->pwr_clk_cnt > 0) {
49 DBG("pixclock: %lu", hdmi->pixclock);
50 ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
51 if (ret) {
52 DRM_DEV_ERROR(dev->dev, "failed to set pixel clk: %s (%d)\n",
53 config->pwr_clk_names[0], ret);
57 for (i = 0; i < config->pwr_clk_cnt; i++) {
58 ret = clk_prepare_enable(hdmi->pwr_clks[i]);
59 if (ret) {
60 DRM_DEV_ERROR(dev->dev, "failed to enable pwr clk: %s (%d)\n",
61 config->pwr_clk_names[i], ret);
66 static void power_off(struct drm_bridge *bridge)
68 struct drm_device *dev = bridge->dev;
69 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
70 struct hdmi *hdmi = hdmi_bridge->hdmi;
71 const struct hdmi_platform_config *config = hdmi->config;
72 int i, ret;
74 /* TODO do we need to wait for final vblank somewhere before
75 * cutting the clocks?
77 mdelay(16 + 4);
79 for (i = 0; i < config->pwr_clk_cnt; i++)
80 clk_disable_unprepare(hdmi->pwr_clks[i]);
82 for (i = 0; i < config->pwr_reg_cnt; i++) {
83 ret = regulator_disable(hdmi->pwr_regs[i]);
84 if (ret) {
85 DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
86 config->pwr_reg_names[i], ret);
90 pm_runtime_put_autosuspend(&hdmi->pdev->dev);
93 #define AVI_IFRAME_LINE_NUMBER 1
95 static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi)
97 struct drm_crtc *crtc = hdmi->encoder->crtc;
98 const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
99 union hdmi_infoframe frame;
100 u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
101 u32 val;
102 int len;
104 drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
105 hdmi->connector, mode);
107 len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
108 if (len < 0) {
109 DRM_DEV_ERROR(&hdmi->pdev->dev,
110 "failed to configure avi infoframe\n");
111 return;
115 * the AVI_INFOx registers don't map exactly to how the AVI infoframes
116 * are packed according to the spec. The checksum from the header is
117 * written to the LSB byte of AVI_INFO0 and the version is written to
118 * the third byte from the LSB of AVI_INFO3
120 hdmi_write(hdmi, REG_HDMI_AVI_INFO(0),
121 buffer[3] |
122 buffer[4] << 8 |
123 buffer[5] << 16 |
124 buffer[6] << 24);
126 hdmi_write(hdmi, REG_HDMI_AVI_INFO(1),
127 buffer[7] |
128 buffer[8] << 8 |
129 buffer[9] << 16 |
130 buffer[10] << 24);
132 hdmi_write(hdmi, REG_HDMI_AVI_INFO(2),
133 buffer[11] |
134 buffer[12] << 8 |
135 buffer[13] << 16 |
136 buffer[14] << 24);
138 hdmi_write(hdmi, REG_HDMI_AVI_INFO(3),
139 buffer[15] |
140 buffer[16] << 8 |
141 buffer[1] << 24);
143 hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0,
144 HDMI_INFOFRAME_CTRL0_AVI_SEND |
145 HDMI_INFOFRAME_CTRL0_AVI_CONT);
147 val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1);
148 val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK;
149 val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER);
150 hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val);
153 static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
155 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
156 struct hdmi *hdmi = hdmi_bridge->hdmi;
157 struct hdmi_phy *phy = hdmi->phy;
159 DBG("power up");
161 if (!hdmi->power_on) {
162 msm_hdmi_phy_resource_enable(phy);
163 msm_hdmi_power_on(bridge);
164 hdmi->power_on = true;
165 if (hdmi->hdmi_mode) {
166 msm_hdmi_config_avi_infoframe(hdmi);
167 msm_hdmi_audio_update(hdmi);
171 msm_hdmi_phy_powerup(phy, hdmi->pixclock);
173 msm_hdmi_set_mode(hdmi, true);
175 if (hdmi->hdcp_ctrl)
176 msm_hdmi_hdcp_on(hdmi->hdcp_ctrl);
179 static void msm_hdmi_bridge_enable(struct drm_bridge *bridge)
183 static void msm_hdmi_bridge_disable(struct drm_bridge *bridge)
187 static void msm_hdmi_bridge_post_disable(struct drm_bridge *bridge)
189 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
190 struct hdmi *hdmi = hdmi_bridge->hdmi;
191 struct hdmi_phy *phy = hdmi->phy;
193 if (hdmi->hdcp_ctrl)
194 msm_hdmi_hdcp_off(hdmi->hdcp_ctrl);
196 DBG("power down");
197 msm_hdmi_set_mode(hdmi, false);
199 msm_hdmi_phy_powerdown(phy);
201 if (hdmi->power_on) {
202 power_off(bridge);
203 hdmi->power_on = false;
204 if (hdmi->hdmi_mode)
205 msm_hdmi_audio_update(hdmi);
206 msm_hdmi_phy_resource_disable(phy);
210 static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge,
211 const struct drm_display_mode *mode,
212 const struct drm_display_mode *adjusted_mode)
214 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
215 struct hdmi *hdmi = hdmi_bridge->hdmi;
216 int hstart, hend, vstart, vend;
217 uint32_t frame_ctrl;
219 mode = adjusted_mode;
221 hdmi->pixclock = mode->clock * 1000;
223 hstart = mode->htotal - mode->hsync_start;
224 hend = mode->htotal - mode->hsync_start + mode->hdisplay;
226 vstart = mode->vtotal - mode->vsync_start - 1;
227 vend = mode->vtotal - mode->vsync_start + mode->vdisplay - 1;
229 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
230 mode->htotal, mode->vtotal, hstart, hend, vstart, vend);
232 hdmi_write(hdmi, REG_HDMI_TOTAL,
233 HDMI_TOTAL_H_TOTAL(mode->htotal - 1) |
234 HDMI_TOTAL_V_TOTAL(mode->vtotal - 1));
236 hdmi_write(hdmi, REG_HDMI_ACTIVE_HSYNC,
237 HDMI_ACTIVE_HSYNC_START(hstart) |
238 HDMI_ACTIVE_HSYNC_END(hend));
239 hdmi_write(hdmi, REG_HDMI_ACTIVE_VSYNC,
240 HDMI_ACTIVE_VSYNC_START(vstart) |
241 HDMI_ACTIVE_VSYNC_END(vend));
243 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
244 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
245 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode->vtotal));
246 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
247 HDMI_VSYNC_ACTIVE_F2_START(vstart + 1) |
248 HDMI_VSYNC_ACTIVE_F2_END(vend + 1));
249 } else {
250 hdmi_write(hdmi, REG_HDMI_VSYNC_TOTAL_F2,
251 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
252 hdmi_write(hdmi, REG_HDMI_VSYNC_ACTIVE_F2,
253 HDMI_VSYNC_ACTIVE_F2_START(0) |
254 HDMI_VSYNC_ACTIVE_F2_END(0));
257 frame_ctrl = 0;
258 if (mode->flags & DRM_MODE_FLAG_NHSYNC)
259 frame_ctrl |= HDMI_FRAME_CTRL_HSYNC_LOW;
260 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
261 frame_ctrl |= HDMI_FRAME_CTRL_VSYNC_LOW;
262 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
263 frame_ctrl |= HDMI_FRAME_CTRL_INTERLACED_EN;
264 DBG("frame_ctrl=%08x", frame_ctrl);
265 hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
267 if (hdmi->hdmi_mode)
268 msm_hdmi_audio_update(hdmi);
271 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
272 .pre_enable = msm_hdmi_bridge_pre_enable,
273 .enable = msm_hdmi_bridge_enable,
274 .disable = msm_hdmi_bridge_disable,
275 .post_disable = msm_hdmi_bridge_post_disable,
276 .mode_set = msm_hdmi_bridge_mode_set,
280 /* initialize bridge */
281 struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
283 struct drm_bridge *bridge = NULL;
284 struct hdmi_bridge *hdmi_bridge;
285 int ret;
287 hdmi_bridge = devm_kzalloc(hdmi->dev->dev,
288 sizeof(*hdmi_bridge), GFP_KERNEL);
289 if (!hdmi_bridge) {
290 ret = -ENOMEM;
291 goto fail;
294 hdmi_bridge->hdmi = hdmi;
296 bridge = &hdmi_bridge->base;
297 bridge->funcs = &msm_hdmi_bridge_funcs;
299 ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
300 if (ret)
301 goto fail;
303 return bridge;
305 fail:
306 if (bridge)
307 msm_hdmi_bridge_destroy(bridge);
309 return ERR_PTR(ret);