aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-12-01 12:12:54 -0500
committerRob Clark <robdclark@gmail.com>2014-01-09 14:44:05 -0500
commitdada25bd22a52a4351357209a8c227070cfd406d (patch)
treea90fd5973a2f7d730cec2918875a0006a1e3d3e8 /drivers/gpu/drm/msm
parent9e0efa63565511dc75846e6b036a4b80e92b9a98 (diff)
drm/msm: add hdmi support for apq8x74/mdp5
The HDMI block is basically the same between older SoC's with mdp4 display controller, and newer ones with mdp5. So mostly this consists of better abstracting out the different sets of regulators, clks, etc. In particular, for regulators and clks we can split it up by what is needed for hot plug detect to work, and what is needed to light up the display. Also, 8x74 has a new phy.. a very simple one, but split out into a different mmio space. And with mdp5, the irq is shared with mdp, so we don't directly register our own irq handler. Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/msm')
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c199
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h38
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c71
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c138
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c157
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c10
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h4
8 files changed, 511 insertions, 107 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 17847af4e7ab..59b76edb5fdd 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -12,6 +12,7 @@ msm-y := \
12 hdmi/hdmi_i2c.o \ 12 hdmi/hdmi_i2c.o \
13 hdmi/hdmi_phy_8960.o \ 13 hdmi/hdmi_phy_8960.o \
14 hdmi/hdmi_phy_8x60.o \ 14 hdmi/hdmi_phy_8x60.o \
15 hdmi/hdmi_phy_8x74.o \
15 mdp/mdp_format.o \ 16 mdp/mdp_format.o \
16 mdp/mdp_kms.o \ 17 mdp/mdp_kms.o \
17 mdp/mdp4/mdp4_crtc.o \ 18 mdp/mdp4/mdp4_crtc.o \
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 32f26f855050..6f1588aa9071 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -41,7 +41,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
41 power_on ? "Enable" : "Disable", ctrl); 41 power_on ? "Enable" : "Disable", ctrl);
42} 42}
43 43
44static irqreturn_t hdmi_irq(int irq, void *dev_id) 44irqreturn_t hdmi_irq(int irq, void *dev_id)
45{ 45{
46 struct hdmi *hdmi = dev_id; 46 struct hdmi *hdmi = dev_id;
47 47
@@ -71,13 +71,13 @@ void hdmi_destroy(struct kref *kref)
71} 71}
72 72
73/* initialize connector */ 73/* initialize connector */
74int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) 74struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
75{ 75{
76 struct hdmi *hdmi = NULL; 76 struct hdmi *hdmi = NULL;
77 struct msm_drm_private *priv = dev->dev_private; 77 struct msm_drm_private *priv = dev->dev_private;
78 struct platform_device *pdev = hdmi_pdev; 78 struct platform_device *pdev = hdmi_pdev;
79 struct hdmi_platform_config *config; 79 struct hdmi_platform_config *config;
80 int ret; 80 int i, ret;
81 81
82 if (!pdev) { 82 if (!pdev) {
83 dev_err(dev->dev, "no hdmi device\n"); 83 dev_err(dev->dev, "no hdmi device\n");
@@ -99,6 +99,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
99 99
100 hdmi->dev = dev; 100 hdmi->dev = dev;
101 hdmi->pdev = pdev; 101 hdmi->pdev = pdev;
102 hdmi->config = config;
102 hdmi->encoder = encoder; 103 hdmi->encoder = encoder;
103 104
104 /* not sure about which phy maps to which msm.. probably I miss some */ 105 /* not sure about which phy maps to which msm.. probably I miss some */
@@ -114,44 +115,70 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
114 goto fail; 115 goto fail;
115 } 116 }
116 117
117 hdmi->mmio = msm_ioremap(pdev, "hdmi_msm_hdmi_addr", "HDMI"); 118 hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
118 if (IS_ERR(hdmi->mmio)) { 119 if (IS_ERR(hdmi->mmio)) {
119 ret = PTR_ERR(hdmi->mmio); 120 ret = PTR_ERR(hdmi->mmio);
120 goto fail; 121 goto fail;
121 } 122 }
122 123
123 hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs"); 124 BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs));
124 if (IS_ERR(hdmi->mvs)) 125 for (i = 0; i < config->hpd_reg_cnt; i++) {
125 hdmi->mvs = devm_regulator_get(&pdev->dev, "8921_hdmi_mvs"); 126 struct regulator *reg;
126 if (IS_ERR(hdmi->mvs)) { 127
127 ret = PTR_ERR(hdmi->mvs); 128 reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]);
128 dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret); 129 if (IS_ERR(reg)) {
129 goto fail; 130 ret = PTR_ERR(reg);
131 dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
132 config->hpd_reg_names[i], ret);
133 goto fail;
134 }
135
136 hdmi->hpd_regs[i] = reg;
130 } 137 }
131 138
132 hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0"); 139 BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs));
133 if (IS_ERR(hdmi->mpp0)) 140 for (i = 0; i < config->pwr_reg_cnt; i++) {
134 hdmi->mpp0 = NULL; 141 struct regulator *reg;
135 142
136 hdmi->clk = devm_clk_get(&pdev->dev, "core_clk"); 143 reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]);
137 if (IS_ERR(hdmi->clk)) { 144 if (IS_ERR(reg)) {
138 ret = PTR_ERR(hdmi->clk); 145 ret = PTR_ERR(reg);
139 dev_err(dev->dev, "failed to get 'clk': %d\n", ret); 146 dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
140 goto fail; 147 config->pwr_reg_names[i], ret);
148 goto fail;
149 }
150
151 hdmi->pwr_regs[i] = reg;
141 } 152 }
142 153
143 hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk"); 154 BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks));
144 if (IS_ERR(hdmi->m_pclk)) { 155 for (i = 0; i < config->hpd_clk_cnt; i++) {
145 ret = PTR_ERR(hdmi->m_pclk); 156 struct clk *clk;
146 dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret); 157
147 goto fail; 158 clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]);
159 if (IS_ERR(clk)) {
160 ret = PTR_ERR(clk);
161 dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n",
162 config->hpd_clk_names[i], ret);
163 goto fail;
164 }
165
166 hdmi->hpd_clks[i] = clk;
148 } 167 }
149 168
150 hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk"); 169 BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks));
151 if (IS_ERR(hdmi->s_pclk)) { 170 for (i = 0; i < config->pwr_clk_cnt; i++) {
152 ret = PTR_ERR(hdmi->s_pclk); 171 struct clk *clk;
153 dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret); 172
154 goto fail; 173 clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]);
174 if (IS_ERR(clk)) {
175 ret = PTR_ERR(clk);
176 dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n",
177 config->pwr_clk_names[i], ret);
178 goto fail;
179 }
180
181 hdmi->pwr_clks[i] = clk;
155 } 182 }
156 183
157 hdmi->i2c = hdmi_i2c_init(hdmi); 184 hdmi->i2c = hdmi_i2c_init(hdmi);
@@ -178,20 +205,22 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
178 goto fail; 205 goto fail;
179 } 206 }
180 207
181 hdmi->irq = platform_get_irq(pdev, 0); 208 if (!config->shared_irq) {
182 if (hdmi->irq < 0) { 209 hdmi->irq = platform_get_irq(pdev, 0);
183 ret = hdmi->irq; 210 if (hdmi->irq < 0) {
184 dev_err(dev->dev, "failed to get irq: %d\n", ret); 211 ret = hdmi->irq;
185 goto fail; 212 dev_err(dev->dev, "failed to get irq: %d\n", ret);
186 } 213 goto fail;
214 }
187 215
188 ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, 216 ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq,
189 NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 217 NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
190 "hdmi_isr", hdmi); 218 "hdmi_isr", hdmi);
191 if (ret < 0) { 219 if (ret < 0) {
192 dev_err(dev->dev, "failed to request IRQ%u: %d\n", 220 dev_err(dev->dev, "failed to request IRQ%u: %d\n",
193 hdmi->irq, ret); 221 hdmi->irq, ret);
194 goto fail; 222 goto fail;
223 }
195 } 224 }
196 225
197 encoder->bridge = hdmi->bridge; 226 encoder->bridge = hdmi->bridge;
@@ -199,7 +228,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
199 priv->bridges[priv->num_bridges++] = hdmi->bridge; 228 priv->bridges[priv->num_bridges++] = hdmi->bridge;
200 priv->connectors[priv->num_connectors++] = hdmi->connector; 229 priv->connectors[priv->num_connectors++] = hdmi->connector;
201 230
202 return 0; 231 return hdmi;
203 232
204fail: 233fail:
205 if (hdmi) { 234 if (hdmi) {
@@ -211,37 +240,100 @@ fail:
211 hdmi_destroy(&hdmi->refcount); 240 hdmi_destroy(&hdmi->refcount);
212 } 241 }
213 242
214 return ret; 243 return ERR_PTR(ret);
215} 244}
216 245
217/* 246/*
218 * The hdmi device: 247 * The hdmi device:
219 */ 248 */
220 249
250#include <linux/of_gpio.h>
251
221static int hdmi_dev_probe(struct platform_device *pdev) 252static int hdmi_dev_probe(struct platform_device *pdev)
222{ 253{
223 static struct hdmi_platform_config config = {}; 254 static struct hdmi_platform_config config = {};
224#ifdef CONFIG_OF 255#ifdef CONFIG_OF
225 /* TODO */ 256 struct device_node *of_node = pdev->dev.of_node;
257
258 int get_gpio(const char *name)
259 {
260 int gpio = of_get_named_gpio(of_node, name, 0);
261 if (gpio < 0) {
262 dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n",
263 name, gpio);
264 gpio = -1;
265 }
266 return gpio;
267 }
268
269 /* TODO actually use DT.. */
270 static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
271 static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
272 static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
273 static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
274
275 config.phy_init = hdmi_phy_8x74_init;
276 config.mmio_name = "core_physical";
277 config.hpd_reg_names = hpd_reg_names;
278 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
279 config.pwr_reg_names = pwr_reg_names;
280 config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names);
281 config.hpd_clk_names = hpd_clk_names;
282 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
283 config.pwr_clk_names = pwr_clk_names;
284 config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names);
285 config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk");
286 config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data");
287 config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd");
288 config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en");
289 config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel");
290 config.shared_irq = true;
291
226#else 292#else
293 static const char *hpd_clk_names[] = {
294 "core_clk", "master_iface_clk", "slave_iface_clk",
295 };
227 if (cpu_is_apq8064()) { 296 if (cpu_is_apq8064()) {
297 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
228 config.phy_init = hdmi_phy_8960_init; 298 config.phy_init = hdmi_phy_8960_init;
299 config.mmio_name = "hdmi_msm_hdmi_addr";
300 config.hpd_reg_names = hpd_reg_names;
301 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
302 config.hpd_clk_names = hpd_clk_names;
303 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
229 config.ddc_clk_gpio = 70; 304 config.ddc_clk_gpio = 70;
230 config.ddc_data_gpio = 71; 305 config.ddc_data_gpio = 71;
231 config.hpd_gpio = 72; 306 config.hpd_gpio = 72;
232 config.pmic_gpio = 13 + NR_GPIO_IRQS; 307 config.mux_en_gpio = -1;
308 config.mux_sel_gpio = 13 + NR_GPIO_IRQS;
233 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { 309 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
310 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
234 config.phy_init = hdmi_phy_8960_init; 311 config.phy_init = hdmi_phy_8960_init;
312 config.mmio_name = "hdmi_msm_hdmi_addr";
313 config.hpd_reg_names = hpd_reg_names;
314 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
315 config.hpd_clk_names = hpd_clk_names;
316 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
235 config.ddc_clk_gpio = 100; 317 config.ddc_clk_gpio = 100;
236 config.ddc_data_gpio = 101; 318 config.ddc_data_gpio = 101;
237 config.hpd_gpio = 102; 319 config.hpd_gpio = 102;
238 config.pmic_gpio = -1; 320 config.mux_en_gpio = -1;
321 config.mux_sel_gpio = -1;
239 } else if (cpu_is_msm8x60()) { 322 } else if (cpu_is_msm8x60()) {
323 static const char *hpd_reg_names[] = {
324 "8901_hdmi_mvs", "8901_mpp0"
325 };
240 config.phy_init = hdmi_phy_8x60_init; 326 config.phy_init = hdmi_phy_8x60_init;
327 config.mmio_name = "hdmi_msm_hdmi_addr";
328 config.hpd_reg_names = hpd_reg_names;
329 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
330 config.hpd_clk_names = hpd_clk_names;
331 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
241 config.ddc_clk_gpio = 170; 332 config.ddc_clk_gpio = 170;
242 config.ddc_data_gpio = 171; 333 config.ddc_data_gpio = 171;
243 config.hpd_gpio = 172; 334 config.hpd_gpio = 172;
244 config.pmic_gpio = -1; 335 config.mux_en_gpio = -1;
336 config.mux_sel_gpio = -1;
245 } 337 }
246#endif 338#endif
247 pdev->dev.platform_data = &config; 339 pdev->dev.platform_data = &config;
@@ -255,10 +347,19 @@ static int hdmi_dev_remove(struct platform_device *pdev)
255 return 0; 347 return 0;
256} 348}
257 349
350static const struct of_device_id dt_match[] = {
351 { .compatible = "qcom,hdmi-tx" },
352 {}
353};
354MODULE_DEVICE_TABLE(of, dt_match);
355
258static struct platform_driver hdmi_driver = { 356static struct platform_driver hdmi_driver = {
259 .probe = hdmi_dev_probe, 357 .probe = hdmi_dev_probe,
260 .remove = hdmi_dev_remove, 358 .remove = hdmi_dev_remove,
261 .driver.name = "hdmi_msm", 359 .driver = {
360 .name = "hdmi_msm",
361 .of_match_table = dt_match,
362 },
262}; 363};
263 364
264void __init hdmi_register(void) 365void __init hdmi_register(void)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 2c2ec566394c..41b29add70b1 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -28,6 +28,7 @@
28 28
29 29
30struct hdmi_phy; 30struct hdmi_phy;
31struct hdmi_platform_config;
31 32
32struct hdmi { 33struct hdmi {
33 struct kref refcount; 34 struct kref refcount;
@@ -35,14 +36,14 @@ struct hdmi {
35 struct drm_device *dev; 36 struct drm_device *dev;
36 struct platform_device *pdev; 37 struct platform_device *pdev;
37 38
38 void __iomem *mmio; 39 const struct hdmi_platform_config *config;
39 40
40 struct regulator *mvs; /* HDMI_5V */ 41 void __iomem *mmio;
41 struct regulator *mpp0; /* External 5V */
42 42
43 struct clk *clk; 43 struct regulator *hpd_regs[2];
44 struct clk *m_pclk; 44 struct regulator *pwr_regs[2];
45 struct clk *s_pclk; 45 struct clk *hpd_clks[3];
46 struct clk *pwr_clks[2];
46 47
47 struct hdmi_phy *phy; 48 struct hdmi_phy *phy;
48 struct i2c_adapter *i2c; 49 struct i2c_adapter *i2c;
@@ -60,7 +61,29 @@ struct hdmi {
60/* platform config data (ie. from DT, or pdata) */ 61/* platform config data (ie. from DT, or pdata) */
61struct hdmi_platform_config { 62struct hdmi_platform_config {
62 struct hdmi_phy *(*phy_init)(struct hdmi *hdmi); 63 struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
63 int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, pmic_gpio; 64 const char *mmio_name;
65
66 /* regulators that need to be on for hpd: */
67 const char **hpd_reg_names;
68 int hpd_reg_cnt;
69
70 /* regulators that need to be on for screen pwr: */
71 const char **pwr_reg_names;
72 int pwr_reg_cnt;
73
74 /* clks that need to be on for hpd: */
75 const char **hpd_clk_names;
76 int hpd_clk_cnt;
77
78 /* clks that need to be on for screen pwr (ie pixel clk): */
79 const char **pwr_clk_names;
80 int pwr_clk_cnt;
81
82 /* gpio's: */
83 int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio;
84
85 /* older devices had their own irq, mdp5+ it is shared w/ mdp: */
86 bool shared_irq;
64}; 87};
65 88
66void hdmi_set_mode(struct hdmi *hdmi, bool power_on); 89void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
@@ -106,6 +129,7 @@ struct hdmi_phy {
106 129
107struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi); 130struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
108struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); 131struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
132struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi);
109 133
110/* 134/*
111 * hdmi bridge: 135 * hdmi bridge:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 5a8ee3473cf5..7d10e55403c6 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -21,6 +21,7 @@ struct hdmi_bridge {
21 struct drm_bridge base; 21 struct drm_bridge base;
22 22
23 struct hdmi *hdmi; 23 struct hdmi *hdmi;
24 bool power_on;
24 25
25 unsigned long int pixclock; 26 unsigned long int pixclock;
26}; 27};
@@ -34,6 +35,65 @@ static void hdmi_bridge_destroy(struct drm_bridge *bridge)
34 kfree(hdmi_bridge); 35 kfree(hdmi_bridge);
35} 36}
36 37
38static void power_on(struct drm_bridge *bridge)
39{
40 struct drm_device *dev = bridge->dev;
41 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
42 struct hdmi *hdmi = hdmi_bridge->hdmi;
43 const struct hdmi_platform_config *config = hdmi->config;
44 int i, ret;
45
46 for (i = 0; i < config->pwr_reg_cnt; i++) {
47 ret = regulator_enable(hdmi->pwr_regs[i]);
48 if (ret) {
49 dev_err(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
50 config->pwr_reg_names[i], ret);
51 }
52 }
53
54 if (config->pwr_clk_cnt > 0) {
55 DBG("pixclock: %lu", hdmi_bridge->pixclock);
56 ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock);
57 if (ret) {
58 dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n",
59 config->pwr_clk_names[0], ret);
60 }
61 }
62
63 for (i = 0; i < config->pwr_clk_cnt; i++) {
64 ret = clk_prepare_enable(hdmi->pwr_clks[i]);
65 if (ret) {
66 dev_err(dev->dev, "failed to enable pwr clk: %s (%d)\n",
67 config->pwr_clk_names[i], ret);
68 }
69 }
70}
71
72static void power_off(struct drm_bridge *bridge)
73{
74 struct drm_device *dev = bridge->dev;
75 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
76 struct hdmi *hdmi = hdmi_bridge->hdmi;
77 const struct hdmi_platform_config *config = hdmi->config;
78 int i, ret;
79
80 /* TODO do we need to wait for final vblank somewhere before
81 * cutting the clocks?
82 */
83 mdelay(16 + 4);
84
85 for (i = 0; i < config->pwr_clk_cnt; i++)
86 clk_disable_unprepare(hdmi->pwr_clks[i]);
87
88 for (i = 0; i < config->pwr_reg_cnt; i++) {
89 ret = regulator_disable(hdmi->pwr_regs[i]);
90 if (ret) {
91 dev_err(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
92 config->pwr_reg_names[i], ret);
93 }
94 }
95}
96
37static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) 97static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
38{ 98{
39 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); 99 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
@@ -41,6 +101,12 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
41 struct hdmi_phy *phy = hdmi->phy; 101 struct hdmi_phy *phy = hdmi->phy;
42 102
43 DBG("power up"); 103 DBG("power up");
104
105 if (!hdmi_bridge->power_on) {
106 power_on(bridge);
107 hdmi_bridge->power_on = true;
108 }
109
44 phy->funcs->powerup(phy, hdmi_bridge->pixclock); 110 phy->funcs->powerup(phy, hdmi_bridge->pixclock);
45 hdmi_set_mode(hdmi, true); 111 hdmi_set_mode(hdmi, true);
46} 112}
@@ -62,6 +128,11 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
62 DBG("power down"); 128 DBG("power down");
63 hdmi_set_mode(hdmi, false); 129 hdmi_set_mode(hdmi, false);
64 phy->funcs->powerdown(phy); 130 phy->funcs->powerdown(phy);
131
132 if (hdmi_bridge->power_on) {
133 power_off(bridge);
134 hdmi_bridge->power_on = false;
135 }
65} 136}
66 137
67static void hdmi_bridge_mode_set(struct drm_bridge *bridge, 138static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index 197b34899b5a..7dedfdd12075 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -23,14 +23,14 @@
23struct hdmi_connector { 23struct hdmi_connector {
24 struct drm_connector base; 24 struct drm_connector base;
25 struct hdmi *hdmi; 25 struct hdmi *hdmi;
26 struct work_struct hpd_work;
26}; 27};
27#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) 28#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
28 29
29static int gpio_config(struct hdmi *hdmi, bool on) 30static int gpio_config(struct hdmi *hdmi, bool on)
30{ 31{
31 struct drm_device *dev = hdmi->dev; 32 struct drm_device *dev = hdmi->dev;
32 struct hdmi_platform_config *config = 33 const struct hdmi_platform_config *config = hdmi->config;
33 hdmi->pdev->dev.platform_data;
34 int ret; 34 int ret;
35 35
36 if (on) { 36 if (on) {
@@ -40,26 +40,43 @@ static int gpio_config(struct hdmi *hdmi, bool on)
40 "HDMI_DDC_CLK", config->ddc_clk_gpio, ret); 40 "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
41 goto error1; 41 goto error1;
42 } 42 }
43 gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
44
43 ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA"); 45 ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
44 if (ret) { 46 if (ret) {
45 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 47 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
46 "HDMI_DDC_DATA", config->ddc_data_gpio, ret); 48 "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
47 goto error2; 49 goto error2;
48 } 50 }
51 gpio_set_value_cansleep(config->ddc_data_gpio, 1);
52
49 ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); 53 ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
50 if (ret) { 54 if (ret) {
51 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 55 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
52 "HDMI_HPD", config->hpd_gpio, ret); 56 "HDMI_HPD", config->hpd_gpio, ret);
53 goto error3; 57 goto error3;
54 } 58 }
55 if (config->pmic_gpio != -1) { 59 gpio_direction_input(config->hpd_gpio);
56 ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL"); 60 gpio_set_value_cansleep(config->hpd_gpio, 1);
61
62 if (config->mux_en_gpio != -1) {
63 ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN");
57 if (ret) { 64 if (ret) {
58 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 65 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
59 "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret); 66 "HDMI_MUX_SEL", config->mux_en_gpio, ret);
60 goto error4; 67 goto error4;
61 } 68 }
62 gpio_set_value_cansleep(config->pmic_gpio, 0); 69 gpio_set_value_cansleep(config->mux_en_gpio, 1);
70 }
71
72 if (config->mux_sel_gpio != -1) {
73 ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL");
74 if (ret) {
75 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
76 "HDMI_MUX_SEL", config->mux_sel_gpio, ret);
77 goto error5;
78 }
79 gpio_set_value_cansleep(config->mux_sel_gpio, 0);
63 } 80 }
64 DBG("gpio on"); 81 DBG("gpio on");
65 } else { 82 } else {
@@ -67,15 +84,23 @@ static int gpio_config(struct hdmi *hdmi, bool on)
67 gpio_free(config->ddc_data_gpio); 84 gpio_free(config->ddc_data_gpio);
68 gpio_free(config->hpd_gpio); 85 gpio_free(config->hpd_gpio);
69 86
70 if (config->pmic_gpio != -1) { 87 if (config->mux_en_gpio != -1) {
71 gpio_set_value_cansleep(config->pmic_gpio, 1); 88 gpio_set_value_cansleep(config->mux_en_gpio, 0);
72 gpio_free(config->pmic_gpio); 89 gpio_free(config->mux_en_gpio);
90 }
91
92 if (config->mux_sel_gpio != -1) {
93 gpio_set_value_cansleep(config->mux_sel_gpio, 1);
94 gpio_free(config->mux_sel_gpio);
73 } 95 }
74 DBG("gpio off"); 96 DBG("gpio off");
75 } 97 }
76 98
77 return 0; 99 return 0;
78 100
101error5:
102 if (config->mux_en_gpio != -1)
103 gpio_free(config->mux_en_gpio);
79error4: 104error4:
80 gpio_free(config->hpd_gpio); 105 gpio_free(config->hpd_gpio);
81error3: 106error3:
@@ -89,10 +114,11 @@ error1:
89static int hpd_enable(struct hdmi_connector *hdmi_connector) 114static int hpd_enable(struct hdmi_connector *hdmi_connector)
90{ 115{
91 struct hdmi *hdmi = hdmi_connector->hdmi; 116 struct hdmi *hdmi = hdmi_connector->hdmi;
117 const struct hdmi_platform_config *config = hdmi->config;
92 struct drm_device *dev = hdmi_connector->base.dev; 118 struct drm_device *dev = hdmi_connector->base.dev;
93 struct hdmi_phy *phy = hdmi->phy; 119 struct hdmi_phy *phy = hdmi->phy;
94 uint32_t hpd_ctrl; 120 uint32_t hpd_ctrl;
95 int ret; 121 int i, ret;
96 122
97 ret = gpio_config(hdmi, true); 123 ret = gpio_config(hdmi, true);
98 if (ret) { 124 if (ret) {
@@ -100,31 +126,22 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
100 goto fail; 126 goto fail;
101 } 127 }
102 128
103 ret = clk_prepare_enable(hdmi->clk); 129 for (i = 0; i < config->hpd_clk_cnt; i++) {
104 if (ret) { 130 ret = clk_prepare_enable(hdmi->hpd_clks[i]);
105 dev_err(dev->dev, "failed to enable 'clk': %d\n", ret); 131 if (ret) {
106 goto fail; 132 dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n",
107 } 133 config->hpd_clk_names[i], ret);
108 134 goto fail;
109 ret = clk_prepare_enable(hdmi->m_pclk); 135 }
110 if (ret) {
111 dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
112 goto fail;
113 }
114
115 ret = clk_prepare_enable(hdmi->s_pclk);
116 if (ret) {
117 dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
118 goto fail;
119 } 136 }
120 137
121 if (hdmi->mpp0) 138 for (i = 0; i < config->hpd_reg_cnt; i++) {
122 ret = regulator_enable(hdmi->mpp0); 139 ret = regulator_enable(hdmi->hpd_regs[i]);
123 if (!ret) 140 if (ret) {
124 ret = regulator_enable(hdmi->mvs); 141 dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
125 if (ret) { 142 config->hpd_reg_names[i], ret);
126 dev_err(dev->dev, "failed to enable regulators: %d\n", ret); 143 goto fail;
127 goto fail; 144 }
128 } 145 }
129 146
130 hdmi_set_mode(hdmi, false); 147 hdmi_set_mode(hdmi, false);
@@ -157,26 +174,26 @@ fail:
157static int hdp_disable(struct hdmi_connector *hdmi_connector) 174static int hdp_disable(struct hdmi_connector *hdmi_connector)
158{ 175{
159 struct hdmi *hdmi = hdmi_connector->hdmi; 176 struct hdmi *hdmi = hdmi_connector->hdmi;
177 const struct hdmi_platform_config *config = hdmi->config;
160 struct drm_device *dev = hdmi_connector->base.dev; 178 struct drm_device *dev = hdmi_connector->base.dev;
161 int ret = 0; 179 int i, ret = 0;
162 180
163 /* Disable HPD interrupt */ 181 /* Disable HPD interrupt */
164 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); 182 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
165 183
166 hdmi_set_mode(hdmi, false); 184 hdmi_set_mode(hdmi, false);
167 185
168 if (hdmi->mpp0) 186 for (i = 0; i < config->hpd_reg_cnt; i++) {
169 ret = regulator_disable(hdmi->mpp0); 187 ret = regulator_disable(hdmi->hpd_regs[i]);
170 if (!ret) 188 if (ret) {
171 ret = regulator_disable(hdmi->mvs); 189 dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
172 if (ret) { 190 config->hpd_reg_names[i], ret);
173 dev_err(dev->dev, "failed to enable regulators: %d\n", ret); 191 goto fail;
174 goto fail; 192 }
175 } 193 }
176 194
177 clk_disable_unprepare(hdmi->clk); 195 for (i = 0; i < config->hpd_clk_cnt; i++)
178 clk_disable_unprepare(hdmi->m_pclk); 196 clk_disable_unprepare(hdmi->hpd_clks[i]);
179 clk_disable_unprepare(hdmi->s_pclk);
180 197
181 ret = gpio_config(hdmi, false); 198 ret = gpio_config(hdmi, false);
182 if (ret) { 199 if (ret) {
@@ -190,9 +207,19 @@ fail:
190 return ret; 207 return ret;
191} 208}
192 209
210static void
211hotplug_work(struct work_struct *work)
212{
213 struct hdmi_connector *hdmi_connector =
214 container_of(work, struct hdmi_connector, hpd_work);
215 struct drm_connector *connector = &hdmi_connector->base;
216 drm_helper_hpd_irq_event(connector->dev);
217}
218
193void hdmi_connector_irq(struct drm_connector *connector) 219void hdmi_connector_irq(struct drm_connector *connector)
194{ 220{
195 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); 221 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
222 struct msm_drm_private *priv = connector->dev->dev_private;
196 struct hdmi *hdmi = hdmi_connector->hdmi; 223 struct hdmi *hdmi = hdmi_connector->hdmi;
197 uint32_t hpd_int_status, hpd_int_ctrl; 224 uint32_t hpd_int_status, hpd_int_ctrl;
198 225
@@ -210,13 +237,13 @@ void hdmi_connector_irq(struct drm_connector *connector)
210 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 237 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
211 hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); 238 hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
212 239
213 drm_helper_hpd_irq_event(connector->dev);
214
215 /* detect disconnect if we are connected or visa versa: */ 240 /* detect disconnect if we are connected or visa versa: */
216 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; 241 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
217 if (!detected) 242 if (!detected)
218 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; 243 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
219 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); 244 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
245
246 queue_work(priv->wq, &hdmi_connector->hpd_work);
220 } 247 }
221} 248}
222 249
@@ -225,6 +252,7 @@ static enum drm_connector_status hdmi_connector_detect(
225{ 252{
226 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); 253 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
227 struct hdmi *hdmi = hdmi_connector->hdmi; 254 struct hdmi *hdmi = hdmi_connector->hdmi;
255 const struct hdmi_platform_config *config = hdmi->config;
228 uint32_t hpd_int_status; 256 uint32_t hpd_int_status;
229 int retry = 20; 257 int retry = 20;
230 258
@@ -234,6 +262,14 @@ static enum drm_connector_status hdmi_connector_detect(
234 * let that trick us into thinking the monitor is gone: 262 * let that trick us into thinking the monitor is gone:
235 */ 263 */
236 while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) { 264 while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
265 /* hdmi debounce logic seems to get stuck sometimes,
266 * read directly the gpio to get a second opinion:
267 */
268 if (gpio_get_value(config->hpd_gpio)) {
269 DBG("gpio tells us we are connected!");
270 hpd_int_status |= HDMI_HPD_INT_STATUS_CABLE_DETECTED;
271 break;
272 }
237 mdelay(10); 273 mdelay(10);
238 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 274 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
239 DBG("status=%08x", hpd_int_status); 275 DBG("status=%08x", hpd_int_status);
@@ -286,6 +322,8 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
286 struct drm_display_mode *mode) 322 struct drm_display_mode *mode)
287{ 323{
288 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); 324 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
325 struct hdmi *hdmi = hdmi_connector->hdmi;
326 const struct hdmi_platform_config *config = hdmi->config;
289 struct msm_drm_private *priv = connector->dev->dev_private; 327 struct msm_drm_private *priv = connector->dev->dev_private;
290 struct msm_kms *kms = priv->kms; 328 struct msm_kms *kms = priv->kms;
291 long actual, requested; 329 long actual, requested;
@@ -294,6 +332,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
294 actual = kms->funcs->round_pixclk(kms, 332 actual = kms->funcs->round_pixclk(kms,
295 requested, hdmi_connector->hdmi->encoder); 333 requested, hdmi_connector->hdmi->encoder);
296 334
335 /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
336 * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
337 * instead):
338 */
339 if (config->pwr_clk_cnt > 0)
340 actual = clk_round_rate(hdmi->pwr_clks[0], actual);
341
297 DBG("requested=%ld, actual=%ld", requested, actual); 342 DBG("requested=%ld, actual=%ld", requested, actual);
298 343
299 if (actual != requested) 344 if (actual != requested)
@@ -336,6 +381,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
336 } 381 }
337 382
338 hdmi_connector->hdmi = hdmi_reference(hdmi); 383 hdmi_connector->hdmi = hdmi_reference(hdmi);
384 INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
339 385
340 connector = &hdmi_connector->base; 386 connector = &hdmi_connector->base;
341 387
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
new file mode 100644
index 000000000000..59fa6cdacb2a
--- /dev/null
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
@@ -0,0 +1,157 @@
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
20struct hdmi_phy_8x74 {
21 struct hdmi_phy base;
22 struct hdmi *hdmi;
23 void __iomem *mmio;
24};
25#define to_hdmi_phy_8x74(x) container_of(x, struct hdmi_phy_8x74, base)
26
27
28static void phy_write(struct hdmi_phy_8x74 *phy, u32 reg, u32 data)
29{
30 msm_writel(data, phy->mmio + reg);
31}
32
33//static u32 phy_read(struct hdmi_phy_8x74 *phy, u32 reg)
34//{
35// return msm_readl(phy->mmio + reg);
36//}
37
38static void hdmi_phy_8x74_destroy(struct hdmi_phy *phy)
39{
40 struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
41 kfree(phy_8x74);
42}
43
44static void hdmi_phy_8x74_reset(struct hdmi_phy *phy)
45{
46 struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
47 struct hdmi *hdmi = phy_8x74->hdmi;
48 unsigned int val;
49
50 /* NOTE that HDMI_PHY_CTL is in core mmio, not phy mmio: */
51
52 val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
53
54 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
55 /* pull low */
56 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
57 val & ~HDMI_PHY_CTRL_SW_RESET);
58 } else {
59 /* pull high */
60 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
61 val | HDMI_PHY_CTRL_SW_RESET);
62 }
63
64 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
65 /* pull low */
66 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
67 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
68 } else {
69 /* pull high */
70 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
71 val | HDMI_PHY_CTRL_SW_RESET_PLL);
72 }
73
74 msleep(100);
75
76 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
77 /* pull high */
78 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
79 val | HDMI_PHY_CTRL_SW_RESET);
80 } else {
81 /* pull low */
82 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
83 val & ~HDMI_PHY_CTRL_SW_RESET);
84 }
85
86 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
87 /* pull high */
88 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
89 val | HDMI_PHY_CTRL_SW_RESET_PLL);
90 } else {
91 /* pull low */
92 hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
93 val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
94 }
95}
96
97static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy,
98 unsigned long int pixclock)
99{
100 struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
101
102 phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG0, 0x1b);
103 phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG1, 0xf2);
104 phy_write(phy_8x74, REG_HDMI_8x74_BIST_CFG0, 0x0);
105 phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN0, 0x0);
106 phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN1, 0x0);
107 phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN2, 0x0);
108 phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN3, 0x0);
109 phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL1, 0x20);
110}
111
112static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy)
113{
114 struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
115 phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL0, 0x7f);
116}
117
118static const struct hdmi_phy_funcs hdmi_phy_8x74_funcs = {
119 .destroy = hdmi_phy_8x74_destroy,
120 .reset = hdmi_phy_8x74_reset,
121 .powerup = hdmi_phy_8x74_powerup,
122 .powerdown = hdmi_phy_8x74_powerdown,
123};
124
125struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi)
126{
127 struct hdmi_phy_8x74 *phy_8x74;
128 struct hdmi_phy *phy = NULL;
129 int ret;
130
131 phy_8x74 = kzalloc(sizeof(*phy_8x74), GFP_KERNEL);
132 if (!phy_8x74) {
133 ret = -ENOMEM;
134 goto fail;
135 }
136
137 phy = &phy_8x74->base;
138
139 phy->funcs = &hdmi_phy_8x74_funcs;
140
141 phy_8x74->hdmi = hdmi;
142
143 /* for 8x74, the phy mmio is mapped separately: */
144 phy_8x74->mmio = msm_ioremap(hdmi->pdev,
145 "phy_physical", "HDMI_8x74");
146 if (IS_ERR(phy_8x74->mmio)) {
147 ret = PTR_ERR(phy_8x74->mmio);
148 goto fail;
149 }
150
151 return phy;
152
153fail:
154 if (phy)
155 hdmi_phy_8x74_destroy(phy);
156 return ERR_PTR(ret);
157}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index 4d1cc2ea700e..272e707c9487 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -39,7 +39,7 @@ static int mdp4_hw_init(struct msm_kms *kms)
39 major = FIELD(version, MDP4_VERSION_MAJOR); 39 major = FIELD(version, MDP4_VERSION_MAJOR);
40 minor = FIELD(version, MDP4_VERSION_MINOR); 40 minor = FIELD(version, MDP4_VERSION_MINOR);
41 41
42 DBG("found MDP version v%d.%d", major, minor); 42 DBG("found MDP4 version v%d.%d", major, minor);
43 43
44 if (major != 4) { 44 if (major != 4) {
45 dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", 45 dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
@@ -195,6 +195,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
195 struct drm_plane *plane; 195 struct drm_plane *plane;
196 struct drm_crtc *crtc; 196 struct drm_crtc *crtc;
197 struct drm_encoder *encoder; 197 struct drm_encoder *encoder;
198 struct hdmi *hdmi;
198 int ret; 199 int ret;
199 200
200 /* 201 /*
@@ -244,9 +245,10 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
244 encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */ 245 encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */
245 priv->encoders[priv->num_encoders++] = encoder; 246 priv->encoders[priv->num_encoders++] = encoder;
246 247
247 ret = hdmi_init(dev, encoder); 248 hdmi = hdmi_init(dev, encoder);
248 if (ret) { 249 if (IS_ERR(hdmi)) {
249 dev_err(dev->dev, "failed to initialize HDMI\n"); 250 ret = PTR_ERR(hdmi);
251 dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
250 goto fail; 252 goto fail;
251 } 253 }
252 254
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index aa78bede1446..3d63269c5b29 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -190,7 +190,9 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
190 190
191struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); 191struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
192 192
193int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder); 193struct hdmi;
194struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
195irqreturn_t hdmi_irq(int irq, void *dev_id);
194void __init hdmi_register(void); 196void __init hdmi_register(void);
195void __exit hdmi_unregister(void); 197void __exit hdmi_unregister(void);
196 198