aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/hdmi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/hdmi')
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c201
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h38
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.xml.h83
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c71
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c139
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c157
-rw-r--r--drivers/gpu/drm/msm/hdmi/qfprom.xml.h8
7 files changed, 583 insertions, 114 deletions
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 50d11df35b21..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, "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;
233 } else if (cpu_is_msm8960()) { 308 config.mux_sel_gpio = 13 + NR_GPIO_IRQS;
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.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
index 4e939f82918c..e2636582cfd7 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
8git clone https://github.com/freedreno/envytools.git 8git clone https://github.com/freedreno/envytools.git
9 9
10The rules-ng-ng source files this header was generated from are: 10The rules-ng-ng source files this header was generated from are:
11- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) 11- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
12- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) 12- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
13- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) 13- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31)
14- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
15- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13)
14- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) 16- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
15- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) 17- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
16- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) 18- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05)
17- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) 19- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
18- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) 20- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04)
19 21
20Copyright (C) 2013 by the following authors: 22Copyright (C) 2013 by the following authors:
21- Rob Clark <robdclark@gmail.com> (robclark) 23- Rob Clark <robdclark@gmail.com> (robclark)
@@ -212,6 +214,20 @@ static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state
212#define REG_HDMI_HDCP_RESET 0x00000130 214#define REG_HDMI_HDCP_RESET 0x00000130
213#define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE 0x00000001 215#define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE 0x00000001
214 216
217#define REG_HDMI_VENSPEC_INFO0 0x0000016c
218
219#define REG_HDMI_VENSPEC_INFO1 0x00000170
220
221#define REG_HDMI_VENSPEC_INFO2 0x00000174
222
223#define REG_HDMI_VENSPEC_INFO3 0x00000178
224
225#define REG_HDMI_VENSPEC_INFO4 0x0000017c
226
227#define REG_HDMI_VENSPEC_INFO5 0x00000180
228
229#define REG_HDMI_VENSPEC_INFO6 0x00000184
230
215#define REG_HDMI_AUDIO_CFG 0x000001d0 231#define REG_HDMI_AUDIO_CFG 0x000001d0
216#define HDMI_AUDIO_CFG_ENGINE_ENABLE 0x00000001 232#define HDMI_AUDIO_CFG_ENGINE_ENABLE 0x00000001
217#define HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK 0x000000f0 233#define HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK 0x000000f0
@@ -235,6 +251,9 @@ static inline uint32_t HDMI_DDC_CTRL_TRANSACTION_CNT(uint32_t val)
235 return ((val) << HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT) & HDMI_DDC_CTRL_TRANSACTION_CNT__MASK; 251 return ((val) << HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT) & HDMI_DDC_CTRL_TRANSACTION_CNT__MASK;
236} 252}
237 253
254#define REG_HDMI_DDC_ARBITRATION 0x00000210
255#define HDMI_DDC_ARBITRATION_HW_ARBITRATION 0x00000010
256
238#define REG_HDMI_DDC_INT_CTRL 0x00000214 257#define REG_HDMI_DDC_INT_CTRL 0x00000214
239#define HDMI_DDC_INT_CTRL_SW_DONE_INT 0x00000001 258#define HDMI_DDC_INT_CTRL_SW_DONE_INT 0x00000001
240#define HDMI_DDC_INT_CTRL_SW_DONE_ACK 0x00000002 259#define HDMI_DDC_INT_CTRL_SW_DONE_ACK 0x00000002
@@ -340,6 +359,20 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
340 return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK; 359 return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK;
341} 360}
342 361
362#define REG_HDMI_CEC_STATUS 0x00000298
363
364#define REG_HDMI_CEC_INT 0x0000029c
365
366#define REG_HDMI_CEC_ADDR 0x000002a0
367
368#define REG_HDMI_CEC_TIME 0x000002a4
369
370#define REG_HDMI_CEC_REFTIMER 0x000002a8
371
372#define REG_HDMI_CEC_RD_DATA 0x000002ac
373
374#define REG_HDMI_CEC_RD_FILTER 0x000002b0
375
343#define REG_HDMI_ACTIVE_HSYNC 0x000002b4 376#define REG_HDMI_ACTIVE_HSYNC 0x000002b4
344#define HDMI_ACTIVE_HSYNC_START__MASK 0x00000fff 377#define HDMI_ACTIVE_HSYNC_START__MASK 0x00000fff
345#define HDMI_ACTIVE_HSYNC_START__SHIFT 0 378#define HDMI_ACTIVE_HSYNC_START__SHIFT 0
@@ -410,17 +443,33 @@ static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val)
410#define HDMI_FRAME_CTRL_HSYNC_LOW 0x20000000 443#define HDMI_FRAME_CTRL_HSYNC_LOW 0x20000000
411#define HDMI_FRAME_CTRL_INTERLACED_EN 0x80000000 444#define HDMI_FRAME_CTRL_INTERLACED_EN 0x80000000
412 445
446#define REG_HDMI_AUD_INT 0x000002cc
447#define HDMI_AUD_INT_AUD_FIFO_URUN_INT 0x00000001
448#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK 0x00000002
449#define HDMI_AUD_INT_AUD_SAM_DROP_INT 0x00000004
450#define HDMI_AUD_INT_AUD_SAM_DROP_MASK 0x00000008
451
413#define REG_HDMI_PHY_CTRL 0x000002d4 452#define REG_HDMI_PHY_CTRL 0x000002d4
414#define HDMI_PHY_CTRL_SW_RESET_PLL 0x00000001 453#define HDMI_PHY_CTRL_SW_RESET_PLL 0x00000001
415#define HDMI_PHY_CTRL_SW_RESET_PLL_LOW 0x00000002 454#define HDMI_PHY_CTRL_SW_RESET_PLL_LOW 0x00000002
416#define HDMI_PHY_CTRL_SW_RESET 0x00000004 455#define HDMI_PHY_CTRL_SW_RESET 0x00000004
417#define HDMI_PHY_CTRL_SW_RESET_LOW 0x00000008 456#define HDMI_PHY_CTRL_SW_RESET_LOW 0x00000008
418 457
419#define REG_HDMI_AUD_INT 0x000002cc 458#define REG_HDMI_CEC_WR_RANGE 0x000002dc
420#define HDMI_AUD_INT_AUD_FIFO_URUN_INT 0x00000001 459
421#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK 0x00000002 460#define REG_HDMI_CEC_RD_RANGE 0x000002e0
422#define HDMI_AUD_INT_AUD_SAM_DROP_INT 0x00000004 461
423#define HDMI_AUD_INT_AUD_SAM_DROP_MASK 0x00000008 462#define REG_HDMI_VERSION 0x000002e4
463
464#define REG_HDMI_CEC_COMPL_CTL 0x00000360
465
466#define REG_HDMI_CEC_RD_START_RANGE 0x00000364
467
468#define REG_HDMI_CEC_RD_TOTAL_RANGE 0x00000368
469
470#define REG_HDMI_CEC_RD_ERR_RESP_LO 0x0000036c
471
472#define REG_HDMI_CEC_WR_CHECK_CONFIG 0x00000370
424 473
425#define REG_HDMI_8x60_PHY_REG0 0x00000300 474#define REG_HDMI_8x60_PHY_REG0 0x00000300
426#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c 475#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c
@@ -504,5 +553,23 @@ static inline uint32_t HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(uint32_t val)
504 553
505#define REG_HDMI_8960_PHY_REG12 0x00000430 554#define REG_HDMI_8960_PHY_REG12 0x00000430
506 555
556#define REG_HDMI_8x74_ANA_CFG0 0x00000000
557
558#define REG_HDMI_8x74_ANA_CFG1 0x00000004
559
560#define REG_HDMI_8x74_PD_CTRL0 0x00000010
561
562#define REG_HDMI_8x74_PD_CTRL1 0x00000014
563
564#define REG_HDMI_8x74_BIST_CFG0 0x00000034
565
566#define REG_HDMI_8x74_BIST_PATN0 0x0000003c
567
568#define REG_HDMI_8x74_BIST_PATN1 0x00000040
569
570#define REG_HDMI_8x74_BIST_PATN2 0x00000044
571
572#define REG_HDMI_8x74_BIST_PATN3 0x00000048
573
507 574
508#endif /* HDMI_XML */ 575#endif /* HDMI_XML */
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 823eee521a31..7dedfdd12075 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -17,19 +17,20 @@
17 17
18#include <linux/gpio.h> 18#include <linux/gpio.h>
19 19
20#include "msm_kms.h"
20#include "hdmi.h" 21#include "hdmi.h"
21 22
22struct hdmi_connector { 23struct hdmi_connector {
23 struct drm_connector base; 24 struct drm_connector base;
24 struct hdmi *hdmi; 25 struct hdmi *hdmi;
26 struct work_struct hpd_work;
25}; 27};
26#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)
27 29
28static int gpio_config(struct hdmi *hdmi, bool on) 30static int gpio_config(struct hdmi *hdmi, bool on)
29{ 31{
30 struct drm_device *dev = hdmi->dev; 32 struct drm_device *dev = hdmi->dev;
31 struct hdmi_platform_config *config = 33 const struct hdmi_platform_config *config = hdmi->config;
32 hdmi->pdev->dev.platform_data;
33 int ret; 34 int ret;
34 35
35 if (on) { 36 if (on) {
@@ -39,26 +40,43 @@ static int gpio_config(struct hdmi *hdmi, bool on)
39 "HDMI_DDC_CLK", config->ddc_clk_gpio, ret); 40 "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
40 goto error1; 41 goto error1;
41 } 42 }
43 gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
44
42 ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA"); 45 ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
43 if (ret) { 46 if (ret) {
44 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 47 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
45 "HDMI_DDC_DATA", config->ddc_data_gpio, ret); 48 "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
46 goto error2; 49 goto error2;
47 } 50 }
51 gpio_set_value_cansleep(config->ddc_data_gpio, 1);
52
48 ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); 53 ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
49 if (ret) { 54 if (ret) {
50 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 55 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
51 "HDMI_HPD", config->hpd_gpio, ret); 56 "HDMI_HPD", config->hpd_gpio, ret);
52 goto error3; 57 goto error3;
53 } 58 }
54 if (config->pmic_gpio != -1) { 59 gpio_direction_input(config->hpd_gpio);
55 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");
56 if (ret) { 64 if (ret) {
57 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", 65 dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
58 "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret); 66 "HDMI_MUX_SEL", config->mux_en_gpio, ret);
59 goto error4; 67 goto error4;
60 } 68 }
61 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);
62 } 80 }
63 DBG("gpio on"); 81 DBG("gpio on");
64 } else { 82 } else {
@@ -66,15 +84,23 @@ static int gpio_config(struct hdmi *hdmi, bool on)
66 gpio_free(config->ddc_data_gpio); 84 gpio_free(config->ddc_data_gpio);
67 gpio_free(config->hpd_gpio); 85 gpio_free(config->hpd_gpio);
68 86
69 if (config->pmic_gpio != -1) { 87 if (config->mux_en_gpio != -1) {
70 gpio_set_value_cansleep(config->pmic_gpio, 1); 88 gpio_set_value_cansleep(config->mux_en_gpio, 0);
71 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);
72 } 95 }
73 DBG("gpio off"); 96 DBG("gpio off");
74 } 97 }
75 98
76 return 0; 99 return 0;
77 100
101error5:
102 if (config->mux_en_gpio != -1)
103 gpio_free(config->mux_en_gpio);
78error4: 104error4:
79 gpio_free(config->hpd_gpio); 105 gpio_free(config->hpd_gpio);
80error3: 106error3:
@@ -88,10 +114,11 @@ error1:
88static int hpd_enable(struct hdmi_connector *hdmi_connector) 114static int hpd_enable(struct hdmi_connector *hdmi_connector)
89{ 115{
90 struct hdmi *hdmi = hdmi_connector->hdmi; 116 struct hdmi *hdmi = hdmi_connector->hdmi;
117 const struct hdmi_platform_config *config = hdmi->config;
91 struct drm_device *dev = hdmi_connector->base.dev; 118 struct drm_device *dev = hdmi_connector->base.dev;
92 struct hdmi_phy *phy = hdmi->phy; 119 struct hdmi_phy *phy = hdmi->phy;
93 uint32_t hpd_ctrl; 120 uint32_t hpd_ctrl;
94 int ret; 121 int i, ret;
95 122
96 ret = gpio_config(hdmi, true); 123 ret = gpio_config(hdmi, true);
97 if (ret) { 124 if (ret) {
@@ -99,31 +126,22 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
99 goto fail; 126 goto fail;
100 } 127 }
101 128
102 ret = clk_prepare_enable(hdmi->clk); 129 for (i = 0; i < config->hpd_clk_cnt; i++) {
103 if (ret) { 130 ret = clk_prepare_enable(hdmi->hpd_clks[i]);
104 dev_err(dev->dev, "failed to enable 'clk': %d\n", ret); 131 if (ret) {
105 goto fail; 132 dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n",
106 } 133 config->hpd_clk_names[i], ret);
107 134 goto fail;
108 ret = clk_prepare_enable(hdmi->m_pclk); 135 }
109 if (ret) {
110 dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
111 goto fail;
112 }
113
114 ret = clk_prepare_enable(hdmi->s_pclk);
115 if (ret) {
116 dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
117 goto fail;
118 } 136 }
119 137
120 if (hdmi->mpp0) 138 for (i = 0; i < config->hpd_reg_cnt; i++) {
121 ret = regulator_enable(hdmi->mpp0); 139 ret = regulator_enable(hdmi->hpd_regs[i]);
122 if (!ret) 140 if (ret) {
123 ret = regulator_enable(hdmi->mvs); 141 dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
124 if (ret) { 142 config->hpd_reg_names[i], ret);
125 dev_err(dev->dev, "failed to enable regulators: %d\n", ret); 143 goto fail;
126 goto fail; 144 }
127 } 145 }
128 146
129 hdmi_set_mode(hdmi, false); 147 hdmi_set_mode(hdmi, false);
@@ -156,26 +174,26 @@ fail:
156static int hdp_disable(struct hdmi_connector *hdmi_connector) 174static int hdp_disable(struct hdmi_connector *hdmi_connector)
157{ 175{
158 struct hdmi *hdmi = hdmi_connector->hdmi; 176 struct hdmi *hdmi = hdmi_connector->hdmi;
177 const struct hdmi_platform_config *config = hdmi->config;
159 struct drm_device *dev = hdmi_connector->base.dev; 178 struct drm_device *dev = hdmi_connector->base.dev;
160 int ret = 0; 179 int i, ret = 0;
161 180
162 /* Disable HPD interrupt */ 181 /* Disable HPD interrupt */
163 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); 182 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
164 183
165 hdmi_set_mode(hdmi, false); 184 hdmi_set_mode(hdmi, false);
166 185
167 if (hdmi->mpp0) 186 for (i = 0; i < config->hpd_reg_cnt; i++) {
168 ret = regulator_disable(hdmi->mpp0); 187 ret = regulator_disable(hdmi->hpd_regs[i]);
169 if (!ret) 188 if (ret) {
170 ret = regulator_disable(hdmi->mvs); 189 dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
171 if (ret) { 190 config->hpd_reg_names[i], ret);
172 dev_err(dev->dev, "failed to enable regulators: %d\n", ret); 191 goto fail;
173 goto fail; 192 }
174 } 193 }
175 194
176 clk_disable_unprepare(hdmi->clk); 195 for (i = 0; i < config->hpd_clk_cnt; i++)
177 clk_disable_unprepare(hdmi->m_pclk); 196 clk_disable_unprepare(hdmi->hpd_clks[i]);
178 clk_disable_unprepare(hdmi->s_pclk);
179 197
180 ret = gpio_config(hdmi, false); 198 ret = gpio_config(hdmi, false);
181 if (ret) { 199 if (ret) {
@@ -189,9 +207,19 @@ fail:
189 return ret; 207 return ret;
190} 208}
191 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
192void hdmi_connector_irq(struct drm_connector *connector) 219void hdmi_connector_irq(struct drm_connector *connector)
193{ 220{
194 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;
195 struct hdmi *hdmi = hdmi_connector->hdmi; 223 struct hdmi *hdmi = hdmi_connector->hdmi;
196 uint32_t hpd_int_status, hpd_int_ctrl; 224 uint32_t hpd_int_status, hpd_int_ctrl;
197 225
@@ -209,13 +237,13 @@ void hdmi_connector_irq(struct drm_connector *connector)
209 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 237 hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
210 hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); 238 hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
211 239
212 drm_helper_hpd_irq_event(connector->dev);
213
214 /* detect disconnect if we are connected or visa versa: */ 240 /* detect disconnect if we are connected or visa versa: */
215 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; 241 hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
216 if (!detected) 242 if (!detected)
217 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; 243 hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
218 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);
219 } 247 }
220} 248}
221 249
@@ -224,6 +252,7 @@ static enum drm_connector_status hdmi_connector_detect(
224{ 252{
225 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); 253 struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
226 struct hdmi *hdmi = hdmi_connector->hdmi; 254 struct hdmi *hdmi = hdmi_connector->hdmi;
255 const struct hdmi_platform_config *config = hdmi->config;
227 uint32_t hpd_int_status; 256 uint32_t hpd_int_status;
228 int retry = 20; 257 int retry = 20;
229 258
@@ -233,6 +262,14 @@ static enum drm_connector_status hdmi_connector_detect(
233 * let that trick us into thinking the monitor is gone: 262 * let that trick us into thinking the monitor is gone:
234 */ 263 */
235 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 }
236 mdelay(10); 273 mdelay(10);
237 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); 274 hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
238 DBG("status=%08x", hpd_int_status); 275 DBG("status=%08x", hpd_int_status);
@@ -285,6 +322,8 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
285 struct drm_display_mode *mode) 322 struct drm_display_mode *mode)
286{ 323{
287 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;
288 struct msm_drm_private *priv = connector->dev->dev_private; 327 struct msm_drm_private *priv = connector->dev->dev_private;
289 struct msm_kms *kms = priv->kms; 328 struct msm_kms *kms = priv->kms;
290 long actual, requested; 329 long actual, requested;
@@ -293,6 +332,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
293 actual = kms->funcs->round_pixclk(kms, 332 actual = kms->funcs->round_pixclk(kms,
294 requested, hdmi_connector->hdmi->encoder); 333 requested, hdmi_connector->hdmi->encoder);
295 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
296 DBG("requested=%ld, actual=%ld", requested, actual); 342 DBG("requested=%ld, actual=%ld", requested, actual);
297 343
298 if (actual != requested) 344 if (actual != requested)
@@ -335,6 +381,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
335 } 381 }
336 382
337 hdmi_connector->hdmi = hdmi_reference(hdmi); 383 hdmi_connector->hdmi = hdmi_reference(hdmi);
384 INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
338 385
339 connector = &hdmi_connector->base; 386 connector = &hdmi_connector->base;
340 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/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
index dbde4f6339b9..d591567173c4 100644
--- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
8git clone https://github.com/freedreno/envytools.git 8git clone https://github.com/freedreno/envytools.git
9 9
10The rules-ng-ng source files this header was generated from are: 10The rules-ng-ng source files this header was generated from are:
11- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) 11- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
12- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) 12- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
13- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) 13- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31)
14- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
15- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13)
14- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) 16- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
15- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) 17- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
16- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) 18- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05)
17- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) 19- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
18- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) 20- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04)
19 21
20Copyright (C) 2013 by the following authors: 22Copyright (C) 2013 by the following authors:
21- Rob Clark <robdclark@gmail.com> (robclark) 23- Rob Clark <robdclark@gmail.com> (robclark)