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 static struct platform_device *hdmi_pdev; 21 22 void hdmi_set_mode(struct hdmi *hdmi, bool power_on) 23 { 24 uint32_t ctrl = 0; 25 26 if (power_on) { 27 ctrl |= HDMI_CTRL_ENABLE; 28 if (!hdmi->hdmi_mode) { 29 ctrl |= HDMI_CTRL_HDMI; 30 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 31 ctrl &= ~HDMI_CTRL_HDMI; 32 } else { 33 ctrl |= HDMI_CTRL_HDMI; 34 } 35 } else { 36 ctrl = HDMI_CTRL_HDMI; 37 } 38 39 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); 40 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", 41 power_on ? "Enable" : "Disable", ctrl); 42 } 43 44 irqreturn_t hdmi_irq(int irq, void *dev_id) 45 { 46 struct hdmi *hdmi = dev_id; 47 48 /* Process HPD: */ 49 hdmi_connector_irq(hdmi->connector); 50 51 /* Process DDC: */ 52 hdmi_i2c_irq(hdmi->i2c); 53 54 /* TODO audio.. */ 55 56 return IRQ_HANDLED; 57 } 58 59 void hdmi_destroy(struct kref *kref) 60 { 61 struct hdmi *hdmi = container_of(kref, struct hdmi, refcount); 62 struct hdmi_phy *phy = hdmi->phy; 63 64 if (phy) 65 phy->funcs->destroy(phy); 66 67 if (hdmi->i2c) 68 hdmi_i2c_destroy(hdmi->i2c); 69 70 put_device(&hdmi->pdev->dev); 71 } 72 73 /* initialize connector */ 74 struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) 75 { 76 struct hdmi *hdmi = NULL; 77 struct msm_drm_private *priv = dev->dev_private; 78 struct platform_device *pdev = hdmi_pdev; 79 struct hdmi_platform_config *config; 80 int i, ret; 81 82 if (!pdev) { 83 dev_err(dev->dev, "no hdmi device\n"); 84 ret = -ENXIO; 85 goto fail; 86 } 87 88 config = pdev->dev.platform_data; 89 90 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); 91 if (!hdmi) { 92 ret = -ENOMEM; 93 goto fail; 94 } 95 96 kref_init(&hdmi->refcount); 97 98 get_device(&pdev->dev); 99 100 hdmi->dev = dev; 101 hdmi->pdev = pdev; 102 hdmi->config = config; 103 hdmi->encoder = encoder; 104 105 /* not sure about which phy maps to which msm.. probably I miss some */ 106 if (config->phy_init) 107 hdmi->phy = config->phy_init(hdmi); 108 else 109 hdmi->phy = ERR_PTR(-ENXIO); 110 111 if (IS_ERR(hdmi->phy)) { 112 ret = PTR_ERR(hdmi->phy); 113 dev_err(dev->dev, "failed to load phy: %d\n", ret); 114 hdmi->phy = NULL; 115 goto fail; 116 } 117 118 hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); 119 if (IS_ERR(hdmi->mmio)) { 120 ret = PTR_ERR(hdmi->mmio); 121 goto fail; 122 } 123 124 BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); 125 for (i = 0; i < config->hpd_reg_cnt; i++) { 126 struct regulator *reg; 127 128 reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]); 129 if (IS_ERR(reg)) { 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; 137 } 138 139 BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); 140 for (i = 0; i < config->pwr_reg_cnt; i++) { 141 struct regulator *reg; 142 143 reg = devm_regulator_get(&pdev->dev, 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 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 int hdmi_dev_probe(struct platform_device *pdev) 253 { 254 static struct hdmi_platform_config config = {}; 255 #ifdef CONFIG_OF 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 292 #else 293 static const char *hpd_clk_names[] = { 294 "core_clk", "master_iface_clk", "slave_iface_clk", 295 }; 296 if (cpu_is_apq8064()) { 297 static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; 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); 304 config.ddc_clk_gpio = 70; 305 config.ddc_data_gpio = 71; 306 config.hpd_gpio = 72; 307 config.mux_en_gpio = -1; 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"}; 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); 317 config.ddc_clk_gpio = 100; 318 config.ddc_data_gpio = 101; 319 config.hpd_gpio = 102; 320 config.mux_en_gpio = -1; 321 config.mux_sel_gpio = -1; 322 } else if (cpu_is_msm8x60()) { 323 static const char *hpd_reg_names[] = { 324 "8901_hdmi_mvs", "8901_mpp0" 325 }; 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); 332 config.ddc_clk_gpio = 170; 333 config.ddc_data_gpio = 171; 334 config.hpd_gpio = 172; 335 config.mux_en_gpio = -1; 336 config.mux_sel_gpio = -1; 337 } 338 #endif 339 pdev->dev.platform_data = &config; 340 hdmi_pdev = pdev; 341 return 0; 342 } 343 344 static int hdmi_dev_remove(struct platform_device *pdev) 345 { 346 hdmi_pdev = NULL; 347 return 0; 348 } 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 356 static struct platform_driver hdmi_driver = { 357 .probe = hdmi_dev_probe, 358 .remove = hdmi_dev_remove, 359 .driver = { 360 .name = "hdmi_msm", 361 .of_match_table = dt_match, 362 }, 363 }; 364 365 void __init hdmi_register(void) 366 { 367 platform_driver_register(&hdmi_driver); 368 } 369 370 void __exit hdmi_unregister(void) 371 { 372 platform_driver_unregister(&hdmi_driver); 373 } 374