cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hdmi5.c (17488B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * HDMI driver for OMAP5
      4 *
      5 * Copyright (C) 2014 Texas Instruments Incorporated
      6 *
      7 * Authors:
      8 *	Yong Zhi
      9 *	Mythri pk
     10 *	Archit Taneja <archit@ti.com>
     11 *	Tomi Valkeinen <tomi.valkeinen@ti.com>
     12 */
     13
     14#define DSS_SUBSYS_NAME "HDMI"
     15
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/err.h>
     19#include <linux/io.h>
     20#include <linux/interrupt.h>
     21#include <linux/mutex.h>
     22#include <linux/delay.h>
     23#include <linux/string.h>
     24#include <linux/platform_device.h>
     25#include <linux/pm_runtime.h>
     26#include <linux/clk.h>
     27#include <linux/of.h>
     28#include <linux/regulator/consumer.h>
     29#include <linux/component.h>
     30#include <video/omapfb_dss.h>
     31#include <sound/omap-hdmi-audio.h>
     32
     33#include "hdmi5_core.h"
     34#include "dss.h"
     35#include "dss_features.h"
     36
     37static struct omap_hdmi hdmi;
     38
     39static int hdmi_runtime_get(void)
     40{
     41	int r;
     42
     43	DSSDBG("hdmi_runtime_get\n");
     44
     45	r = pm_runtime_get_sync(&hdmi.pdev->dev);
     46	if (WARN_ON(r < 0)) {
     47		pm_runtime_put_sync(&hdmi.pdev->dev);
     48		return r;
     49	}
     50
     51	return 0;
     52}
     53
     54static void hdmi_runtime_put(void)
     55{
     56	int r;
     57
     58	DSSDBG("hdmi_runtime_put\n");
     59
     60	r = pm_runtime_put_sync(&hdmi.pdev->dev);
     61	WARN_ON(r < 0 && r != -ENOSYS);
     62}
     63
     64static irqreturn_t hdmi_irq_handler(int irq, void *data)
     65{
     66	struct hdmi_wp_data *wp = data;
     67	u32 irqstatus;
     68
     69	irqstatus = hdmi_wp_get_irqstatus(wp);
     70	hdmi_wp_set_irqstatus(wp, irqstatus);
     71
     72	if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
     73			irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
     74		u32 v;
     75		/*
     76		 * If we get both connect and disconnect interrupts at the same
     77		 * time, turn off the PHY, clear interrupts, and restart, which
     78		 * raises connect interrupt if a cable is connected, or nothing
     79		 * if cable is not connected.
     80		 */
     81
     82		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
     83
     84		/*
     85		 * We always get bogus CONNECT & DISCONNECT interrupts when
     86		 * setting the PHY to LDOON. To ignore those, we force the RXDET
     87		 * line to 0 until the PHY power state has been changed.
     88		 */
     89		v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
     90		v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
     91		v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
     92		hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
     93
     94		hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
     95				HDMI_IRQ_LINK_DISCONNECT);
     96
     97		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
     98
     99		REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
    100
    101	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
    102		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
    103	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
    104		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
    105	}
    106
    107	return IRQ_HANDLED;
    108}
    109
    110static int hdmi_init_regulator(void)
    111{
    112	struct regulator *reg;
    113
    114	if (hdmi.vdda_reg != NULL)
    115		return 0;
    116
    117	reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
    118	if (IS_ERR(reg)) {
    119		DSSERR("can't get VDDA regulator\n");
    120		return PTR_ERR(reg);
    121	}
    122
    123	hdmi.vdda_reg = reg;
    124
    125	return 0;
    126}
    127
    128static int hdmi_power_on_core(struct omap_dss_device *dssdev)
    129{
    130	int r;
    131
    132	r = regulator_enable(hdmi.vdda_reg);
    133	if (r)
    134		return r;
    135
    136	r = hdmi_runtime_get();
    137	if (r)
    138		goto err_runtime_get;
    139
    140	/* Make selection of HDMI in DSS */
    141	dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
    142
    143	hdmi.core_enabled = true;
    144
    145	return 0;
    146
    147err_runtime_get:
    148	regulator_disable(hdmi.vdda_reg);
    149
    150	return r;
    151}
    152
    153static void hdmi_power_off_core(struct omap_dss_device *dssdev)
    154{
    155	hdmi.core_enabled = false;
    156
    157	hdmi_runtime_put();
    158	regulator_disable(hdmi.vdda_reg);
    159}
    160
    161static int hdmi_power_on_full(struct omap_dss_device *dssdev)
    162{
    163	int r;
    164	struct omap_video_timings *p;
    165	struct omap_overlay_manager *mgr = hdmi.output.manager;
    166	struct dss_pll_clock_info hdmi_cinfo = { 0 };
    167
    168	r = hdmi_power_on_core(dssdev);
    169	if (r)
    170		return r;
    171
    172	p = &hdmi.cfg.timings;
    173
    174	DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
    175
    176	hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
    177
    178	/* disable and clear irqs */
    179	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
    180	hdmi_wp_set_irqstatus(&hdmi.wp,
    181			hdmi_wp_get_irqstatus(&hdmi.wp));
    182
    183	r = dss_pll_enable(&hdmi.pll.pll);
    184	if (r) {
    185		DSSERR("Failed to enable PLL\n");
    186		goto err_pll_enable;
    187	}
    188
    189	r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
    190	if (r) {
    191		DSSERR("Failed to configure PLL\n");
    192		goto err_pll_cfg;
    193	}
    194
    195	r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
    196		hdmi_cinfo.clkout[0]);
    197	if (r) {
    198		DSSDBG("Failed to start PHY\n");
    199		goto err_phy_cfg;
    200	}
    201
    202	r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
    203	if (r)
    204		goto err_phy_pwr;
    205
    206	hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
    207
    208	/* bypass TV gamma table */
    209	dispc_enable_gamma_table(0);
    210
    211	/* tv size */
    212	dss_mgr_set_timings(mgr, p);
    213
    214	r = hdmi_wp_video_start(&hdmi.wp);
    215	if (r)
    216		goto err_vid_enable;
    217
    218	r = dss_mgr_enable(mgr);
    219	if (r)
    220		goto err_mgr_enable;
    221
    222	hdmi_wp_set_irqenable(&hdmi.wp,
    223			HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
    224
    225	return 0;
    226
    227err_mgr_enable:
    228	hdmi_wp_video_stop(&hdmi.wp);
    229err_vid_enable:
    230	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
    231err_phy_pwr:
    232err_phy_cfg:
    233err_pll_cfg:
    234	dss_pll_disable(&hdmi.pll.pll);
    235err_pll_enable:
    236	hdmi_power_off_core(dssdev);
    237	return -EIO;
    238}
    239
    240static void hdmi_power_off_full(struct omap_dss_device *dssdev)
    241{
    242	struct omap_overlay_manager *mgr = hdmi.output.manager;
    243
    244	hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
    245
    246	dss_mgr_disable(mgr);
    247
    248	hdmi_wp_video_stop(&hdmi.wp);
    249
    250	hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
    251
    252	dss_pll_disable(&hdmi.pll.pll);
    253
    254	hdmi_power_off_core(dssdev);
    255}
    256
    257static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
    258					struct omap_video_timings *timings)
    259{
    260	struct omap_dss_device *out = &hdmi.output;
    261
    262	/* TODO: proper interlace support */
    263	if (timings->interlace)
    264		return -EINVAL;
    265
    266	if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
    267		return -EINVAL;
    268
    269	return 0;
    270}
    271
    272static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
    273		struct omap_video_timings *timings)
    274{
    275	mutex_lock(&hdmi.lock);
    276
    277	hdmi.cfg.timings = *timings;
    278
    279	dispc_set_tv_pclk(timings->pixelclock);
    280
    281	mutex_unlock(&hdmi.lock);
    282}
    283
    284static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
    285		struct omap_video_timings *timings)
    286{
    287	*timings = hdmi.cfg.timings;
    288}
    289
    290static void hdmi_dump_regs(struct seq_file *s)
    291{
    292	mutex_lock(&hdmi.lock);
    293
    294	if (hdmi_runtime_get()) {
    295		mutex_unlock(&hdmi.lock);
    296		return;
    297	}
    298
    299	hdmi_wp_dump(&hdmi.wp, s);
    300	hdmi_pll_dump(&hdmi.pll, s);
    301	hdmi_phy_dump(&hdmi.phy, s);
    302	hdmi5_core_dump(&hdmi.core, s);
    303
    304	hdmi_runtime_put();
    305	mutex_unlock(&hdmi.lock);
    306}
    307
    308static int read_edid(u8 *buf, int len)
    309{
    310	int r;
    311	int idlemode;
    312
    313	mutex_lock(&hdmi.lock);
    314
    315	r = hdmi_runtime_get();
    316	BUG_ON(r);
    317
    318	idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
    319	/* No-idle mode */
    320	REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
    321
    322	r = hdmi5_read_edid(&hdmi.core,  buf, len);
    323
    324	REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
    325
    326	hdmi_runtime_put();
    327	mutex_unlock(&hdmi.lock);
    328
    329	return r;
    330}
    331
    332static void hdmi_start_audio_stream(struct omap_hdmi *hd)
    333{
    334	REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
    335	hdmi_wp_audio_enable(&hd->wp, true);
    336	hdmi_wp_audio_core_req_enable(&hd->wp, true);
    337}
    338
    339static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
    340{
    341	hdmi_wp_audio_core_req_enable(&hd->wp, false);
    342	hdmi_wp_audio_enable(&hd->wp, false);
    343	REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
    344}
    345
    346static int hdmi_display_enable(struct omap_dss_device *dssdev)
    347{
    348	struct omap_dss_device *out = &hdmi.output;
    349	unsigned long flags;
    350	int r = 0;
    351
    352	DSSDBG("ENTER hdmi_display_enable\n");
    353
    354	mutex_lock(&hdmi.lock);
    355
    356	if (out->manager == NULL) {
    357		DSSERR("failed to enable display: no output/manager\n");
    358		r = -ENODEV;
    359		goto err0;
    360	}
    361
    362	r = hdmi_power_on_full(dssdev);
    363	if (r) {
    364		DSSERR("failed to power on device\n");
    365		goto err0;
    366	}
    367
    368	if (hdmi.audio_configured) {
    369		r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
    370				       hdmi.cfg.timings.pixelclock);
    371		if (r) {
    372			DSSERR("Error restoring audio configuration: %d", r);
    373			hdmi.audio_abort_cb(&hdmi.pdev->dev);
    374			hdmi.audio_configured = false;
    375		}
    376	}
    377
    378	spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
    379	if (hdmi.audio_configured && hdmi.audio_playing)
    380		hdmi_start_audio_stream(&hdmi);
    381	hdmi.display_enabled = true;
    382	spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
    383
    384	mutex_unlock(&hdmi.lock);
    385	return 0;
    386
    387err0:
    388	mutex_unlock(&hdmi.lock);
    389	return r;
    390}
    391
    392static void hdmi_display_disable(struct omap_dss_device *dssdev)
    393{
    394	unsigned long flags;
    395
    396	DSSDBG("Enter hdmi_display_disable\n");
    397
    398	mutex_lock(&hdmi.lock);
    399
    400	spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
    401	hdmi_stop_audio_stream(&hdmi);
    402	hdmi.display_enabled = false;
    403	spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
    404
    405	hdmi_power_off_full(dssdev);
    406
    407	mutex_unlock(&hdmi.lock);
    408}
    409
    410static int hdmi_core_enable(struct omap_dss_device *dssdev)
    411{
    412	int r = 0;
    413
    414	DSSDBG("ENTER omapdss_hdmi_core_enable\n");
    415
    416	mutex_lock(&hdmi.lock);
    417
    418	r = hdmi_power_on_core(dssdev);
    419	if (r) {
    420		DSSERR("failed to power on device\n");
    421		goto err0;
    422	}
    423
    424	mutex_unlock(&hdmi.lock);
    425	return 0;
    426
    427err0:
    428	mutex_unlock(&hdmi.lock);
    429	return r;
    430}
    431
    432static void hdmi_core_disable(struct omap_dss_device *dssdev)
    433{
    434	DSSDBG("Enter omapdss_hdmi_core_disable\n");
    435
    436	mutex_lock(&hdmi.lock);
    437
    438	hdmi_power_off_core(dssdev);
    439
    440	mutex_unlock(&hdmi.lock);
    441}
    442
    443static int hdmi_connect(struct omap_dss_device *dssdev,
    444		struct omap_dss_device *dst)
    445{
    446	struct omap_overlay_manager *mgr;
    447	int r;
    448
    449	r = hdmi_init_regulator();
    450	if (r)
    451		return r;
    452
    453	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
    454	if (!mgr)
    455		return -ENODEV;
    456
    457	r = dss_mgr_connect(mgr, dssdev);
    458	if (r)
    459		return r;
    460
    461	r = omapdss_output_set_device(dssdev, dst);
    462	if (r) {
    463		DSSERR("failed to connect output to new device: %s\n",
    464				dst->name);
    465		dss_mgr_disconnect(mgr, dssdev);
    466		return r;
    467	}
    468
    469	return 0;
    470}
    471
    472static void hdmi_disconnect(struct omap_dss_device *dssdev,
    473		struct omap_dss_device *dst)
    474{
    475	WARN_ON(dst != dssdev->dst);
    476
    477	if (dst != dssdev->dst)
    478		return;
    479
    480	omapdss_output_unset_device(dssdev);
    481
    482	if (dssdev->manager)
    483		dss_mgr_disconnect(dssdev->manager, dssdev);
    484}
    485
    486static int hdmi_read_edid(struct omap_dss_device *dssdev,
    487		u8 *edid, int len)
    488{
    489	bool need_enable;
    490	int r;
    491
    492	need_enable = hdmi.core_enabled == false;
    493
    494	if (need_enable) {
    495		r = hdmi_core_enable(dssdev);
    496		if (r)
    497			return r;
    498	}
    499
    500	r = read_edid(edid, len);
    501
    502	if (need_enable)
    503		hdmi_core_disable(dssdev);
    504
    505	return r;
    506}
    507
    508static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
    509		const struct hdmi_avi_infoframe *avi)
    510{
    511	hdmi.cfg.infoframe = *avi;
    512	return 0;
    513}
    514
    515static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
    516		bool hdmi_mode)
    517{
    518	hdmi.cfg.hdmi_dvi_mode = hdmi_mode ? HDMI_HDMI : HDMI_DVI;
    519	return 0;
    520}
    521
    522static const struct omapdss_hdmi_ops hdmi_ops = {
    523	.connect		= hdmi_connect,
    524	.disconnect		= hdmi_disconnect,
    525
    526	.enable			= hdmi_display_enable,
    527	.disable		= hdmi_display_disable,
    528
    529	.check_timings		= hdmi_display_check_timing,
    530	.set_timings		= hdmi_display_set_timing,
    531	.get_timings		= hdmi_display_get_timings,
    532
    533	.read_edid		= hdmi_read_edid,
    534	.set_infoframe		= hdmi_set_infoframe,
    535	.set_hdmi_mode		= hdmi_set_hdmi_mode,
    536};
    537
    538static void hdmi_init_output(struct platform_device *pdev)
    539{
    540	struct omap_dss_device *out = &hdmi.output;
    541
    542	out->dev = &pdev->dev;
    543	out->id = OMAP_DSS_OUTPUT_HDMI;
    544	out->output_type = OMAP_DISPLAY_TYPE_HDMI;
    545	out->name = "hdmi.0";
    546	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
    547	out->ops.hdmi = &hdmi_ops;
    548	out->owner = THIS_MODULE;
    549
    550	omapdss_register_output(out);
    551}
    552
    553static void hdmi_uninit_output(struct platform_device *pdev)
    554{
    555	struct omap_dss_device *out = &hdmi.output;
    556
    557	omapdss_unregister_output(out);
    558}
    559
    560static int hdmi_probe_of(struct platform_device *pdev)
    561{
    562	struct device_node *node = pdev->dev.of_node;
    563	struct device_node *ep;
    564	int r;
    565
    566	ep = omapdss_of_get_first_endpoint(node);
    567	if (!ep)
    568		return 0;
    569
    570	r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
    571	if (r)
    572		goto err;
    573
    574	of_node_put(ep);
    575	return 0;
    576
    577err:
    578	of_node_put(ep);
    579	return r;
    580}
    581
    582/* Audio callbacks */
    583static int hdmi_audio_startup(struct device *dev,
    584			      void (*abort_cb)(struct device *dev))
    585{
    586	struct omap_hdmi *hd = dev_get_drvdata(dev);
    587	int ret = 0;
    588
    589	mutex_lock(&hd->lock);
    590
    591	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
    592		ret = -EPERM;
    593		goto out;
    594	}
    595
    596	hd->audio_abort_cb = abort_cb;
    597
    598out:
    599	mutex_unlock(&hd->lock);
    600
    601	return ret;
    602}
    603
    604static int hdmi_audio_shutdown(struct device *dev)
    605{
    606	struct omap_hdmi *hd = dev_get_drvdata(dev);
    607
    608	mutex_lock(&hd->lock);
    609	hd->audio_abort_cb = NULL;
    610	hd->audio_configured = false;
    611	hd->audio_playing = false;
    612	mutex_unlock(&hd->lock);
    613
    614	return 0;
    615}
    616
    617static int hdmi_audio_start(struct device *dev)
    618{
    619	struct omap_hdmi *hd = dev_get_drvdata(dev);
    620	unsigned long flags;
    621
    622	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
    623
    624	spin_lock_irqsave(&hd->audio_playing_lock, flags);
    625
    626	if (hd->display_enabled)
    627		hdmi_start_audio_stream(hd);
    628	hd->audio_playing = true;
    629
    630	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
    631	return 0;
    632}
    633
    634static void hdmi_audio_stop(struct device *dev)
    635{
    636	struct omap_hdmi *hd = dev_get_drvdata(dev);
    637	unsigned long flags;
    638
    639	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
    640
    641	spin_lock_irqsave(&hd->audio_playing_lock, flags);
    642
    643	if (hd->display_enabled)
    644		hdmi_stop_audio_stream(hd);
    645	hd->audio_playing = false;
    646
    647	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
    648}
    649
    650static int hdmi_audio_config(struct device *dev,
    651			     struct omap_dss_audio *dss_audio)
    652{
    653	struct omap_hdmi *hd = dev_get_drvdata(dev);
    654	int ret;
    655
    656	mutex_lock(&hd->lock);
    657
    658	if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
    659		ret = -EPERM;
    660		goto out;
    661	}
    662
    663	ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
    664				 hd->cfg.timings.pixelclock);
    665
    666	if (!ret) {
    667		hd->audio_configured = true;
    668		hd->audio_config = *dss_audio;
    669	}
    670out:
    671	mutex_unlock(&hd->lock);
    672
    673	return ret;
    674}
    675
    676static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
    677	.audio_startup = hdmi_audio_startup,
    678	.audio_shutdown = hdmi_audio_shutdown,
    679	.audio_start = hdmi_audio_start,
    680	.audio_stop = hdmi_audio_stop,
    681	.audio_config = hdmi_audio_config,
    682};
    683
    684static int hdmi_audio_register(struct device *dev)
    685{
    686	struct omap_hdmi_audio_pdata pdata = {
    687		.dev = dev,
    688		.version = 5,
    689		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
    690		.ops = &hdmi_audio_ops,
    691	};
    692
    693	hdmi.audio_pdev = platform_device_register_data(
    694		dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
    695		&pdata, sizeof(pdata));
    696
    697	if (IS_ERR(hdmi.audio_pdev))
    698		return PTR_ERR(hdmi.audio_pdev);
    699
    700	hdmi_runtime_get();
    701	hdmi.wp_idlemode =
    702		REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
    703	hdmi_runtime_put();
    704
    705	return 0;
    706}
    707
    708/* HDMI HW IP initialisation */
    709static int hdmi5_bind(struct device *dev, struct device *master, void *data)
    710{
    711	struct platform_device *pdev = to_platform_device(dev);
    712	int r;
    713	int irq;
    714
    715	hdmi.pdev = pdev;
    716	platform_set_drvdata(pdev, &hdmi);
    717
    718	mutex_init(&hdmi.lock);
    719	spin_lock_init(&hdmi.audio_playing_lock);
    720
    721	if (pdev->dev.of_node) {
    722		r = hdmi_probe_of(pdev);
    723		if (r)
    724			return r;
    725	}
    726
    727	r = hdmi_wp_init(pdev, &hdmi.wp);
    728	if (r)
    729		return r;
    730
    731	r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
    732	if (r)
    733		return r;
    734
    735	r = hdmi_phy_init(pdev, &hdmi.phy);
    736	if (r)
    737		goto err;
    738
    739	r = hdmi5_core_init(pdev, &hdmi.core);
    740	if (r)
    741		goto err;
    742
    743	irq = platform_get_irq(pdev, 0);
    744	if (irq < 0) {
    745		DSSERR("platform_get_irq failed\n");
    746		r = -ENODEV;
    747		goto err;
    748	}
    749
    750	r = devm_request_threaded_irq(&pdev->dev, irq,
    751			NULL, hdmi_irq_handler,
    752			IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
    753	if (r) {
    754		DSSERR("HDMI IRQ request failed\n");
    755		goto err;
    756	}
    757
    758	pm_runtime_enable(&pdev->dev);
    759
    760	hdmi_init_output(pdev);
    761
    762	r = hdmi_audio_register(&pdev->dev);
    763	if (r) {
    764		DSSERR("Registering HDMI audio failed %d\n", r);
    765		hdmi_uninit_output(pdev);
    766		pm_runtime_disable(&pdev->dev);
    767		return r;
    768	}
    769
    770	dss_debugfs_create_file("hdmi", hdmi_dump_regs);
    771
    772	return 0;
    773err:
    774	hdmi_pll_uninit(&hdmi.pll);
    775	return r;
    776}
    777
    778static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
    779{
    780	struct platform_device *pdev = to_platform_device(dev);
    781
    782	if (hdmi.audio_pdev)
    783		platform_device_unregister(hdmi.audio_pdev);
    784
    785	hdmi_uninit_output(pdev);
    786
    787	hdmi_pll_uninit(&hdmi.pll);
    788
    789	pm_runtime_disable(&pdev->dev);
    790}
    791
    792static const struct component_ops hdmi5_component_ops = {
    793	.bind	= hdmi5_bind,
    794	.unbind	= hdmi5_unbind,
    795};
    796
    797static int hdmi5_probe(struct platform_device *pdev)
    798{
    799	return component_add(&pdev->dev, &hdmi5_component_ops);
    800}
    801
    802static int hdmi5_remove(struct platform_device *pdev)
    803{
    804	component_del(&pdev->dev, &hdmi5_component_ops);
    805	return 0;
    806}
    807
    808static int hdmi_runtime_suspend(struct device *dev)
    809{
    810	dispc_runtime_put();
    811
    812	return 0;
    813}
    814
    815static int hdmi_runtime_resume(struct device *dev)
    816{
    817	int r;
    818
    819	r = dispc_runtime_get();
    820	if (r < 0)
    821		return r;
    822
    823	return 0;
    824}
    825
    826static const struct dev_pm_ops hdmi_pm_ops = {
    827	.runtime_suspend = hdmi_runtime_suspend,
    828	.runtime_resume = hdmi_runtime_resume,
    829};
    830
    831static const struct of_device_id hdmi_of_match[] = {
    832	{ .compatible = "ti,omap5-hdmi", },
    833	{ .compatible = "ti,dra7-hdmi", },
    834	{},
    835};
    836
    837static struct platform_driver omapdss_hdmihw_driver = {
    838	.probe		= hdmi5_probe,
    839	.remove		= hdmi5_remove,
    840	.driver         = {
    841		.name   = "omapdss_hdmi5",
    842		.pm	= &hdmi_pm_ops,
    843		.of_match_table = hdmi_of_match,
    844		.suppress_bind_attrs = true,
    845	},
    846};
    847
    848int __init hdmi5_init_platform_driver(void)
    849{
    850	return platform_driver_register(&omapdss_hdmihw_driver);
    851}
    852
    853void hdmi5_uninit_platform_driver(void)
    854{
    855	platform_driver_unregister(&omapdss_hdmihw_driver);
    856}