diff options
Diffstat (limited to 'drivers/gpu/drm/msm/hdmi/hdmi.c')
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.c | 201 |
1 files changed, 151 insertions, 50 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 | ||
44 | static irqreturn_t hdmi_irq(int irq, void *dev_id) | 44 | irqreturn_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 */ |
74 | int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) | 74 | struct 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 | ||
204 | fail: | 233 | fail: |
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 | |||
221 | static int hdmi_dev_probe(struct platform_device *pdev) | 252 | static 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 | ||
350 | static const struct of_device_id dt_match[] = { | ||
351 | { .compatible = "qcom,hdmi-tx" }, | ||
352 | {} | ||
353 | }; | ||
354 | MODULE_DEVICE_TABLE(of, dt_match); | ||
355 | |||
258 | static struct platform_driver hdmi_driver = { | 356 | static 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 | ||
264 | void __init hdmi_register(void) | 365 | void __init hdmi_register(void) |