static int hdmi_power_on_core(struct omap_dss_device *dssdev) { int r; gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); gpio_set_value(hdmi.ls_oe_gpio, 1); /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ udelay(300); r = regulator_enable(hdmi.vdda_hdmi_dac_reg); if (r) goto err_vdac_enable; r = hdmi_runtime_get(); if (r) goto err_runtime_get; /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); return 0; err_runtime_get: regulator_disable(hdmi.vdda_hdmi_dac_reg); err_vdac_enable: gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); gpio_set_value(hdmi.ls_oe_gpio, 0); return r; }
static int hdmi_power_on(struct omap_dss_device *dssdev) { int r; const struct hdmi_config *timing; struct omap_video_timings *p; unsigned long phy; r = hdmi_runtime_get(); if (r) return r; if (cpu_is_omap54xx()) { r = regulator_enable(hdmi.vdds_hdmi); if (r) goto err; } dss_mgr_disable(dssdev->manager); p = &dssdev->panel.timings; DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); timing = hdmi_get_timings(); if (timing == NULL) { /* HDMI code 4 corresponds to 640 * 480 VGA */ hdmi.ip_data.cfg.cm.code = 4; /* DVI mode 1 corresponds to HDMI 0 to DVI */ hdmi.ip_data.cfg.cm.mode = HDMI_DVI; hdmi.ip_data.cfg = vesa_timings[0]; } else { hdmi.ip_data.cfg = *timing; } switch (hdmi.ip_data.cfg.deep_color) { case HDMI_DEEP_COLOR_30BIT: phy = (p->pixel_clock * 125) / 100 ; break; case HDMI_DEEP_COLOR_36BIT: if (p->pixel_clock >= 148500) { DSSERR("36 bit deep color not supported for the \ pixel clock %d\n", p->pixel_clock); goto err; } phy = (p->pixel_clock * 150) / 100; break; case HDMI_DEEP_COLOR_24BIT: default: phy = p->pixel_clock; break; }
void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); if (hdmi_runtime_get()) return; hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); }
bool omapdss_hdmi_detect(void) { int r; mutex_lock(&hdmi.lock); r = hdmi_runtime_get(); BUG_ON(r); r = hdmi.ip_data.ops->detect(&hdmi.ip_data); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); return r == 1; }
int omapdss_hdmi_read_edid(u8 *buf, int len) { int r; mutex_lock(&hdmi.lock); r = hdmi_runtime_get(); BUG_ON(r); r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); return r; }
static int read_edid(u8 *buf, int len) { int r; mutex_lock(&hdmi.lock); r = hdmi_runtime_get(); BUG_ON(r); r = hdmi4_read_edid(&hdmi.core, buf, len); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); return r; }
static void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); if (hdmi_runtime_get()) { mutex_unlock(&hdmi.lock); return; } hdmi_wp_dump(&hdmi.wp, s); hdmi_pll_dump(&hdmi.pll, s); hdmi_phy_dump(&hdmi.phy, s); hdmi5_core_dump(&hdmi.core, s); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); }
static int hdcp_wq_start_authentication(void) { int status = 0; struct hdmi_ip_data *ip_data; HDCP_DBG("hdcp_wq_start_authentication %ums\n", jiffies_to_msecs(jiffies)); if (hdmi_runtime_get()) { HDCP_ERR("%s Error enabling clocks\n", __func__); return -EINVAL; } ip_data = get_hdmi_ip_data(); if (ip_data->ops->hdcp_enable) ip_data->ops->hdcp_enable(ip_data); else status = -EINVAL; hdmi_runtime_put(); return status; }
static int read_edid(u8 *buf, int len) { int r; int idlemode; mutex_lock(&hdmi.lock); r = hdmi_runtime_get(); BUG_ON(r); idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); /* No-idle mode */ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); r = hdmi5_read_edid(&hdmi.core, buf, len); REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2); hdmi_runtime_put(); mutex_unlock(&hdmi.lock); return r; }
static int hdmi_power_on_core(struct omap_dss_device *dssdev) { int r; r = regulator_enable(hdmi.vdda_reg); if (r) return r; r = hdmi_runtime_get(); if (r) goto err_runtime_get; /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); hdmi.core_enabled = true; return 0; err_runtime_get: regulator_disable(hdmi.vdda_reg); return r; }
static void __exit hdcp_exit(void) { HDCP_DBG("hdcp_exit() %ums\n", jiffies_to_msecs(jiffies)); mutex_lock(&hdcp.lock); kfree(hdcp.en_ctrl); if (hdmi_runtime_get()) { HDCP_ERR("%s Error enabling clocks\n", __func__); goto err_handling; } /* Un-register HDCP callbacks to HDMI library */ omapdss_hdmi_register_hdcp_callbacks(NULL, NULL, NULL); hdmi_runtime_put(); err_handling: misc_deregister(hdcp.mdev); kfree(hdcp.mdev); iounmap(hdcp.deshdcp_base_addr); if (cpu_is_omap44xx()) iounmap(hdcp.hdmi_wp_base_addr); kfree(hdcp.hdcp_work); destroy_workqueue(hdcp.workqueue); mutex_unlock(&hdcp.lock); mutex_destroy(&hdcp.lock); mutex_destroy(&hdcp.re_entrant_lock); }
static int hdmi_audio_register(struct device *dev) { struct omap_hdmi_audio_pdata pdata = { .dev = dev, .dss_version = omapdss_get_version(), .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), .ops = &hdmi_audio_ops, }; hdmi.audio_pdev = platform_device_register_data( dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); if (IS_ERR(hdmi.audio_pdev)) return PTR_ERR(hdmi.audio_pdev); hdmi_runtime_get(); hdmi.wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); hdmi_runtime_put(); return 0; } /* HDMI HW IP initialisation */ static int hdmi5_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); int r; int irq; hdmi.pdev = pdev; dev_set_drvdata(&pdev->dev, &hdmi); mutex_init(&hdmi.lock); spin_lock_init(&hdmi.audio_playing_lock); if (pdev->dev.of_node) { r = hdmi_probe_of(pdev); if (r) return r; } r = hdmi_wp_init(pdev, &hdmi.wp); if (r) return r; r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); if (r) return r; r = hdmi_phy_init(pdev, &hdmi.phy); if (r) goto err; r = hdmi5_core_init(pdev, &hdmi.core); if (r) goto err; irq = platform_get_irq(pdev, 0); if (irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; goto err; } r = devm_request_threaded_irq(&pdev->dev, irq, NULL, hdmi_irq_handler, IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); if (r) { DSSERR("HDMI IRQ request failed\n"); goto err; } pm_runtime_enable(&pdev->dev); hdmi_init_output(pdev); r = hdmi_audio_register(&pdev->dev); if (r) { DSSERR("Registering HDMI audio failed %d\n", r); hdmi_uninit_output(pdev); pm_runtime_disable(&pdev->dev); return r; } dss_debugfs_create_file("hdmi", hdmi_dump_regs); return 0; err: hdmi_pll_uninit(&hdmi.pll); return r; } static void hdmi5_unbind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); if (hdmi.audio_pdev) platform_device_unregister(hdmi.audio_pdev); hdmi_uninit_output(pdev); hdmi_pll_uninit(&hdmi.pll); pm_runtime_disable(&pdev->dev); } static const struct component_ops hdmi5_component_ops = { .bind = hdmi5_bind, .unbind = hdmi5_unbind, }; static int hdmi5_probe(struct platform_device *pdev) { return component_add(&pdev->dev, &hdmi5_component_ops); } static int hdmi5_remove(struct platform_device *pdev) { component_del(&pdev->dev, &hdmi5_component_ops); return 0; }
static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; struct omap_video_timings *p; unsigned long phy; r = hdmi_runtime_get(); if (r) return r; dss_mgr_disable(dssdev->manager); p = &dssdev->panel.timings; DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); code = get_timings_index(); update_hdmi_timings(&hdmi.ip_data.cfg, p, code); phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); /* config the PLL and PHY hdmi_set_pll_pwrfirst */ r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); goto err; } r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); goto err; } hdmi.ip_data.cfg.cm.mode = hdmi.mode; hdmi.ip_data.cfg.cm.code = hdmi.code; hdmi.ip_data.ops->video_configure(&hdmi.ip_data); /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); /* Select the dispc clock source as PRCM clock, to ensure that it is not * DSI PLL source as the clock selected by DSI PLL might not be * sufficient for the resolution selected / that can be changed * dynamically by user. This can be moved to single location , say * Boardfile. */ dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); /* bypass TV gamma table */ dispc_enable_gamma_table(0); /* tv size */ dispc_set_digit_size(dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); r = dss_mgr_enable(dssdev->manager); if (r) goto err_mgr_enable; return 0; err_mgr_enable: hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err: hdmi_runtime_put(); return -EIO; }
static int hdmi_power_on(struct omap_dss_device *dssdev) { int r; struct omap_video_timings *p; struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned long phy; gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); gpio_set_value(hdmi.ls_oe_gpio, 1); /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ udelay(300); r = regulator_enable(hdmi.vdda_hdmi_dac_reg); if (r) goto err_vdac_enable; r = hdmi_runtime_get(); if (r) goto err_runtime_get; dss_mgr_disable(mgr); p = &hdmi.ip_data.cfg.timings; DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); hdmi.ip_data.ops->video_disable(&hdmi.ip_data); /* config the PLL and PHY hdmi_set_pll_pwrfirst */ r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); goto err_pll_enable; } r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); goto err_phy_enable; } hdmi.ip_data.ops->video_configure(&hdmi.ip_data); /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); /* Select the dispc clock source as PRCM clock, to ensure that it is not * DSI PLL source as the clock selected by DSI PLL might not be * sufficient for the resolution selected / that can be changed * dynamically by user. This can be moved to single location , say * Boardfile. */ dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); /* bypass TV gamma table */ dispc_enable_gamma_table(0); /* tv size */ dss_mgr_set_timings(mgr, p); r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); if (r) goto err_vid_enable; r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; return 0; err_mgr_enable: hdmi.ip_data.ops->video_disable(&hdmi.ip_data); err_vid_enable: hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err_pll_enable: hdmi_runtime_put(); err_runtime_get: regulator_disable(hdmi.vdda_hdmi_dac_reg); err_vdac_enable: gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); gpio_set_value(hdmi.ls_oe_gpio, 0); return -EIO; }
static int __init hdcp_init(void) { HDCP_DBG("hdcp_init() %ums\n", jiffies_to_msecs(jiffies)); if (cpu_is_omap44xx()) { /* Map HDMI WP address */ hdcp.hdmi_wp_base_addr = ioremap(HDMI_WP, 0x1000); if (!hdcp.hdmi_wp_base_addr) { printk(KERN_ERR "HDCP: HDMI WP IOremap error\n"); return -EFAULT; } } else { hdcp.hdmi_wp_base_addr = NULL; } hdcp.hdcp_work = kzalloc(sizeof(struct hdcp_worker_data), GFP_KERNEL); if (!hdcp.hdcp_work) { HDCP_ERR("Could not allocate HDCP worker structure\n"); goto err_alloc_work; } hdcp.mdev = kzalloc(sizeof(struct miscdevice), GFP_KERNEL); if (!hdcp.mdev) { HDCP_ERR("Could not allocate misc device memory\n"); goto err_alloc_mdev; } /* Map DESHDCP in kernel address space */ hdcp.deshdcp_base_addr = ioremap(DSS_SS_FROM_L3__DESHDCP, 0x34); if (!hdcp.deshdcp_base_addr) { HDCP_ERR("DESHDCP IOremap error\n"); goto err_map_deshdcp; } mutex_init(&hdcp.lock); hdcp.mdev->minor = MISC_DYNAMIC_MINOR; hdcp.mdev->name = "hdcp"; hdcp.mdev->mode = 0666; hdcp.mdev->fops = &hdcp_fops; if (misc_register(hdcp.mdev)) { HDCP_ERR("Could not add character driver\n"); goto err_misc_register; } mutex_lock(&hdcp.lock); /* Variable init */ hdcp.en_ctrl = 0; hdcp.hdcp_state = HDCP_DISABLED; hdcp.pending_start = 0; hdcp.pending_wq_event = 0; hdcp.retry_cnt = 0; hdcp.auth_state = HDCP_STATE_DISABLED; hdcp.pending_disable = 0; hdcp.hdcp_up_event = 0; hdcp.hdcp_down_event = 0; hdcp_wait_re_entrance = 0; hdcp.hpd_low = 0; spin_lock_init(&hdcp.spinlock); init_completion(&hdcp_comp); hdcp.workqueue = create_singlethread_workqueue("hdcp"); if (hdcp.workqueue == NULL) { HDCP_ERR("Could not create HDCP workqueue\n"); goto err_add_driver; } INIT_DELAYED_WORK(&hdcp.hdcp_work->dwork, hdcp_work_queue); mutex_init(&hdcp.re_entrant_lock); if (hdmi_runtime_get()) { HDCP_ERR("%s Error enabling clocks\n", __func__); goto err_runtime; } /* Register HDCP callbacks to HDMI library */ if (cpu_is_omap44xx()) omapdss_hdmi_register_hdcp_callbacks(&omap4_hdcp_start_frame_cb, &omap4_hdcp_3des_cb, &omap4_hdcp_irq_cb); else omapdss_hdmi_register_hdcp_callbacks(&hdcp_start_frame_cb, &hdcp_3des_cb, &hdcp_irq_cb); hdmi_runtime_put(); mutex_unlock(&hdcp.lock); hdcp_load_keys(); return 0; err_runtime: mutex_destroy(&hdcp.re_entrant_lock); destroy_workqueue(hdcp.workqueue); err_add_driver: misc_deregister(hdcp.mdev); mutex_unlock(&hdcp.lock); err_misc_register: mutex_destroy(&hdcp.lock); iounmap(hdcp.deshdcp_base_addr); err_map_deshdcp: kfree(hdcp.mdev); err_alloc_mdev: kfree(hdcp.hdcp_work); err_alloc_work: if (cpu_is_omap44xx()) iounmap(hdcp.hdmi_wp_base_addr); return -EFAULT; }
static void omap4_hdcp_work_queue(struct work_struct *work) { struct hdcp_worker_data *hdcp_w = container_of(work, struct hdcp_worker_data, dwork.work); int event = atomic_read(&hdcp_w->state); mutex_lock(&hdcp.lock); hdmi_runtime_get(); HDCP_DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d auth=%d evt= %x %d" " hdcp_ctrl=%02x", jiffies_to_msecs(jiffies), hdcp.hdmi_state, hdcp.hdcp_state, hdcp.auth_state, (event & 0xFF00) >> 8, event & 0xFF, RD_REG_32(hdcp.hdmi_wp_base_addr + HDMI_IP_CORE_SYSTEM, HDMI_IP_CORE_SYSTEM__HDCP_CTRL)); /* Clear pending_wq_event * In case a delayed work is scheduled from the state machine * "pending_wq_event" is used to memorize pointer on the event to be * able to cancel any pending work in case HDCP is disabled */ if (event & HDCP_WORKQUEUE_SRC) hdcp.pending_wq_event = 0; /* First handle HDMI state */ if (event == HDCP_START_FRAME_EVENT) { hdcp.pending_start = 0; hdcp.hdmi_state = HDMI_STARTED; } /**********************/ /* HDCP state machine */ /**********************/ switch (hdcp.hdcp_state) { /* State */ /*********/ case HDCP_DISABLED: /* HDCP enable control or re-authentication event */ if (event == HDCP_ENABLE_CTL) { if (hdcp.en_ctrl->nb_retry == 0) hdcp.retry_cnt = HDCP_INFINITE_REAUTH; else hdcp.retry_cnt = hdcp.en_ctrl->nb_retry; if (hdcp.hdmi_state == HDMI_STARTED) omap4_hdcp_wq_start_authentication(); else hdcp.hdcp_state = HDCP_ENABLE_PENDING; } break; /* State */ /*********/ case HDCP_ENABLE_PENDING: /* HDMI start frame event */ if (event == HDCP_START_FRAME_EVENT) omap4_hdcp_wq_start_authentication(); break; /* State */ /*********/ case HDCP_AUTHENTICATION_START: /* Re-authentication */ if (event == HDCP_AUTH_REATT_EVENT) omap4_hdcp_wq_start_authentication(); break; /* State */ /*********/ case HDCP_WAIT_R0_DELAY: /* R0 timer elapsed */ if (event == HDCP_R0_EXP_EVENT) hdcp_wq_check_r0(); break; /* State */ /*********/ case HDCP_WAIT_KSV_LIST: /* Ri failure */ if (event == HDCP_RI_FAIL_EVENT) { printk(KERN_INFO "HDCP: Ri check failure\n"); hdcp_wq_authentication_failure(); } /* KSV list ready event */ else if (event == HDCP_KSV_LIST_RDY_EVENT) hdcp_wq_step2_authentication(); /* Timeout */ else if (event == HDCP_KSV_TIMEOUT_EVENT) { printk(KERN_INFO "HDCP: BCAPS polling timeout\n"); hdcp_wq_authentication_failure(); } break; /* State */ /*********/ case HDCP_LINK_INTEGRITY_CHECK: /* Ri failure */ if (event == HDCP_RI_FAIL_EVENT) { printk(KERN_INFO "HDCP: Ri check failure\n"); hdcp_wq_authentication_failure(); } break; default: printk(KERN_WARNING "HDCP: error - unknow HDCP state\n"); break; } kfree(hdcp_w); hdcp_w = 0; if (event == HDCP_START_FRAME_EVENT) hdcp.pending_start = 0; if (event == HDCP_KSV_LIST_RDY_EVENT || event == HDCP_R0_EXP_EVENT) { hdcp.pending_wq_event = 0; } HDCP_DBG("hdcp_work_queue() - END - %u hdmi=%d hdcp=%d auth=%d evt=%x %d ", jiffies_to_msecs(jiffies), hdcp.hdmi_state, hdcp.hdcp_state, hdcp.auth_state, (event & 0xFF00) >> 8, event & 0xFF); hdmi_runtime_put(); mutex_unlock(&hdcp.lock); }