1 /* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "hdmi.h" 19 20 void hdmi_set_mode(struct hdmi *hdmi, bool power_on) 21 { 22 uint32_t ctrl = 0; 23 24 if (power_on) { 25 ctrl |= HDMI_CTRL_ENABLE; 26 if (!hdmi->hdmi_mode) { 27 ctrl |= HDMI_CTRL_HDMI; 28 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 29 ctrl &= ~HDMI_CTRL_HDMI; 30 } else { 31 ctrl |= HDMI_CTRL_HDMI; 32 } 33 } else { 34 ctrl = HDMI_CTRL_HDMI; 35 } 36 37 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 38 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", 39 power_on ? "Enable" : "Disable", ctrl); 40 } 41 42 irqreturn_t hdmi_irq(int irq, void *dev_id) 43 { 44 struct hdmi *hdmi = dev_id; 45 46 /* Process HPD: */ 47 hdmi_connector_irq(hdmi->connector); 48 49 /* Process DDC: */ 50 hdmi_i2c_irq(hdmi->i2c); 51 52 /* TODO audio.. */ 53 54 return IRQ_HANDLED; 55 } 56 57 void hdmi_destroy(struct kref *kref) 58 { 59 struct hdmi *hdmi = container_of(kref, struct hdmi, refcount); 60 struct hdmi_phy *phy = hdmi->phy; 61 62 if (phy) 63 phy->funcs->destroy(phy); 64 65 if (hdmi->i2c) 66 hdmi_i2c_destroy(hdmi->i2c); 67 68 platform_set_drvdata(hdmi->pdev, NULL); 69 } 70 71 /* initialize connector */ 72 struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) 73 { 74 struct hdmi *hdmi = NULL; 75 struct msm_drm_private *priv = dev->dev_private; 76 struct platform_device *pdev = priv->hdmi_pdev; 77 struct hdmi_platform_config *config; 78 int i, ret; 79 80 if (!pdev) { 81 dev_err(dev->dev, "no hdmi device\n"); 82 ret = -ENXIO; 83 goto fail; 84 } 85 86 config = pdev->dev.platform_data; 87 88 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); 89 if (!hdmi) { 90 ret = -ENOMEM; 91 goto fail; 92 } 93 94 kref_init(&hdmi->refcount); 95 96 hdmi->dev = dev; 97 hdmi->pdev = pdev; 98 hdmi->config = config; 99 hdmi->encoder = encoder; 100 101 hdmi_audio_infoframe_init(&hdmi->audio.infoframe); 102 103 /* not sure about which phy maps to which msm.. probably I miss some */ 104 if (config->phy_init) 105 hdmi->phy = config->phy_init(hdmi); 106 else 107 hdmi->phy = ERR_PTR(-ENXIO); 108 109 if (IS_ERR(hdmi->phy)) { 110 ret = PTR_ERR(hdmi->phy); 111 dev_err(dev->dev, "failed to load phy: %d\n", ret); 112 hdmi->phy = NULL; 113 goto fail; 114 } 115 116 hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); 117 if (IS_ERR(hdmi->mmio)) { 118 ret = PTR_ERR(hdmi->mmio); 119 goto fail; 120 } 121 122 BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); 123 for (i = 0; i < config->hpd_reg_cnt; i++) { 124 struct regulator *reg; 125 126 reg = devm_regulator_get_exclusive(&pdev->dev, 127 config->hpd_reg_names[i]); 128 if (IS_ERR(reg)) { 129 ret = PTR_ERR(reg); 130 dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", 131 config->hpd_reg_names[i], ret); 132 goto fail; 133 } 134 135 hdmi->hpd_regs[i] = reg; 136 } 137 138 BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); 139 for (i = 0; i < config->pwr_reg_cnt; i++) { 140 struct regulator *reg; 141 142 reg = devm_regulator_get_exclusive(&pdev->dev, 143 config->pwr_reg_names[i]); 144 if (IS_ERR(reg)) { 145 ret = PTR_ERR(reg); 146 dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", 147 config->pwr_reg_names[i], ret); 148 goto fail; 149 } 150 151 hdmi->pwr_regs[i] = reg; 152 } 153 154 BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); 155 for (i = 0; i < config->hpd_clk_cnt; i++) { 156 struct clk *clk; 157 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; 167 } 168 169 BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); 170 for (i = 0; i < config->pwr_clk_cnt; i++) { 171 struct clk *clk; 172 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; 182 } 183 184 hdmi->i2c = hdmi_i2c_init(hdmi); 185 if (IS_ERR(hdmi->i2c)) { 186 ret = PTR_ERR(hdmi->i2c); 187 dev_err(dev->dev, "failed to get i2c: %d\n", ret); 188 hdmi->i2c = NULL; 189 goto fail; 190 } 191 192 hdmi->bridge = hdmi_bridge_init(hdmi); 193 if (IS_ERR(hdmi->bridge)) { 194 ret = PTR_ERR(hdmi->bridge); 195 dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); 196 hdmi->bridge = NULL; 197 goto fail; 198 } 199 200 hdmi->connector = hdmi_connector_init(hdmi); 201 if (IS_ERR(hdmi->connector)) { 202 ret = PTR_ERR(hdmi->connector); 203 dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); 204 hdmi->connector = NULL; 205 goto fail; 206 } 207 208 if (!config->shared_irq) { 209 hdmi->irq = platform_get_irq(pdev, 0); 210 if (hdmi->irq < 0) { 211 ret = hdmi->irq; 212 dev_err(dev->dev, "failed to get irq: %d\n", ret); 213 goto fail; 214 } 215 216 ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, 217 NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 218 "hdmi_isr", hdmi); 219 if (ret < 0) { 220 dev_err(dev->dev, "failed to request IRQ%u: %d\n", 221 hdmi->irq, ret); 222 goto fail; 223 } 224 } 225 226 encoder->bridge = hdmi->bridge; 227 228 priv->bridges[priv->num_bridges++] = hdmi->bridge; 229 priv->connectors[priv->num_connectors++] = hdmi->connector; 230 231 platform_set_drvdata(pdev, hdmi); 232 233 return hdmi; 234 235 fail: 236 if (hdmi) { 237 /* bridge/connector are normally destroyed by drm: */ 238 if (hdmi->bridge) 239 hdmi->bridge->funcs->destroy(hdmi->bridge); 240 if (hdmi->connector) 241 hdmi->connector->funcs->destroy(hdmi->connector); 242 hdmi_destroy(&hdmi->refcount); 243 } 244 245 return ERR_PTR(ret); 246 } 247 248 /* 249 * The hdmi device: 250 */ 251 252 #include <linux/of_gpio.h> 253 254 static void set_hdmi_pdev(struct drm_device *dev, 255 struct platform_device *pdev) 256 { 257 struct msm_drm_private *priv = dev->dev_private; 258 priv->hdmi_pdev = pdev; 259 } 260 261 #ifdef CONFIG_OF 262 static int get_gpio(struct device *dev, struct device_node *of_node, const char *name) 263 { 264 int gpio = of_get_named_gpio(of_node, name, 0); 265 if (gpio < 0) { 266 char name2[32]; 267 snprintf(name2, sizeof(name2), "%s-gpio", name); 268 gpio = of_get_named_gpio(of_node, name2, 0); 269 if (gpio < 0) { 270 dev_err(dev, "failed to get gpio: %s (%d)\n", 271 name, gpio); 272 gpio = -1; 273 } 274 } 275 return gpio; 276 } 277 #endif 278 279 static int hdmi_bind(struct device *dev, struct device *master, void *data) 280 { 281 static struct hdmi_platform_config config = {}; 282 #ifdef CONFIG_OF 283 struct device_node *of_node = dev->of_node; 284 285 if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) { 286 static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; 287 static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; 288 static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 289 static unsigned long hpd_clk_freq[] = {0, 19200000, 0}; 290 static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; 291 config.phy_init = hdmi_phy_8x74_init; 292 config.hpd_reg_names = hpd_reg_names; 293 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 294 config.pwr_reg_names = pwr_reg_names; 295 config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); 296 config.hpd_clk_names = hpd_clk_names; 297 config.hpd_freq = hpd_clk_freq; 298 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 299 config.pwr_clk_names = pwr_clk_names; 300 config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); 301 config.shared_irq = true; 302 } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) { 303 static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"}; 304 static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"}; 305 config.phy_init = hdmi_phy_8960_init; 306 config.hpd_reg_names = hpd_reg_names; 307 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 308 config.hpd_clk_names = hpd_clk_names; 309 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 310 } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) { 311 config.phy_init = hdmi_phy_8x60_init; 312 } else { 313 dev_err(dev, "unknown phy: %s\n", of_node->name); 314 } 315 316 config.mmio_name = "core_physical"; 317 config.ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk"); 318 config.ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data"); 319 config.hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd"); 320 config.mux_en_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en"); 321 config.mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel"); 322 config.mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm"); 323 324 #else 325 static const char *hpd_clk_names[] = { 326 "core_clk", "master_iface_clk", "slave_iface_clk", 327 }; 328 if (cpu_is_apq8064()) { 329 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 330 config.phy_init = hdmi_phy_8960_init; 331 config.mmio_name = "hdmi_msm_hdmi_addr"; 332 config.hpd_reg_names = hpd_reg_names; 333 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 334 config.hpd_clk_names = hpd_clk_names; 335 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 336 config.ddc_clk_gpio = 70; 337 config.ddc_data_gpio = 71; 338 config.hpd_gpio = 72; 339 config.mux_en_gpio = -1; 340 config.mux_sel_gpio = -1; 341 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { 342 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 343 config.phy_init = hdmi_phy_8960_init; 344 config.mmio_name = "hdmi_msm_hdmi_addr"; 345 config.hpd_reg_names = hpd_reg_names; 346 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 347 config.hpd_clk_names = hpd_clk_names; 348 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 349 config.ddc_clk_gpio = 100; 350 config.ddc_data_gpio = 101; 351 config.hpd_gpio = 102; 352 config.mux_en_gpio = -1; 353 config.mux_sel_gpio = -1; 354 } else if (cpu_is_msm8x60()) { 355 static const char *hpd_reg_names[] = { 356 "8901_hdmi_mvs", "8901_mpp0" 357 }; 358 config.phy_init = hdmi_phy_8x60_init; 359 config.mmio_name = "hdmi_msm_hdmi_addr"; 360 config.hpd_reg_names = hpd_reg_names; 361 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 362 config.hpd_clk_names = hpd_clk_names; 363 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 364 config.ddc_clk_gpio = 170; 365 config.ddc_data_gpio = 171; 366 config.hpd_gpio = 172; 367 config.mux_en_gpio = -1; 368 config.mux_sel_gpio = -1; 369 } 370 #endif 371 dev->platform_data = &config; 372 set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); 373 return 0; 374 } 375 376 static void hdmi_unbind(struct device *dev, struct device *master, 377 void *data) 378 { 379 set_hdmi_pdev(dev_get_drvdata(master), NULL); 380 } 381 382 static const struct component_ops hdmi_ops = { 383 .bind = hdmi_bind, 384 .unbind = hdmi_unbind, 385 }; 386 387 static int hdmi_dev_probe(struct platform_device *pdev) 388 { 389 return component_add(&pdev->dev, &hdmi_ops); 390 } 391 392 static int hdmi_dev_remove(struct platform_device *pdev) 393 { 394 component_del(&pdev->dev, &hdmi_ops); 395 return 0; 396 } 397 398 static const struct of_device_id dt_match[] = { 399 { .compatible = "qcom,hdmi-tx-8074" }, 400 { .compatible = "qcom,hdmi-tx-8960" }, 401 { .compatible = "qcom,hdmi-tx-8660" }, 402 {} 403 }; 404 405 static struct platform_driver hdmi_driver = { 406 .probe = hdmi_dev_probe, 407 .remove = hdmi_dev_remove, 408 .driver = { 409 .name = "hdmi_msm", 410 .of_match_table = dt_match, 411 }, 412 }; 413 414 void __init hdmi_register(void) 415 { 416 platform_driver_register(&hdmi_driver); 417 } 418 419 void __exit hdmi_unregister(void) 420 { 421 platform_driver_unregister(&hdmi_driver); 422 } 423