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(&pdev->dev, config->hpd_reg_names[i]); 127 if (IS_ERR(reg)) { 128 ret = PTR_ERR(reg); 129 dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", 130 config->hpd_reg_names[i], ret); 131 goto fail; 132 } 133 134 hdmi->hpd_regs[i] = reg; 135 } 136 137 BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); 138 for (i = 0; i < config->pwr_reg_cnt; i++) { 139 struct regulator *reg; 140 141 reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]); 142 if (IS_ERR(reg)) { 143 ret = PTR_ERR(reg); 144 dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", 145 config->pwr_reg_names[i], ret); 146 goto fail; 147 } 148 149 hdmi->pwr_regs[i] = reg; 150 } 151 152 BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); 153 for (i = 0; i < config->hpd_clk_cnt; i++) { 154 struct clk *clk; 155 156 clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); 157 if (IS_ERR(clk)) { 158 ret = PTR_ERR(clk); 159 dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n", 160 config->hpd_clk_names[i], ret); 161 goto fail; 162 } 163 164 hdmi->hpd_clks[i] = clk; 165 } 166 167 BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); 168 for (i = 0; i < config->pwr_clk_cnt; i++) { 169 struct clk *clk; 170 171 clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); 172 if (IS_ERR(clk)) { 173 ret = PTR_ERR(clk); 174 dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n", 175 config->pwr_clk_names[i], ret); 176 goto fail; 177 } 178 179 hdmi->pwr_clks[i] = clk; 180 } 181 182 hdmi->i2c = hdmi_i2c_init(hdmi); 183 if (IS_ERR(hdmi->i2c)) { 184 ret = PTR_ERR(hdmi->i2c); 185 dev_err(dev->dev, "failed to get i2c: %d\n", ret); 186 hdmi->i2c = NULL; 187 goto fail; 188 } 189 190 hdmi->bridge = hdmi_bridge_init(hdmi); 191 if (IS_ERR(hdmi->bridge)) { 192 ret = PTR_ERR(hdmi->bridge); 193 dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); 194 hdmi->bridge = NULL; 195 goto fail; 196 } 197 198 hdmi->connector = hdmi_connector_init(hdmi); 199 if (IS_ERR(hdmi->connector)) { 200 ret = PTR_ERR(hdmi->connector); 201 dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); 202 hdmi->connector = NULL; 203 goto fail; 204 } 205 206 if (!config->shared_irq) { 207 hdmi->irq = platform_get_irq(pdev, 0); 208 if (hdmi->irq < 0) { 209 ret = hdmi->irq; 210 dev_err(dev->dev, "failed to get irq: %d\n", ret); 211 goto fail; 212 } 213 214 ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, 215 NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 216 "hdmi_isr", hdmi); 217 if (ret < 0) { 218 dev_err(dev->dev, "failed to request IRQ%u: %d\n", 219 hdmi->irq, ret); 220 goto fail; 221 } 222 } 223 224 encoder->bridge = hdmi->bridge; 225 226 priv->bridges[priv->num_bridges++] = hdmi->bridge; 227 priv->connectors[priv->num_connectors++] = hdmi->connector; 228 229 platform_set_drvdata(pdev, hdmi); 230 231 return hdmi; 232 233 fail: 234 if (hdmi) { 235 /* bridge/connector are normally destroyed by drm: */ 236 if (hdmi->bridge) 237 hdmi->bridge->funcs->destroy(hdmi->bridge); 238 if (hdmi->connector) 239 hdmi->connector->funcs->destroy(hdmi->connector); 240 hdmi_destroy(&hdmi->refcount); 241 } 242 243 return ERR_PTR(ret); 244 } 245 246 /* 247 * The hdmi device: 248 */ 249 250 #include <linux/of_gpio.h> 251 252 static void set_hdmi_pdev(struct drm_device *dev, 253 struct platform_device *pdev) 254 { 255 struct msm_drm_private *priv = dev->dev_private; 256 priv->hdmi_pdev = pdev; 257 } 258 259 static int hdmi_bind(struct device *dev, struct device *master, void *data) 260 { 261 static struct hdmi_platform_config config = {}; 262 #ifdef CONFIG_OF 263 struct device_node *of_node = dev->of_node; 264 265 int get_gpio(const char *name) 266 { 267 int gpio = of_get_named_gpio(of_node, name, 0); 268 if (gpio < 0) { 269 dev_err(dev, "failed to get gpio: %s (%d)\n", 270 name, gpio); 271 gpio = -1; 272 } 273 return gpio; 274 } 275 276 /* TODO actually use DT.. */ 277 static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; 278 static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; 279 static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; 280 static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; 281 282 config.phy_init = hdmi_phy_8x74_init; 283 config.mmio_name = "core_physical"; 284 config.hpd_reg_names = hpd_reg_names; 285 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 286 config.pwr_reg_names = pwr_reg_names; 287 config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); 288 config.hpd_clk_names = hpd_clk_names; 289 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 290 config.pwr_clk_names = pwr_clk_names; 291 config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); 292 config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk"); 293 config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data"); 294 config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd"); 295 config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en"); 296 config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel"); 297 config.shared_irq = true; 298 299 #else 300 static const char *hpd_clk_names[] = { 301 "core_clk", "master_iface_clk", "slave_iface_clk", 302 }; 303 if (cpu_is_apq8064()) { 304 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 305 config.phy_init = hdmi_phy_8960_init; 306 config.mmio_name = "hdmi_msm_hdmi_addr"; 307 config.hpd_reg_names = hpd_reg_names; 308 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 309 config.hpd_clk_names = hpd_clk_names; 310 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 311 config.ddc_clk_gpio = 70; 312 config.ddc_data_gpio = 71; 313 config.hpd_gpio = 72; 314 config.mux_en_gpio = -1; 315 config.mux_sel_gpio = -1; 316 } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { 317 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 318 config.phy_init = hdmi_phy_8960_init; 319 config.mmio_name = "hdmi_msm_hdmi_addr"; 320 config.hpd_reg_names = hpd_reg_names; 321 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 322 config.hpd_clk_names = hpd_clk_names; 323 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 324 config.ddc_clk_gpio = 100; 325 config.ddc_data_gpio = 101; 326 config.hpd_gpio = 102; 327 config.mux_en_gpio = -1; 328 config.mux_sel_gpio = -1; 329 } else if (cpu_is_msm8x60()) { 330 static const char *hpd_reg_names[] = { 331 "8901_hdmi_mvs", "8901_mpp0" 332 }; 333 config.phy_init = hdmi_phy_8x60_init; 334 config.mmio_name = "hdmi_msm_hdmi_addr"; 335 config.hpd_reg_names = hpd_reg_names; 336 config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); 337 config.hpd_clk_names = hpd_clk_names; 338 config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); 339 config.ddc_clk_gpio = 170; 340 config.ddc_data_gpio = 171; 341 config.hpd_gpio = 172; 342 config.mux_en_gpio = -1; 343 config.mux_sel_gpio = -1; 344 } 345 #endif 346 dev->platform_data = &config; 347 set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); 348 return 0; 349 } 350 351 static void hdmi_unbind(struct device *dev, struct device *master, 352 void *data) 353 { 354 set_hdmi_pdev(dev_get_drvdata(master), NULL); 355 } 356 357 static const struct component_ops hdmi_ops = { 358 .bind = hdmi_bind, 359 .unbind = hdmi_unbind, 360 }; 361 362 static int hdmi_dev_probe(struct platform_device *pdev) 363 { 364 return component_add(&pdev->dev, &hdmi_ops); 365 } 366 367 static int hdmi_dev_remove(struct platform_device *pdev) 368 { 369 component_del(&pdev->dev, &hdmi_ops); 370 return 0; 371 } 372 373 static const struct of_device_id dt_match[] = { 374 { .compatible = "qcom,hdmi-tx" }, 375 {} 376 }; 377 378 static struct platform_driver hdmi_driver = { 379 .probe = hdmi_dev_probe, 380 .remove = hdmi_dev_remove, 381 .driver = { 382 .name = "hdmi_msm", 383 .of_match_table = dt_match, 384 }, 385 }; 386 387 void __init hdmi_register(void) 388 { 389 platform_driver_register(&hdmi_driver); 390 } 391 392 void __exit hdmi_unregister(void) 393 { 394 platform_driver_unregister(&hdmi_driver); 395 } 396