diff options
Diffstat (limited to 'drivers/gpu/drm/msm/hdmi/hdmi.c')
| -rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.c | 161 |
1 files changed, 83 insertions, 78 deletions
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 814536202efe..9a0989c0b4de 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -17,12 +17,16 @@ */ #include <linux/of_irq.h> +#include <linux/of_gpio.h> + #include "hdmi.h" void hdmi_set_mode(struct hdmi *hdmi, bool power_on) { uint32_t ctrl = 0; + unsigned long flags; + spin_lock_irqsave(&hdmi->reg_lock, flags); if (power_on) { ctrl |= HDMI_CTRL_ENABLE; if (!hdmi->hdmi_mode) { @@ -37,6 +41,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on) } hdmi_write(hdmi, REG_HDMI_CTRL, ctrl); + spin_unlock_irqrestore(&hdmi->reg_lock, flags); DBG("HDMI Core: %s, HDMI_CTRL=0x%08x", power_on ? "Enable" : "Disable", ctrl); } @@ -51,6 +56,10 @@ static irqreturn_t hdmi_irq(int irq, void *dev_id) /* Process DDC: */ hdmi_i2c_irq(hdmi->i2c); + /* Process HDCP: */ + if (hdmi->hdcp_ctrl) + hdmi_hdcp_irq(hdmi->hdcp_ctrl); + /* TODO audio.. */ return IRQ_HANDLED; @@ -60,6 +69,15 @@ static void hdmi_destroy(struct hdmi *hdmi) { struct hdmi_phy *phy = hdmi->phy; + /* + * at this point, hpd has been disabled, + * after flush workq, it's safe to deinit hdcp + */ + if (hdmi->workq) { + flush_workqueue(hdmi->workq); + destroy_workqueue(hdmi->workq); + } + hdmi_hdcp_destroy(hdmi); if (phy) phy->funcs->destroy(phy); @@ -77,6 +95,7 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) { struct hdmi_platform_config *config = pdev->dev.platform_data; struct hdmi *hdmi = NULL; + struct resource *res; int i, ret; hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); @@ -87,18 +106,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) hdmi->pdev = pdev; hdmi->config = config; + spin_lock_init(&hdmi->reg_lock); /* not sure about which phy maps to which msm.. probably I miss some */ - if (config->phy_init) + if (config->phy_init) { hdmi->phy = config->phy_init(hdmi); - else - hdmi->phy = ERR_PTR(-ENXIO); - if (IS_ERR(hdmi->phy)) { - ret = PTR_ERR(hdmi->phy); - dev_err(&pdev->dev, "failed to load phy: %d\n", ret); - hdmi->phy = NULL; - goto fail; + if (IS_ERR(hdmi->phy)) { + ret = PTR_ERR(hdmi->phy); + dev_err(&pdev->dev, "failed to load phy: %d\n", ret); + hdmi->phy = NULL; + goto fail; + } } hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); @@ -107,6 +126,18 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) goto fail; } + /* HDCP needs physical address of hdmi register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + config->mmio_name); + hdmi->mmio_phy_addr = res->start; + + hdmi->qfprom_mmio = msm_ioremap(pdev, + config->qfprom_mmio_name, "HDMI_QFPROM"); + if (IS_ERR(hdmi->qfprom_mmio)) { + dev_info(&pdev->dev, "can't find qfprom resource\n"); + hdmi->qfprom_mmio = NULL; + } + hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) * config->hpd_reg_cnt, GFP_KERNEL); if (!hdmi->hpd_regs) { @@ -189,6 +220,8 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) hdmi->pwr_clks[i] = clk; } + hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0); + hdmi->i2c = hdmi_i2c_init(hdmi); if (IS_ERR(hdmi->i2c)) { ret = PTR_ERR(hdmi->i2c); @@ -197,6 +230,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev) goto fail; } + hdmi->hdcp_ctrl = hdmi_hdcp_init(hdmi); + if (IS_ERR(hdmi->hdcp_ctrl)) { + dev_warn(&pdev->dev, "failed to init hdcp: disabled\n"); + hdmi->hdcp_ctrl = NULL; + } + return hdmi; fail: @@ -285,12 +324,13 @@ fail: * The hdmi device: */ -#include <linux/of_gpio.h> - #define HDMI_CFG(item, entry) \ .item ## _names = item ##_names_ ## entry, \ .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry) +static const char *pwr_reg_names_none[] = {}; +static const char *hpd_reg_names_none[] = {}; + static struct hdmi_platform_config hdmi_tx_8660_config = { .phy_init = hdmi_phy_8x60_init, }; @@ -310,7 +350,7 @@ static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"}; static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"}; static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0}; -static struct hdmi_platform_config hdmi_tx_8074_config = { +static struct hdmi_platform_config hdmi_tx_8974_config = { .phy_init = hdmi_phy_8x74_init, HDMI_CFG(pwr_reg, 8x74), HDMI_CFG(hpd_reg, 8x74), @@ -330,15 +370,24 @@ static struct hdmi_platform_config hdmi_tx_8084_config = { .hpd_freq = hpd_clk_freq_8x74, }; -static const struct of_device_id dt_match[] = { - { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, - { .compatible = "qcom,hdmi-tx-8074", .data = &hdmi_tx_8074_config }, - { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config }, - { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config }, - {} +static struct hdmi_platform_config hdmi_tx_8994_config = { + .phy_init = NULL, /* nothing to do for this HDMI PHY 20nm */ + HDMI_CFG(pwr_reg, 8x74), + HDMI_CFG(hpd_reg, none), + HDMI_CFG(pwr_clk, 8x74), + HDMI_CFG(hpd_clk, 8x74), + .hpd_freq = hpd_clk_freq_8x74, +}; + +static struct hdmi_platform_config hdmi_tx_8996_config = { + .phy_init = NULL, + HDMI_CFG(pwr_reg, none), + HDMI_CFG(hpd_reg, none), + HDMI_CFG(pwr_clk, 8x74), + HDMI_CFG(hpd_clk, 8x74), + .hpd_freq = hpd_clk_freq_8x74, }; -#ifdef CONFIG_OF static int get_gpio(struct device *dev, struct device_node *of_node, const char *name) { int gpio = of_get_named_gpio(of_node, name, 0); @@ -347,14 +396,12 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char snprintf(name2, sizeof(name2), "%s-gpio", name); gpio = of_get_named_gpio(of_node, name2, 0); if (gpio < 0) { - dev_err(dev, "failed to get gpio: %s (%d)\n", - name, gpio); + DBG("failed to get gpio: %s (%d)", name, gpio); gpio = -1; } } return gpio; } -#endif static int hdmi_bind(struct device *dev, struct device *master, void *data) { @@ -362,20 +409,17 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) struct msm_drm_private *priv = drm->dev_private; static struct hdmi_platform_config *hdmi_cfg; struct hdmi *hdmi; -#ifdef CONFIG_OF struct device_node *of_node = dev->of_node; - const struct of_device_id *match; - match = of_match_node(dt_match, of_node); - if (match && match->data) { - hdmi_cfg = (struct hdmi_platform_config *)match->data; - DBG("hdmi phy: %s", match->compatible); - } else { - dev_err(dev, "unknown phy: %s\n", of_node->name); + hdmi_cfg = (struct hdmi_platform_config *) + of_device_get_match_data(dev); + if (!hdmi_cfg) { + dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name); return -ENXIO; } hdmi_cfg->mmio_name = "core_physical"; + hdmi_cfg->qfprom_mmio_name = "qfprom_physical"; hdmi_cfg->ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk"); hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data"); hdmi_cfg->hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd"); @@ -383,55 +427,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel"); hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm"); -#else - static struct hdmi_platform_config config = {}; - static const char *hpd_clk_names[] = { - "core_clk", "master_iface_clk", "slave_iface_clk", - }; - if (cpu_is_apq8064()) { - static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; - config.phy_init = hdmi_phy_8960_init; - config.mmio_name = "hdmi_msm_hdmi_addr"; - config.hpd_reg_names = hpd_reg_names; - config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); - config.hpd_clk_names = hpd_clk_names; - config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); - config.ddc_clk_gpio = 70; - config.ddc_data_gpio = 71; - config.hpd_gpio = 72; - config.mux_en_gpio = -1; - config.mux_sel_gpio = -1; - } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { - static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; - config.phy_init = hdmi_phy_8960_init; - config.mmio_name = "hdmi_msm_hdmi_addr"; - config.hpd_reg_names = hpd_reg_names; - config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); - config.hpd_clk_names = hpd_clk_names; - config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); - config.ddc_clk_gpio = 100; - config.ddc_data_gpio = 101; - config.hpd_gpio = 102; - config.mux_en_gpio = -1; - config.mux_sel_gpio = -1; - } else if (cpu_is_msm8x60()) { - static const char *hpd_reg_names[] = { - "8901_hdmi_mvs", "8901_mpp0" - }; - config.phy_init = hdmi_phy_8x60_init; - config.mmio_name = "hdmi_msm_hdmi_addr"; - config.hpd_reg_names = hpd_reg_names; - config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); - config.hpd_clk_names = hpd_clk_names; - config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); - config.ddc_clk_gpio = 170; - config.ddc_data_gpio = 171; - config.hpd_gpio = 172; - config.mux_en_gpio = -1; - config.mux_sel_gpio = -1; - } - hdmi_cfg = &config; -#endif dev->platform_data = hdmi_cfg; hdmi = hdmi_init(to_platform_device(dev)); @@ -469,6 +464,16 @@ static int hdmi_dev_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config }, + { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config }, + { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config }, + { .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config }, + { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config }, + { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config }, + {} +}; + static struct platform_driver hdmi_driver = { .probe = hdmi_dev_probe, .remove = hdmi_dev_remove, |

