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

hdmi4.c (18893B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
      4 *
      5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com/
      6 * Authors: Yong Zhi
      7 *	Mythri pk <mythripk@ti.com>
      8 */
      9
     10#define DSS_SUBSYS_NAME "HDMI"
     11
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/err.h>
     15#include <linux/io.h>
     16#include <linux/interrupt.h>
     17#include <linux/mutex.h>
     18#include <linux/delay.h>
     19#include <linux/string.h>
     20#include <linux/platform_device.h>
     21#include <linux/pm_runtime.h>
     22#include <linux/clk.h>
     23#include <linux/regulator/consumer.h>
     24#include <linux/component.h>
     25#include <linux/of.h>
     26#include <linux/of_graph.h>
     27#include <sound/omap-hdmi-audio.h>
     28#include <media/cec.h>
     29
     30#include <drm/drm_atomic.h>
     31#include <drm/drm_atomic_state_helper.h>
     32
     33#include "omapdss.h"
     34#include "hdmi4_core.h"
     35#include "hdmi4_cec.h"
     36#include "dss.h"
     37#include "hdmi.h"
     38
     39static int hdmi_runtime_get(struct omap_hdmi *hdmi)
     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_noidle(&hdmi->pdev->dev);
     48		return r;
     49	}
     50	return 0;
     51}
     52
     53static void hdmi_runtime_put(struct omap_hdmi *hdmi)
     54{
     55	int r;
     56
     57	DSSDBG("hdmi_runtime_put\n");
     58
     59	r = pm_runtime_put_sync(&hdmi->pdev->dev);
     60	WARN_ON(r < 0 && r != -ENOSYS);
     61}
     62
     63static irqreturn_t hdmi_irq_handler(int irq, void *data)
     64{
     65	struct omap_hdmi *hdmi = data;
     66	struct hdmi_wp_data *wp = &hdmi->wp;
     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		/*
     75		 * If we get both connect and disconnect interrupts at the same
     76		 * time, turn off the PHY, clear interrupts, and restart, which
     77		 * raises connect interrupt if a cable is connected, or nothing
     78		 * if cable is not connected.
     79		 */
     80		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
     81
     82		hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
     83				HDMI_IRQ_LINK_DISCONNECT);
     84
     85		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
     86	} else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
     87		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
     88	} else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
     89		hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
     90	}
     91	if (irqstatus & HDMI_IRQ_CORE) {
     92		u32 intr4 = hdmi_read_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4);
     93
     94		hdmi_write_reg(hdmi->core.base, HDMI_CORE_SYS_INTR4, intr4);
     95		if (intr4 & 8)
     96			hdmi4_cec_irq(&hdmi->core);
     97	}
     98
     99	return IRQ_HANDLED;
    100}
    101
    102static int hdmi_power_on_core(struct omap_hdmi *hdmi)
    103{
    104	int r;
    105
    106	if (hdmi->core.core_pwr_cnt++)
    107		return 0;
    108
    109	r = regulator_enable(hdmi->vdda_reg);
    110	if (r)
    111		goto err_reg_enable;
    112
    113	r = hdmi_runtime_get(hdmi);
    114	if (r)
    115		goto err_runtime_get;
    116
    117	hdmi4_core_powerdown_disable(&hdmi->core);
    118
    119	/* Make selection of HDMI in DSS */
    120	dss_select_hdmi_venc_clk_source(hdmi->dss, DSS_HDMI_M_PCLK);
    121
    122	hdmi->core_enabled = true;
    123
    124	return 0;
    125
    126err_runtime_get:
    127	regulator_disable(hdmi->vdda_reg);
    128err_reg_enable:
    129	hdmi->core.core_pwr_cnt--;
    130
    131	return r;
    132}
    133
    134static void hdmi_power_off_core(struct omap_hdmi *hdmi)
    135{
    136	if (--hdmi->core.core_pwr_cnt)
    137		return;
    138
    139	hdmi->core_enabled = false;
    140
    141	hdmi_runtime_put(hdmi);
    142	regulator_disable(hdmi->vdda_reg);
    143}
    144
    145static int hdmi_power_on_full(struct omap_hdmi *hdmi)
    146{
    147	int r;
    148	const struct videomode *vm;
    149	struct hdmi_wp_data *wp = &hdmi->wp;
    150	struct dss_pll_clock_info hdmi_cinfo = { 0 };
    151	unsigned int pc;
    152
    153	r = hdmi_power_on_core(hdmi);
    154	if (r)
    155		return r;
    156
    157	/* disable and clear irqs */
    158	hdmi_wp_clear_irqenable(wp, ~HDMI_IRQ_CORE);
    159	hdmi_wp_set_irqstatus(wp, ~HDMI_IRQ_CORE);
    160
    161	vm = &hdmi->cfg.vm;
    162
    163	DSSDBG("hdmi_power_on hactive= %d vactive = %d\n", vm->hactive,
    164	       vm->vactive);
    165
    166	pc = vm->pixelclock;
    167	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
    168		pc *= 2;
    169
    170	/* DSS_HDMI_TCLK is bitclk / 10 */
    171	pc *= 10;
    172
    173	dss_pll_calc_b(&hdmi->pll.pll, clk_get_rate(hdmi->pll.pll.clkin),
    174		pc, &hdmi_cinfo);
    175
    176	r = dss_pll_enable(&hdmi->pll.pll);
    177	if (r) {
    178		DSSERR("Failed to enable PLL\n");
    179		goto err_pll_enable;
    180	}
    181
    182	r = dss_pll_set_config(&hdmi->pll.pll, &hdmi_cinfo);
    183	if (r) {
    184		DSSERR("Failed to configure PLL\n");
    185		goto err_pll_cfg;
    186	}
    187
    188	r = hdmi_phy_configure(&hdmi->phy, hdmi_cinfo.clkdco,
    189		hdmi_cinfo.clkout[0]);
    190	if (r) {
    191		DSSDBG("Failed to configure PHY\n");
    192		goto err_phy_cfg;
    193	}
    194
    195	r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
    196	if (r)
    197		goto err_phy_pwr;
    198
    199	hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
    200
    201	r = dss_mgr_enable(&hdmi->output);
    202	if (r)
    203		goto err_mgr_enable;
    204
    205	r = hdmi_wp_video_start(&hdmi->wp);
    206	if (r)
    207		goto err_vid_enable;
    208
    209	hdmi_wp_set_irqenable(wp,
    210		HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
    211
    212	return 0;
    213
    214err_vid_enable:
    215	dss_mgr_disable(&hdmi->output);
    216err_mgr_enable:
    217	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
    218err_phy_pwr:
    219err_phy_cfg:
    220err_pll_cfg:
    221	dss_pll_disable(&hdmi->pll.pll);
    222err_pll_enable:
    223	hdmi_power_off_core(hdmi);
    224	return -EIO;
    225}
    226
    227static void hdmi_power_off_full(struct omap_hdmi *hdmi)
    228{
    229	hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE);
    230
    231	hdmi_wp_video_stop(&hdmi->wp);
    232
    233	dss_mgr_disable(&hdmi->output);
    234
    235	hdmi_wp_set_phy_pwr(&hdmi->wp, HDMI_PHYPWRCMD_OFF);
    236
    237	dss_pll_disable(&hdmi->pll.pll);
    238
    239	hdmi_power_off_core(hdmi);
    240}
    241
    242static int hdmi_dump_regs(struct seq_file *s, void *p)
    243{
    244	struct omap_hdmi *hdmi = s->private;
    245
    246	mutex_lock(&hdmi->lock);
    247
    248	if (hdmi_runtime_get(hdmi)) {
    249		mutex_unlock(&hdmi->lock);
    250		return 0;
    251	}
    252
    253	hdmi_wp_dump(&hdmi->wp, s);
    254	hdmi_pll_dump(&hdmi->pll, s);
    255	hdmi_phy_dump(&hdmi->phy, s);
    256	hdmi4_core_dump(&hdmi->core, s);
    257
    258	hdmi_runtime_put(hdmi);
    259	mutex_unlock(&hdmi->lock);
    260	return 0;
    261}
    262
    263static void hdmi_start_audio_stream(struct omap_hdmi *hd)
    264{
    265	hdmi_wp_audio_enable(&hd->wp, true);
    266	hdmi4_audio_start(&hd->core, &hd->wp);
    267}
    268
    269static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
    270{
    271	hdmi4_audio_stop(&hd->core, &hd->wp);
    272	hdmi_wp_audio_enable(&hd->wp, false);
    273}
    274
    275int hdmi4_core_enable(struct hdmi_core_data *core)
    276{
    277	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
    278	int r = 0;
    279
    280	DSSDBG("ENTER omapdss_hdmi4_core_enable\n");
    281
    282	mutex_lock(&hdmi->lock);
    283
    284	r = hdmi_power_on_core(hdmi);
    285	if (r) {
    286		DSSERR("failed to power on device\n");
    287		goto err0;
    288	}
    289
    290	mutex_unlock(&hdmi->lock);
    291	return 0;
    292
    293err0:
    294	mutex_unlock(&hdmi->lock);
    295	return r;
    296}
    297
    298void hdmi4_core_disable(struct hdmi_core_data *core)
    299{
    300	struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
    301
    302	DSSDBG("Enter omapdss_hdmi4_core_disable\n");
    303
    304	mutex_lock(&hdmi->lock);
    305
    306	hdmi_power_off_core(hdmi);
    307
    308	mutex_unlock(&hdmi->lock);
    309}
    310
    311/* -----------------------------------------------------------------------------
    312 * DRM Bridge Operations
    313 */
    314
    315static int hdmi4_bridge_attach(struct drm_bridge *bridge,
    316			       enum drm_bridge_attach_flags flags)
    317{
    318	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    319
    320	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
    321		return -EINVAL;
    322
    323	return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
    324				 bridge, flags);
    325}
    326
    327static void hdmi4_bridge_mode_set(struct drm_bridge *bridge,
    328				  const struct drm_display_mode *mode,
    329				  const struct drm_display_mode *adjusted_mode)
    330{
    331	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    332
    333	mutex_lock(&hdmi->lock);
    334
    335	drm_display_mode_to_videomode(adjusted_mode, &hdmi->cfg.vm);
    336
    337	dispc_set_tv_pclk(hdmi->dss->dispc, adjusted_mode->clock * 1000);
    338
    339	mutex_unlock(&hdmi->lock);
    340}
    341
    342static void hdmi4_bridge_enable(struct drm_bridge *bridge,
    343				struct drm_bridge_state *bridge_state)
    344{
    345	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    346	struct drm_atomic_state *state = bridge_state->base.state;
    347	struct drm_connector_state *conn_state;
    348	struct drm_connector *connector;
    349	struct drm_crtc_state *crtc_state;
    350	unsigned long flags;
    351	int ret;
    352
    353	/*
    354	 * None of these should fail, as the bridge can't be enabled without a
    355	 * valid CRTC to connector path with fully populated new states.
    356	 */
    357	connector = drm_atomic_get_new_connector_for_encoder(state,
    358							     bridge->encoder);
    359	if (WARN_ON(!connector))
    360		return;
    361	conn_state = drm_atomic_get_new_connector_state(state, connector);
    362	if (WARN_ON(!conn_state))
    363		return;
    364	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
    365	if (WARN_ON(!crtc_state))
    366		return;
    367
    368	hdmi->cfg.hdmi_dvi_mode = connector->display_info.is_hdmi
    369				? HDMI_HDMI : HDMI_DVI;
    370
    371	if (connector->display_info.is_hdmi) {
    372		const struct drm_display_mode *mode;
    373		struct hdmi_avi_infoframe avi;
    374
    375		mode = &crtc_state->adjusted_mode;
    376		ret = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
    377							       mode);
    378		if (ret == 0)
    379			hdmi->cfg.infoframe = avi;
    380	}
    381
    382	mutex_lock(&hdmi->lock);
    383
    384	ret = hdmi_power_on_full(hdmi);
    385	if (ret) {
    386		DSSERR("failed to power on device\n");
    387		goto done;
    388	}
    389
    390	if (hdmi->audio_configured) {
    391		ret = hdmi4_audio_config(&hdmi->core, &hdmi->wp,
    392					 &hdmi->audio_config,
    393					 hdmi->cfg.vm.pixelclock);
    394		if (ret) {
    395			DSSERR("Error restoring audio configuration: %d", ret);
    396			hdmi->audio_abort_cb(&hdmi->pdev->dev);
    397			hdmi->audio_configured = false;
    398		}
    399	}
    400
    401	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
    402	if (hdmi->audio_configured && hdmi->audio_playing)
    403		hdmi_start_audio_stream(hdmi);
    404	hdmi->display_enabled = true;
    405	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
    406
    407done:
    408	mutex_unlock(&hdmi->lock);
    409}
    410
    411static void hdmi4_bridge_disable(struct drm_bridge *bridge,
    412				 struct drm_bridge_state *bridge_state)
    413{
    414	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    415	unsigned long flags;
    416
    417	mutex_lock(&hdmi->lock);
    418
    419	spin_lock_irqsave(&hdmi->audio_playing_lock, flags);
    420	hdmi_stop_audio_stream(hdmi);
    421	hdmi->display_enabled = false;
    422	spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
    423
    424	hdmi_power_off_full(hdmi);
    425
    426	mutex_unlock(&hdmi->lock);
    427}
    428
    429static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
    430				    enum drm_connector_status status)
    431{
    432	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    433
    434	if (status == connector_status_disconnected)
    435		hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
    436}
    437
    438static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
    439					  struct drm_connector *connector)
    440{
    441	struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
    442	struct edid *edid = NULL;
    443	unsigned int cec_addr;
    444	bool need_enable;
    445	int r;
    446
    447	need_enable = hdmi->core_enabled == false;
    448
    449	if (need_enable) {
    450		r = hdmi4_core_enable(&hdmi->core);
    451		if (r)
    452			return NULL;
    453	}
    454
    455	mutex_lock(&hdmi->lock);
    456	r = hdmi_runtime_get(hdmi);
    457	BUG_ON(r);
    458
    459	r = hdmi4_core_ddc_init(&hdmi->core);
    460	if (r)
    461		goto done;
    462
    463	edid = drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core);
    464
    465done:
    466	hdmi_runtime_put(hdmi);
    467	mutex_unlock(&hdmi->lock);
    468
    469	if (edid && edid->extensions) {
    470		unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
    471
    472		cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
    473	} else {
    474		cec_addr = CEC_PHYS_ADDR_INVALID;
    475	}
    476
    477	hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
    478
    479	if (need_enable)
    480		hdmi4_core_disable(&hdmi->core);
    481
    482	return edid;
    483}
    484
    485static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
    486	.attach = hdmi4_bridge_attach,
    487	.mode_set = hdmi4_bridge_mode_set,
    488	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
    489	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
    490	.atomic_reset = drm_atomic_helper_bridge_reset,
    491	.atomic_enable = hdmi4_bridge_enable,
    492	.atomic_disable = hdmi4_bridge_disable,
    493	.hpd_notify = hdmi4_bridge_hpd_notify,
    494	.get_edid = hdmi4_bridge_get_edid,
    495};
    496
    497static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
    498{
    499	hdmi->bridge.funcs = &hdmi4_bridge_funcs;
    500	hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
    501	hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
    502	hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
    503
    504	drm_bridge_add(&hdmi->bridge);
    505}
    506
    507static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi)
    508{
    509	drm_bridge_remove(&hdmi->bridge);
    510}
    511
    512/* -----------------------------------------------------------------------------
    513 * Audio Callbacks
    514 */
    515
    516static int hdmi_audio_startup(struct device *dev,
    517			      void (*abort_cb)(struct device *dev))
    518{
    519	struct omap_hdmi *hd = dev_get_drvdata(dev);
    520
    521	mutex_lock(&hd->lock);
    522
    523	WARN_ON(hd->audio_abort_cb != NULL);
    524
    525	hd->audio_abort_cb = abort_cb;
    526
    527	mutex_unlock(&hd->lock);
    528
    529	return 0;
    530}
    531
    532static int hdmi_audio_shutdown(struct device *dev)
    533{
    534	struct omap_hdmi *hd = dev_get_drvdata(dev);
    535
    536	mutex_lock(&hd->lock);
    537	hd->audio_abort_cb = NULL;
    538	hd->audio_configured = false;
    539	hd->audio_playing = false;
    540	mutex_unlock(&hd->lock);
    541
    542	return 0;
    543}
    544
    545static int hdmi_audio_start(struct device *dev)
    546{
    547	struct omap_hdmi *hd = dev_get_drvdata(dev);
    548	unsigned long flags;
    549
    550	spin_lock_irqsave(&hd->audio_playing_lock, flags);
    551
    552	if (hd->display_enabled) {
    553		if (!hdmi_mode_has_audio(&hd->cfg))
    554			DSSERR("%s: Video mode does not support audio\n",
    555			       __func__);
    556		hdmi_start_audio_stream(hd);
    557	}
    558	hd->audio_playing = true;
    559
    560	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
    561	return 0;
    562}
    563
    564static void hdmi_audio_stop(struct device *dev)
    565{
    566	struct omap_hdmi *hd = dev_get_drvdata(dev);
    567	unsigned long flags;
    568
    569	WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
    570
    571	spin_lock_irqsave(&hd->audio_playing_lock, flags);
    572
    573	if (hd->display_enabled)
    574		hdmi_stop_audio_stream(hd);
    575	hd->audio_playing = false;
    576
    577	spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
    578}
    579
    580static int hdmi_audio_config(struct device *dev,
    581			     struct omap_dss_audio *dss_audio)
    582{
    583	struct omap_hdmi *hd = dev_get_drvdata(dev);
    584	int ret = 0;
    585
    586	mutex_lock(&hd->lock);
    587
    588	if (hd->display_enabled) {
    589		ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
    590					 hd->cfg.vm.pixelclock);
    591		if (ret)
    592			goto out;
    593	}
    594
    595	hd->audio_configured = true;
    596	hd->audio_config = *dss_audio;
    597out:
    598	mutex_unlock(&hd->lock);
    599
    600	return ret;
    601}
    602
    603static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
    604	.audio_startup = hdmi_audio_startup,
    605	.audio_shutdown = hdmi_audio_shutdown,
    606	.audio_start = hdmi_audio_start,
    607	.audio_stop = hdmi_audio_stop,
    608	.audio_config = hdmi_audio_config,
    609};
    610
    611static int hdmi_audio_register(struct omap_hdmi *hdmi)
    612{
    613	struct omap_hdmi_audio_pdata pdata = {
    614		.dev = &hdmi->pdev->dev,
    615		.version = 4,
    616		.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi->wp),
    617		.ops = &hdmi_audio_ops,
    618	};
    619
    620	hdmi->audio_pdev = platform_device_register_data(
    621		&hdmi->pdev->dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
    622		&pdata, sizeof(pdata));
    623
    624	if (IS_ERR(hdmi->audio_pdev))
    625		return PTR_ERR(hdmi->audio_pdev);
    626
    627	return 0;
    628}
    629
    630/* -----------------------------------------------------------------------------
    631 * Component Bind & Unbind
    632 */
    633
    634static int hdmi4_bind(struct device *dev, struct device *master, void *data)
    635{
    636	struct dss_device *dss = dss_get_device(master);
    637	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
    638	int r;
    639
    640	hdmi->dss = dss;
    641
    642	r = hdmi_runtime_get(hdmi);
    643	if (r)
    644		return r;
    645
    646	r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
    647	if (r)
    648		goto err_runtime_put;
    649
    650	r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
    651	if (r)
    652		goto err_pll_uninit;
    653
    654	r = hdmi_audio_register(hdmi);
    655	if (r) {
    656		DSSERR("Registering HDMI audio failed\n");
    657		goto err_cec_uninit;
    658	}
    659
    660	hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
    661					       hdmi);
    662
    663	hdmi_runtime_put(hdmi);
    664
    665	return 0;
    666
    667err_cec_uninit:
    668	hdmi4_cec_uninit(&hdmi->core);
    669err_pll_uninit:
    670	hdmi_pll_uninit(&hdmi->pll);
    671err_runtime_put:
    672	hdmi_runtime_put(hdmi);
    673	return r;
    674}
    675
    676static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
    677{
    678	struct omap_hdmi *hdmi = dev_get_drvdata(dev);
    679
    680	dss_debugfs_remove_file(hdmi->debugfs);
    681
    682	if (hdmi->audio_pdev)
    683		platform_device_unregister(hdmi->audio_pdev);
    684
    685	hdmi4_cec_uninit(&hdmi->core);
    686	hdmi_pll_uninit(&hdmi->pll);
    687}
    688
    689static const struct component_ops hdmi4_component_ops = {
    690	.bind	= hdmi4_bind,
    691	.unbind	= hdmi4_unbind,
    692};
    693
    694/* -----------------------------------------------------------------------------
    695 * Probe & Remove, Suspend & Resume
    696 */
    697
    698static int hdmi4_init_output(struct omap_hdmi *hdmi)
    699{
    700	struct omap_dss_device *out = &hdmi->output;
    701	int r;
    702
    703	hdmi4_bridge_init(hdmi);
    704
    705	out->dev = &hdmi->pdev->dev;
    706	out->id = OMAP_DSS_OUTPUT_HDMI;
    707	out->type = OMAP_DISPLAY_TYPE_HDMI;
    708	out->name = "hdmi.0";
    709	out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
    710	out->of_port = 0;
    711
    712	r = omapdss_device_init_output(out, &hdmi->bridge);
    713	if (r < 0) {
    714		hdmi4_bridge_cleanup(hdmi);
    715		return r;
    716	}
    717
    718	omapdss_device_register(out);
    719
    720	return 0;
    721}
    722
    723static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
    724{
    725	struct omap_dss_device *out = &hdmi->output;
    726
    727	omapdss_device_unregister(out);
    728	omapdss_device_cleanup_output(out);
    729
    730	hdmi4_bridge_cleanup(hdmi);
    731}
    732
    733static int hdmi4_probe_of(struct omap_hdmi *hdmi)
    734{
    735	struct platform_device *pdev = hdmi->pdev;
    736	struct device_node *node = pdev->dev.of_node;
    737	struct device_node *ep;
    738	int r;
    739
    740	ep = of_graph_get_endpoint_by_regs(node, 0, 0);
    741	if (!ep)
    742		return 0;
    743
    744	r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
    745	of_node_put(ep);
    746	return r;
    747}
    748
    749static int hdmi4_probe(struct platform_device *pdev)
    750{
    751	struct omap_hdmi *hdmi;
    752	int irq;
    753	int r;
    754
    755	hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
    756	if (!hdmi)
    757		return -ENOMEM;
    758
    759	hdmi->pdev = pdev;
    760
    761	dev_set_drvdata(&pdev->dev, hdmi);
    762
    763	mutex_init(&hdmi->lock);
    764	spin_lock_init(&hdmi->audio_playing_lock);
    765
    766	r = hdmi4_probe_of(hdmi);
    767	if (r)
    768		goto err_free;
    769
    770	r = hdmi_wp_init(pdev, &hdmi->wp, 4);
    771	if (r)
    772		goto err_free;
    773
    774	r = hdmi_phy_init(pdev, &hdmi->phy, 4);
    775	if (r)
    776		goto err_free;
    777
    778	r = hdmi4_core_init(pdev, &hdmi->core);
    779	if (r)
    780		goto err_free;
    781
    782	irq = platform_get_irq(pdev, 0);
    783	if (irq < 0) {
    784		DSSERR("platform_get_irq failed\n");
    785		r = -ENODEV;
    786		goto err_free;
    787	}
    788
    789	r = devm_request_threaded_irq(&pdev->dev, irq,
    790			NULL, hdmi_irq_handler,
    791			IRQF_ONESHOT, "OMAP HDMI", hdmi);
    792	if (r) {
    793		DSSERR("HDMI IRQ request failed\n");
    794		goto err_free;
    795	}
    796
    797	hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
    798	if (IS_ERR(hdmi->vdda_reg)) {
    799		r = PTR_ERR(hdmi->vdda_reg);
    800		if (r != -EPROBE_DEFER)
    801			DSSERR("can't get VDDA regulator\n");
    802		goto err_free;
    803	}
    804
    805	pm_runtime_enable(&pdev->dev);
    806
    807	r = hdmi4_init_output(hdmi);
    808	if (r)
    809		goto err_pm_disable;
    810
    811	r = component_add(&pdev->dev, &hdmi4_component_ops);
    812	if (r)
    813		goto err_uninit_output;
    814
    815	return 0;
    816
    817err_uninit_output:
    818	hdmi4_uninit_output(hdmi);
    819err_pm_disable:
    820	pm_runtime_disable(&pdev->dev);
    821err_free:
    822	kfree(hdmi);
    823	return r;
    824}
    825
    826static int hdmi4_remove(struct platform_device *pdev)
    827{
    828	struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
    829
    830	component_del(&pdev->dev, &hdmi4_component_ops);
    831
    832	hdmi4_uninit_output(hdmi);
    833
    834	pm_runtime_disable(&pdev->dev);
    835
    836	kfree(hdmi);
    837	return 0;
    838}
    839
    840static const struct of_device_id hdmi_of_match[] = {
    841	{ .compatible = "ti,omap4-hdmi", },
    842	{},
    843};
    844
    845struct platform_driver omapdss_hdmi4hw_driver = {
    846	.probe		= hdmi4_probe,
    847	.remove		= hdmi4_remove,
    848	.driver         = {
    849		.name   = "omapdss_hdmi",
    850		.of_match_table = hdmi_of_match,
    851		.suppress_bind_attrs = true,
    852	},
    853};