582 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2014 The Linux Foundation. All rights reserved.4 * Copyright (C) 2013 Red Hat5 * Author: Rob Clark <robdclark@gmail.com>6 */7 8#include <linux/gpio/consumer.h>9#include <linux/of_irq.h>10#include <linux/of_platform.h>11#include <linux/platform_device.h>12 13#include <drm/drm_bridge_connector.h>14#include <drm/drm_of.h>15 16#include <sound/hdmi-codec.h>17#include "hdmi.h"18 19void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)20{21 uint32_t ctrl = 0;22 unsigned long flags;23 24 spin_lock_irqsave(&hdmi->reg_lock, flags);25 if (power_on) {26 ctrl |= HDMI_CTRL_ENABLE;27 if (!hdmi->hdmi_mode) {28 ctrl |= HDMI_CTRL_HDMI;29 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);30 ctrl &= ~HDMI_CTRL_HDMI;31 } else {32 ctrl |= HDMI_CTRL_HDMI;33 }34 } else {35 ctrl = HDMI_CTRL_HDMI;36 }37 38 hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);39 spin_unlock_irqrestore(&hdmi->reg_lock, flags);40 DBG("HDMI Core: %s, HDMI_CTRL=0x%08x",41 power_on ? "Enable" : "Disable", ctrl);42}43 44static irqreturn_t msm_hdmi_irq(int irq, void *dev_id)45{46 struct hdmi *hdmi = dev_id;47 48 /* Process HPD: */49 msm_hdmi_hpd_irq(hdmi->bridge);50 51 /* Process DDC: */52 msm_hdmi_i2c_irq(hdmi->i2c);53 54 /* Process HDCP: */55 if (hdmi->hdcp_ctrl)56 msm_hdmi_hdcp_irq(hdmi->hdcp_ctrl);57 58 /* TODO audio.. */59 60 return IRQ_HANDLED;61}62 63static void msm_hdmi_destroy(struct hdmi *hdmi)64{65 /*66 * at this point, hpd has been disabled,67 * after flush workq, it's safe to deinit hdcp68 */69 if (hdmi->workq)70 destroy_workqueue(hdmi->workq);71 msm_hdmi_hdcp_destroy(hdmi);72 73 if (hdmi->i2c)74 msm_hdmi_i2c_destroy(hdmi->i2c);75}76 77static void msm_hdmi_put_phy(struct hdmi *hdmi)78{79 if (hdmi->phy_dev) {80 put_device(hdmi->phy_dev);81 hdmi->phy = NULL;82 hdmi->phy_dev = NULL;83 }84}85 86static int msm_hdmi_get_phy(struct hdmi *hdmi)87{88 struct platform_device *pdev = hdmi->pdev;89 struct platform_device *phy_pdev;90 struct device_node *phy_node;91 92 phy_node = of_parse_phandle(pdev->dev.of_node, "phys", 0);93 if (!phy_node) {94 DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n");95 return -ENXIO;96 }97 98 phy_pdev = of_find_device_by_node(phy_node);99 of_node_put(phy_node);100 101 if (!phy_pdev)102 return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");103 104 hdmi->phy = platform_get_drvdata(phy_pdev);105 if (!hdmi->phy) {106 put_device(&phy_pdev->dev);107 return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready\n");108 }109 110 hdmi->phy_dev = &phy_pdev->dev;111 112 return 0;113}114 115/* construct hdmi at bind/probe time, grab all the resources. If116 * we are to EPROBE_DEFER we want to do it here, rather than later117 * at modeset_init() time118 */119static int msm_hdmi_init(struct hdmi *hdmi)120{121 struct platform_device *pdev = hdmi->pdev;122 int ret;123 124 hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);125 if (!hdmi->workq) {126 ret = -ENOMEM;127 goto fail;128 }129 130 hdmi->i2c = msm_hdmi_i2c_init(hdmi);131 if (IS_ERR(hdmi->i2c)) {132 ret = PTR_ERR(hdmi->i2c);133 DRM_DEV_ERROR(&pdev->dev, "failed to get i2c: %d\n", ret);134 hdmi->i2c = NULL;135 goto fail;136 }137 138 hdmi->hdcp_ctrl = msm_hdmi_hdcp_init(hdmi);139 if (IS_ERR(hdmi->hdcp_ctrl)) {140 dev_warn(&pdev->dev, "failed to init hdcp: disabled\n");141 hdmi->hdcp_ctrl = NULL;142 }143 144 return 0;145 146fail:147 msm_hdmi_destroy(hdmi);148 149 return ret;150}151 152/* Second part of initialization, the drm/kms level modeset_init,153 * constructs/initializes mode objects, etc, is called from master154 * driver (not hdmi sub-device's probe/bind!)155 *156 * Any resource (regulator/clk/etc) which could be missing at boot157 * should be handled in msm_hdmi_init() so that failure happens from158 * hdmi sub-device's probe.159 */160int msm_hdmi_modeset_init(struct hdmi *hdmi,161 struct drm_device *dev, struct drm_encoder *encoder)162{163 int ret;164 165 hdmi->dev = dev;166 hdmi->encoder = encoder;167 168 hdmi_audio_infoframe_init(&hdmi->audio.infoframe);169 170 ret = msm_hdmi_bridge_init(hdmi);171 if (ret) {172 DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret);173 goto fail;174 }175 176 if (hdmi->next_bridge) {177 ret = drm_bridge_attach(hdmi->encoder, hdmi->next_bridge, hdmi->bridge,178 DRM_BRIDGE_ATTACH_NO_CONNECTOR);179 if (ret) {180 DRM_DEV_ERROR(dev->dev, "failed to attach next HDMI bridge: %d\n", ret);181 goto fail;182 }183 }184 185 hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder);186 if (IS_ERR(hdmi->connector)) {187 ret = PTR_ERR(hdmi->connector);188 DRM_DEV_ERROR(dev->dev, "failed to create HDMI connector: %d\n", ret);189 hdmi->connector = NULL;190 goto fail;191 }192 193 drm_connector_attach_encoder(hdmi->connector, hdmi->encoder);194 195 ret = devm_request_irq(dev->dev, hdmi->irq,196 msm_hdmi_irq, IRQF_TRIGGER_HIGH,197 "hdmi_isr", hdmi);198 if (ret < 0) {199 DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n",200 hdmi->irq, ret);201 goto fail;202 }203 204 ret = msm_hdmi_hpd_enable(hdmi->bridge);205 if (ret < 0) {206 DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret);207 goto fail;208 }209 210 return 0;211 212fail:213 if (hdmi->connector) {214 hdmi->connector->funcs->destroy(hdmi->connector);215 hdmi->connector = NULL;216 }217 218 return ret;219}220 221/*222 * The hdmi device:223 */224 225#define HDMI_CFG(item, entry) \226 .item ## _names = item ##_names_ ## entry, \227 .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)228 229static const char *hpd_reg_names_8960[] = {"core-vdda"};230static const char *hpd_clk_names_8960[] = {"core", "master_iface", "slave_iface"};231 232static const struct hdmi_platform_config hdmi_tx_8960_config = {233 HDMI_CFG(hpd_reg, 8960),234 HDMI_CFG(hpd_clk, 8960),235};236 237static const char *pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"};238static const char *pwr_clk_names_8x74[] = {"extp", "alt_iface"};239static const char *hpd_clk_names_8x74[] = {"iface", "core", "mdp_core"};240static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};241 242static const struct hdmi_platform_config hdmi_tx_8974_config = {243 HDMI_CFG(pwr_reg, 8x74),244 HDMI_CFG(pwr_clk, 8x74),245 HDMI_CFG(hpd_clk, 8x74),246 .hpd_freq = hpd_clk_freq_8x74,247};248 249/*250 * HDMI audio codec callbacks251 */252static int msm_hdmi_audio_hw_params(struct device *dev, void *data,253 struct hdmi_codec_daifmt *daifmt,254 struct hdmi_codec_params *params)255{256 struct hdmi *hdmi = dev_get_drvdata(dev);257 unsigned int chan;258 unsigned int channel_allocation = 0;259 unsigned int rate;260 unsigned int level_shift = 0; /* 0dB */261 bool down_mix = false;262 263 DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,264 params->sample_width, params->cea.channels);265 266 switch (params->cea.channels) {267 case 2:268 /* FR and FL speakers */269 channel_allocation = 0;270 chan = MSM_HDMI_AUDIO_CHANNEL_2;271 break;272 case 4:273 /* FC, LFE, FR and FL speakers */274 channel_allocation = 0x3;275 chan = MSM_HDMI_AUDIO_CHANNEL_4;276 break;277 case 6:278 /* RR, RL, FC, LFE, FR and FL speakers */279 channel_allocation = 0x0B;280 chan = MSM_HDMI_AUDIO_CHANNEL_6;281 break;282 case 8:283 /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */284 channel_allocation = 0x1F;285 chan = MSM_HDMI_AUDIO_CHANNEL_8;286 break;287 default:288 return -EINVAL;289 }290 291 switch (params->sample_rate) {292 case 32000:293 rate = HDMI_SAMPLE_RATE_32KHZ;294 break;295 case 44100:296 rate = HDMI_SAMPLE_RATE_44_1KHZ;297 break;298 case 48000:299 rate = HDMI_SAMPLE_RATE_48KHZ;300 break;301 case 88200:302 rate = HDMI_SAMPLE_RATE_88_2KHZ;303 break;304 case 96000:305 rate = HDMI_SAMPLE_RATE_96KHZ;306 break;307 case 176400:308 rate = HDMI_SAMPLE_RATE_176_4KHZ;309 break;310 case 192000:311 rate = HDMI_SAMPLE_RATE_192KHZ;312 break;313 default:314 DRM_DEV_ERROR(dev, "rate[%d] not supported!\n",315 params->sample_rate);316 return -EINVAL;317 }318 319 msm_hdmi_audio_set_sample_rate(hdmi, rate);320 msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,321 level_shift, down_mix);322 323 return 0;324}325 326static void msm_hdmi_audio_shutdown(struct device *dev, void *data)327{328 struct hdmi *hdmi = dev_get_drvdata(dev);329 330 msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);331}332 333static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {334 .hw_params = msm_hdmi_audio_hw_params,335 .audio_shutdown = msm_hdmi_audio_shutdown,336};337 338static struct hdmi_codec_pdata codec_data = {339 .ops = &msm_hdmi_audio_codec_ops,340 .max_i2s_channels = 8,341 .i2s = 1,342};343 344static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev)345{346 hdmi->audio_pdev = platform_device_register_data(dev,347 HDMI_CODEC_DRV_NAME,348 PLATFORM_DEVID_AUTO,349 &codec_data,350 sizeof(codec_data));351 return PTR_ERR_OR_ZERO(hdmi->audio_pdev);352}353 354static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)355{356 struct msm_drm_private *priv = dev_get_drvdata(master);357 struct hdmi *hdmi = dev_get_drvdata(dev);358 int err;359 360 err = msm_hdmi_init(hdmi);361 if (err)362 return err;363 priv->hdmi = hdmi;364 365 err = msm_hdmi_register_audio_driver(hdmi, dev);366 if (err) {367 DRM_ERROR("Failed to attach an audio codec %d\n", err);368 hdmi->audio_pdev = NULL;369 }370 371 return 0;372}373 374static void msm_hdmi_unbind(struct device *dev, struct device *master,375 void *data)376{377 struct msm_drm_private *priv = dev_get_drvdata(master);378 379 if (priv->hdmi) {380 if (priv->hdmi->audio_pdev)381 platform_device_unregister(priv->hdmi->audio_pdev);382 383 if (priv->hdmi->bridge)384 msm_hdmi_hpd_disable(priv->hdmi);385 386 msm_hdmi_destroy(priv->hdmi);387 priv->hdmi = NULL;388 }389}390 391static const struct component_ops msm_hdmi_ops = {392 .bind = msm_hdmi_bind,393 .unbind = msm_hdmi_unbind,394};395 396static int msm_hdmi_dev_probe(struct platform_device *pdev)397{398 const struct hdmi_platform_config *config;399 struct device *dev = &pdev->dev;400 struct hdmi *hdmi;401 struct resource *res;402 int i, ret;403 404 config = of_device_get_match_data(dev);405 if (!config)406 return -EINVAL;407 408 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);409 if (!hdmi)410 return -ENOMEM;411 412 hdmi->pdev = pdev;413 hdmi->config = config;414 spin_lock_init(&hdmi->reg_lock);415 416 ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 1, 0, NULL, &hdmi->next_bridge);417 if (ret && ret != -ENODEV)418 return ret;419 420 hdmi->mmio = msm_ioremap(pdev, "core_physical");421 if (IS_ERR(hdmi->mmio))422 return PTR_ERR(hdmi->mmio);423 424 /* HDCP needs physical address of hdmi register */425 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,426 "core_physical");427 if (!res)428 return -EINVAL;429 hdmi->mmio_phy_addr = res->start;430 431 hdmi->qfprom_mmio = msm_ioremap(pdev, "qfprom_physical");432 if (IS_ERR(hdmi->qfprom_mmio)) {433 DRM_DEV_INFO(&pdev->dev, "can't find qfprom resource\n");434 hdmi->qfprom_mmio = NULL;435 }436 437 hdmi->irq = platform_get_irq(pdev, 0);438 if (hdmi->irq < 0)439 return hdmi->irq;440 441 hdmi->hpd_regs = devm_kcalloc(&pdev->dev,442 config->hpd_reg_cnt,443 sizeof(hdmi->hpd_regs[0]),444 GFP_KERNEL);445 if (!hdmi->hpd_regs)446 return -ENOMEM;447 448 for (i = 0; i < config->hpd_reg_cnt; i++)449 hdmi->hpd_regs[i].supply = config->hpd_reg_names[i];450 451 ret = devm_regulator_bulk_get(&pdev->dev, config->hpd_reg_cnt, hdmi->hpd_regs);452 if (ret)453 return dev_err_probe(dev, ret, "failed to get hpd regulators\n");454 455 hdmi->pwr_regs = devm_kcalloc(&pdev->dev,456 config->pwr_reg_cnt,457 sizeof(hdmi->pwr_regs[0]),458 GFP_KERNEL);459 if (!hdmi->pwr_regs)460 return -ENOMEM;461 462 for (i = 0; i < config->pwr_reg_cnt; i++)463 hdmi->pwr_regs[i].supply = config->pwr_reg_names[i];464 465 ret = devm_regulator_bulk_get(&pdev->dev, config->pwr_reg_cnt, hdmi->pwr_regs);466 if (ret)467 return dev_err_probe(dev, ret, "failed to get pwr regulators\n");468 469 hdmi->hpd_clks = devm_kcalloc(&pdev->dev,470 config->hpd_clk_cnt,471 sizeof(hdmi->hpd_clks[0]),472 GFP_KERNEL);473 if (!hdmi->hpd_clks)474 return -ENOMEM;475 476 for (i = 0; i < config->hpd_clk_cnt; i++) {477 struct clk *clk;478 479 clk = msm_clk_get(pdev, config->hpd_clk_names[i]);480 if (IS_ERR(clk))481 return dev_err_probe(dev, PTR_ERR(clk),482 "failed to get hpd clk: %s\n",483 config->hpd_clk_names[i]);484 485 hdmi->hpd_clks[i] = clk;486 }487 488 hdmi->pwr_clks = devm_kcalloc(&pdev->dev,489 config->pwr_clk_cnt,490 sizeof(hdmi->pwr_clks[0]),491 GFP_KERNEL);492 if (!hdmi->pwr_clks)493 return -ENOMEM;494 495 for (i = 0; i < config->pwr_clk_cnt; i++) {496 struct clk *clk;497 498 clk = msm_clk_get(pdev, config->pwr_clk_names[i]);499 if (IS_ERR(clk))500 return dev_err_probe(dev, PTR_ERR(clk),501 "failed to get pwr clk: %s\n",502 config->pwr_clk_names[i]);503 504 hdmi->pwr_clks[i] = clk;505 }506 507 hdmi->hpd_gpiod = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);508 /* This will catch e.g. -EPROBE_DEFER */509 if (IS_ERR(hdmi->hpd_gpiod))510 return dev_err_probe(dev, PTR_ERR(hdmi->hpd_gpiod),511 "failed to get hpd gpio\n");512 513 if (!hdmi->hpd_gpiod)514 DBG("failed to get HPD gpio");515 516 if (hdmi->hpd_gpiod)517 gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD");518 519 ret = msm_hdmi_get_phy(hdmi);520 if (ret) {521 DRM_DEV_ERROR(&pdev->dev, "failed to get phy\n");522 return ret;523 }524 525 ret = devm_pm_runtime_enable(&pdev->dev);526 if (ret)527 goto err_put_phy;528 529 platform_set_drvdata(pdev, hdmi);530 531 ret = component_add(&pdev->dev, &msm_hdmi_ops);532 if (ret)533 goto err_put_phy;534 535 return 0;536 537err_put_phy:538 msm_hdmi_put_phy(hdmi);539 return ret;540}541 542static void msm_hdmi_dev_remove(struct platform_device *pdev)543{544 struct hdmi *hdmi = dev_get_drvdata(&pdev->dev);545 546 component_del(&pdev->dev, &msm_hdmi_ops);547 548 msm_hdmi_put_phy(hdmi);549}550 551static const struct of_device_id msm_hdmi_dt_match[] = {552 { .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },553 { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },554 { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },555 { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8974_config },556 { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },557 { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },558 { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config },559 {}560};561 562static struct platform_driver msm_hdmi_driver = {563 .probe = msm_hdmi_dev_probe,564 .remove_new = msm_hdmi_dev_remove,565 .driver = {566 .name = "hdmi_msm",567 .of_match_table = msm_hdmi_dt_match,568 },569};570 571void __init msm_hdmi_register(void)572{573 msm_hdmi_phy_driver_register();574 platform_driver_register(&msm_hdmi_driver);575}576 577void __exit msm_hdmi_unregister(void)578{579 platform_driver_unregister(&msm_hdmi_driver);580 msm_hdmi_phy_driver_unregister();581}582