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

dpi.c (18414B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/drivers/video/omap2/dss/dpi.c
      4 *
      5 * Copyright (C) 2009 Nokia Corporation
      6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
      7 *
      8 * Some code and ideas taken from drivers/video/omap/ driver
      9 * by Imre Deak.
     10 */
     11
     12#define DSS_SUBSYS_NAME "DPI"
     13
     14#include <linux/kernel.h>
     15#include <linux/delay.h>
     16#include <linux/export.h>
     17#include <linux/err.h>
     18#include <linux/errno.h>
     19#include <linux/platform_device.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/string.h>
     22#include <linux/of.h>
     23#include <linux/clk.h>
     24#include <linux/component.h>
     25
     26#include <video/omapfb_dss.h>
     27
     28#include "dss.h"
     29#include "dss_features.h"
     30
     31#define HSDIV_DISPC	0
     32
     33struct dpi_data {
     34	struct platform_device *pdev;
     35
     36	struct regulator *vdds_dsi_reg;
     37	struct dss_pll *pll;
     38
     39	struct mutex lock;
     40
     41	struct omap_video_timings timings;
     42	struct dss_lcd_mgr_config mgr_config;
     43	int data_lines;
     44
     45	struct omap_dss_device output;
     46
     47	bool port_initialized;
     48};
     49
     50static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
     51{
     52	return container_of(dssdev, struct dpi_data, output);
     53}
     54
     55/* only used in non-DT mode */
     56static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
     57{
     58	return platform_get_drvdata(pdev);
     59}
     60
     61static struct dss_pll *dpi_get_pll(enum omap_channel channel)
     62{
     63	/*
     64	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
     65	 * would also be used for DISPC fclk. Meaning, when the DPI output is
     66	 * disabled, DISPC clock will be disabled, and TV out will stop.
     67	 */
     68	switch (omapdss_get_version()) {
     69	case OMAPDSS_VER_OMAP24xx:
     70	case OMAPDSS_VER_OMAP34xx_ES1:
     71	case OMAPDSS_VER_OMAP34xx_ES3:
     72	case OMAPDSS_VER_OMAP3630:
     73	case OMAPDSS_VER_AM35xx:
     74	case OMAPDSS_VER_AM43xx:
     75		return NULL;
     76
     77	case OMAPDSS_VER_OMAP4430_ES1:
     78	case OMAPDSS_VER_OMAP4430_ES2:
     79	case OMAPDSS_VER_OMAP4:
     80		switch (channel) {
     81		case OMAP_DSS_CHANNEL_LCD:
     82			return dss_pll_find("dsi0");
     83		case OMAP_DSS_CHANNEL_LCD2:
     84			return dss_pll_find("dsi1");
     85		default:
     86			return NULL;
     87		}
     88
     89	case OMAPDSS_VER_OMAP5:
     90		switch (channel) {
     91		case OMAP_DSS_CHANNEL_LCD:
     92			return dss_pll_find("dsi0");
     93		case OMAP_DSS_CHANNEL_LCD3:
     94			return dss_pll_find("dsi1");
     95		default:
     96			return NULL;
     97		}
     98
     99	case OMAPDSS_VER_DRA7xx:
    100		switch (channel) {
    101		case OMAP_DSS_CHANNEL_LCD:
    102		case OMAP_DSS_CHANNEL_LCD2:
    103			return dss_pll_find("video0");
    104		case OMAP_DSS_CHANNEL_LCD3:
    105			return dss_pll_find("video1");
    106		default:
    107			return NULL;
    108		}
    109
    110	default:
    111		return NULL;
    112	}
    113}
    114
    115static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
    116{
    117	switch (channel) {
    118	case OMAP_DSS_CHANNEL_LCD:
    119		return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
    120	case OMAP_DSS_CHANNEL_LCD2:
    121		return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
    122	case OMAP_DSS_CHANNEL_LCD3:
    123		return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
    124	default:
    125		/* this shouldn't happen */
    126		WARN_ON(1);
    127		return OMAP_DSS_CLK_SRC_FCK;
    128	}
    129}
    130
    131struct dpi_clk_calc_ctx {
    132	struct dss_pll *pll;
    133
    134	/* inputs */
    135
    136	unsigned long pck_min, pck_max;
    137
    138	/* outputs */
    139
    140	struct dss_pll_clock_info dsi_cinfo;
    141	unsigned long fck;
    142	struct dispc_clock_info dispc_cinfo;
    143};
    144
    145static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
    146		unsigned long pck, void *data)
    147{
    148	struct dpi_clk_calc_ctx *ctx = data;
    149
    150	/*
    151	 * Odd dividers give us uneven duty cycle, causing problem when level
    152	 * shifted. So skip all odd dividers when the pixel clock is on the
    153	 * higher side.
    154	 */
    155	if (ctx->pck_min >= 100000000) {
    156		if (lckd > 1 && lckd % 2 != 0)
    157			return false;
    158
    159		if (pckd > 1 && pckd % 2 != 0)
    160			return false;
    161	}
    162
    163	ctx->dispc_cinfo.lck_div = lckd;
    164	ctx->dispc_cinfo.pck_div = pckd;
    165	ctx->dispc_cinfo.lck = lck;
    166	ctx->dispc_cinfo.pck = pck;
    167
    168	return true;
    169}
    170
    171
    172static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
    173		void *data)
    174{
    175	struct dpi_clk_calc_ctx *ctx = data;
    176
    177	/*
    178	 * Odd dividers give us uneven duty cycle, causing problem when level
    179	 * shifted. So skip all odd dividers when the pixel clock is on the
    180	 * higher side.
    181	 */
    182	if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
    183		return false;
    184
    185	ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
    186	ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
    187
    188	return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
    189			dpi_calc_dispc_cb, ctx);
    190}
    191
    192
    193static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
    194		unsigned long clkdco,
    195		void *data)
    196{
    197	struct dpi_clk_calc_ctx *ctx = data;
    198
    199	ctx->dsi_cinfo.n = n;
    200	ctx->dsi_cinfo.m = m;
    201	ctx->dsi_cinfo.fint = fint;
    202	ctx->dsi_cinfo.clkdco = clkdco;
    203
    204	return dss_pll_hsdiv_calc(ctx->pll, clkdco,
    205		ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
    206		dpi_calc_hsdiv_cb, ctx);
    207}
    208
    209static bool dpi_calc_dss_cb(unsigned long fck, void *data)
    210{
    211	struct dpi_clk_calc_ctx *ctx = data;
    212
    213	ctx->fck = fck;
    214
    215	return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
    216			dpi_calc_dispc_cb, ctx);
    217}
    218
    219static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
    220		struct dpi_clk_calc_ctx *ctx)
    221{
    222	unsigned long clkin;
    223	unsigned long pll_min, pll_max;
    224
    225	memset(ctx, 0, sizeof(*ctx));
    226	ctx->pll = dpi->pll;
    227	ctx->pck_min = pck - 1000;
    228	ctx->pck_max = pck + 1000;
    229
    230	pll_min = 0;
    231	pll_max = 0;
    232
    233	clkin = clk_get_rate(ctx->pll->clkin);
    234
    235	return dss_pll_calc(ctx->pll, clkin,
    236			pll_min, pll_max,
    237			dpi_calc_pll_cb, ctx);
    238}
    239
    240static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
    241{
    242	int i;
    243
    244	/*
    245	 * DSS fck gives us very few possibilities, so finding a good pixel
    246	 * clock may not be possible. We try multiple times to find the clock,
    247	 * each time widening the pixel clock range we look for, up to
    248	 * +/- ~15MHz.
    249	 */
    250
    251	for (i = 0; i < 25; ++i) {
    252		bool ok;
    253
    254		memset(ctx, 0, sizeof(*ctx));
    255		if (pck > 1000 * i * i * i)
    256			ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
    257		else
    258			ctx->pck_min = 0;
    259		ctx->pck_max = pck + 1000 * i * i * i;
    260
    261		ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
    262		if (ok)
    263			return ok;
    264	}
    265
    266	return false;
    267}
    268
    269
    270
    271static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
    272		unsigned long pck_req, unsigned long *fck, int *lck_div,
    273		int *pck_div)
    274{
    275	struct dpi_clk_calc_ctx ctx;
    276	int r;
    277	bool ok;
    278
    279	ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
    280	if (!ok)
    281		return -EINVAL;
    282
    283	r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
    284	if (r)
    285		return r;
    286
    287	dss_select_lcd_clk_source(channel,
    288			dpi_get_alt_clk_src(channel));
    289
    290	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
    291
    292	*fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
    293	*lck_div = ctx.dispc_cinfo.lck_div;
    294	*pck_div = ctx.dispc_cinfo.pck_div;
    295
    296	return 0;
    297}
    298
    299static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
    300		unsigned long *fck, int *lck_div, int *pck_div)
    301{
    302	struct dpi_clk_calc_ctx ctx;
    303	int r;
    304	bool ok;
    305
    306	ok = dpi_dss_clk_calc(pck_req, &ctx);
    307	if (!ok)
    308		return -EINVAL;
    309
    310	r = dss_set_fck_rate(ctx.fck);
    311	if (r)
    312		return r;
    313
    314	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
    315
    316	*fck = ctx.fck;
    317	*lck_div = ctx.dispc_cinfo.lck_div;
    318	*pck_div = ctx.dispc_cinfo.pck_div;
    319
    320	return 0;
    321}
    322
    323static int dpi_set_mode(struct dpi_data *dpi)
    324{
    325	struct omap_dss_device *out = &dpi->output;
    326	struct omap_overlay_manager *mgr = out->manager;
    327	struct omap_video_timings *t = &dpi->timings;
    328	int lck_div = 0, pck_div = 0;
    329	unsigned long fck = 0;
    330	unsigned long pck;
    331	int r = 0;
    332
    333	if (dpi->pll)
    334		r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
    335				&lck_div, &pck_div);
    336	else
    337		r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
    338				&lck_div, &pck_div);
    339	if (r)
    340		return r;
    341
    342	pck = fck / lck_div / pck_div;
    343
    344	if (pck != t->pixelclock) {
    345		DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
    346			t->pixelclock, pck);
    347
    348		t->pixelclock = pck;
    349	}
    350
    351	dss_mgr_set_timings(mgr, t);
    352
    353	return 0;
    354}
    355
    356static void dpi_config_lcd_manager(struct dpi_data *dpi)
    357{
    358	struct omap_dss_device *out = &dpi->output;
    359	struct omap_overlay_manager *mgr = out->manager;
    360
    361	dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
    362
    363	dpi->mgr_config.stallmode = false;
    364	dpi->mgr_config.fifohandcheck = false;
    365
    366	dpi->mgr_config.video_port_width = dpi->data_lines;
    367
    368	dpi->mgr_config.lcden_sig_polarity = 0;
    369
    370	dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
    371}
    372
    373static int dpi_display_enable(struct omap_dss_device *dssdev)
    374{
    375	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    376	struct omap_dss_device *out = &dpi->output;
    377	int r;
    378
    379	mutex_lock(&dpi->lock);
    380
    381	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
    382		DSSERR("no VDSS_DSI regulator\n");
    383		r = -ENODEV;
    384		goto err_no_reg;
    385	}
    386
    387	if (out->manager == NULL) {
    388		DSSERR("failed to enable display: no output/manager\n");
    389		r = -ENODEV;
    390		goto err_no_out_mgr;
    391	}
    392
    393	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
    394		r = regulator_enable(dpi->vdds_dsi_reg);
    395		if (r)
    396			goto err_reg_enable;
    397	}
    398
    399	r = dispc_runtime_get();
    400	if (r)
    401		goto err_get_dispc;
    402
    403	r = dss_dpi_select_source(out->port_num, out->manager->id);
    404	if (r)
    405		goto err_src_sel;
    406
    407	if (dpi->pll) {
    408		r = dss_pll_enable(dpi->pll);
    409		if (r)
    410			goto err_dsi_pll_init;
    411	}
    412
    413	r = dpi_set_mode(dpi);
    414	if (r)
    415		goto err_set_mode;
    416
    417	dpi_config_lcd_manager(dpi);
    418
    419	mdelay(2);
    420
    421	r = dss_mgr_enable(out->manager);
    422	if (r)
    423		goto err_mgr_enable;
    424
    425	mutex_unlock(&dpi->lock);
    426
    427	return 0;
    428
    429err_mgr_enable:
    430err_set_mode:
    431	if (dpi->pll)
    432		dss_pll_disable(dpi->pll);
    433err_dsi_pll_init:
    434err_src_sel:
    435	dispc_runtime_put();
    436err_get_dispc:
    437	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
    438		regulator_disable(dpi->vdds_dsi_reg);
    439err_reg_enable:
    440err_no_out_mgr:
    441err_no_reg:
    442	mutex_unlock(&dpi->lock);
    443	return r;
    444}
    445
    446static void dpi_display_disable(struct omap_dss_device *dssdev)
    447{
    448	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    449	struct omap_overlay_manager *mgr = dpi->output.manager;
    450
    451	mutex_lock(&dpi->lock);
    452
    453	dss_mgr_disable(mgr);
    454
    455	if (dpi->pll) {
    456		dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
    457		dss_pll_disable(dpi->pll);
    458	}
    459
    460	dispc_runtime_put();
    461
    462	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
    463		regulator_disable(dpi->vdds_dsi_reg);
    464
    465	mutex_unlock(&dpi->lock);
    466}
    467
    468static void dpi_set_timings(struct omap_dss_device *dssdev,
    469		struct omap_video_timings *timings)
    470{
    471	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    472
    473	DSSDBG("dpi_set_timings\n");
    474
    475	mutex_lock(&dpi->lock);
    476
    477	dpi->timings = *timings;
    478
    479	mutex_unlock(&dpi->lock);
    480}
    481
    482static void dpi_get_timings(struct omap_dss_device *dssdev,
    483		struct omap_video_timings *timings)
    484{
    485	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    486
    487	mutex_lock(&dpi->lock);
    488
    489	*timings = dpi->timings;
    490
    491	mutex_unlock(&dpi->lock);
    492}
    493
    494static int dpi_check_timings(struct omap_dss_device *dssdev,
    495			struct omap_video_timings *timings)
    496{
    497	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    498	struct omap_overlay_manager *mgr = dpi->output.manager;
    499	int lck_div, pck_div;
    500	unsigned long fck;
    501	unsigned long pck;
    502	struct dpi_clk_calc_ctx ctx;
    503	bool ok;
    504
    505	if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
    506		return -EINVAL;
    507
    508	if (timings->pixelclock == 0)
    509		return -EINVAL;
    510
    511	if (dpi->pll) {
    512		ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
    513		if (!ok)
    514			return -EINVAL;
    515
    516		fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
    517	} else {
    518		ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
    519		if (!ok)
    520			return -EINVAL;
    521
    522		fck = ctx.fck;
    523	}
    524
    525	lck_div = ctx.dispc_cinfo.lck_div;
    526	pck_div = ctx.dispc_cinfo.pck_div;
    527
    528	pck = fck / lck_div / pck_div;
    529
    530	timings->pixelclock = pck;
    531
    532	return 0;
    533}
    534
    535static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
    536{
    537	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    538
    539	mutex_lock(&dpi->lock);
    540
    541	dpi->data_lines = data_lines;
    542
    543	mutex_unlock(&dpi->lock);
    544}
    545
    546static int dpi_verify_dsi_pll(struct dss_pll *pll)
    547{
    548	int r;
    549
    550	/* do initial setup with the PLL to see if it is operational */
    551
    552	r = dss_pll_enable(pll);
    553	if (r)
    554		return r;
    555
    556	dss_pll_disable(pll);
    557
    558	return 0;
    559}
    560
    561static int dpi_init_regulator(struct dpi_data *dpi)
    562{
    563	struct regulator *vdds_dsi;
    564
    565	if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
    566		return 0;
    567
    568	if (dpi->vdds_dsi_reg)
    569		return 0;
    570
    571	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
    572	if (IS_ERR(vdds_dsi)) {
    573		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
    574			DSSERR("can't get VDDS_DSI regulator\n");
    575		return PTR_ERR(vdds_dsi);
    576	}
    577
    578	dpi->vdds_dsi_reg = vdds_dsi;
    579
    580	return 0;
    581}
    582
    583static void dpi_init_pll(struct dpi_data *dpi)
    584{
    585	struct dss_pll *pll;
    586
    587	if (dpi->pll)
    588		return;
    589
    590	pll = dpi_get_pll(dpi->output.dispc_channel);
    591	if (!pll)
    592		return;
    593
    594	/* On DRA7 we need to set a mux to use the PLL */
    595	if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
    596		dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
    597
    598	if (dpi_verify_dsi_pll(pll)) {
    599		DSSWARN("DSI PLL not operational\n");
    600		return;
    601	}
    602
    603	dpi->pll = pll;
    604}
    605
    606/*
    607 * Return a hardcoded channel for the DPI output. This should work for
    608 * current use cases, but this can be later expanded to either resolve
    609 * the channel in some more dynamic manner, or get the channel as a user
    610 * parameter.
    611 */
    612static enum omap_channel dpi_get_channel(int port_num)
    613{
    614	switch (omapdss_get_version()) {
    615	case OMAPDSS_VER_OMAP24xx:
    616	case OMAPDSS_VER_OMAP34xx_ES1:
    617	case OMAPDSS_VER_OMAP34xx_ES3:
    618	case OMAPDSS_VER_OMAP3630:
    619	case OMAPDSS_VER_AM35xx:
    620	case OMAPDSS_VER_AM43xx:
    621		return OMAP_DSS_CHANNEL_LCD;
    622
    623	case OMAPDSS_VER_DRA7xx:
    624		switch (port_num) {
    625		case 2:
    626			return OMAP_DSS_CHANNEL_LCD3;
    627		case 1:
    628			return OMAP_DSS_CHANNEL_LCD2;
    629		case 0:
    630		default:
    631			return OMAP_DSS_CHANNEL_LCD;
    632		}
    633
    634	case OMAPDSS_VER_OMAP4430_ES1:
    635	case OMAPDSS_VER_OMAP4430_ES2:
    636	case OMAPDSS_VER_OMAP4:
    637		return OMAP_DSS_CHANNEL_LCD2;
    638
    639	case OMAPDSS_VER_OMAP5:
    640		return OMAP_DSS_CHANNEL_LCD3;
    641
    642	default:
    643		DSSWARN("unsupported DSS version\n");
    644		return OMAP_DSS_CHANNEL_LCD;
    645	}
    646}
    647
    648static int dpi_connect(struct omap_dss_device *dssdev,
    649		struct omap_dss_device *dst)
    650{
    651	struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
    652	struct omap_overlay_manager *mgr;
    653	int r;
    654
    655	r = dpi_init_regulator(dpi);
    656	if (r)
    657		return r;
    658
    659	dpi_init_pll(dpi);
    660
    661	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
    662	if (!mgr)
    663		return -ENODEV;
    664
    665	r = dss_mgr_connect(mgr, dssdev);
    666	if (r)
    667		return r;
    668
    669	r = omapdss_output_set_device(dssdev, dst);
    670	if (r) {
    671		DSSERR("failed to connect output to new device: %s\n",
    672				dst->name);
    673		dss_mgr_disconnect(mgr, dssdev);
    674		return r;
    675	}
    676
    677	return 0;
    678}
    679
    680static void dpi_disconnect(struct omap_dss_device *dssdev,
    681		struct omap_dss_device *dst)
    682{
    683	WARN_ON(dst != dssdev->dst);
    684
    685	if (dst != dssdev->dst)
    686		return;
    687
    688	omapdss_output_unset_device(dssdev);
    689
    690	if (dssdev->manager)
    691		dss_mgr_disconnect(dssdev->manager, dssdev);
    692}
    693
    694static const struct omapdss_dpi_ops dpi_ops = {
    695	.connect = dpi_connect,
    696	.disconnect = dpi_disconnect,
    697
    698	.enable = dpi_display_enable,
    699	.disable = dpi_display_disable,
    700
    701	.check_timings = dpi_check_timings,
    702	.set_timings = dpi_set_timings,
    703	.get_timings = dpi_get_timings,
    704
    705	.set_data_lines = dpi_set_data_lines,
    706};
    707
    708static void dpi_init_output(struct platform_device *pdev)
    709{
    710	struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
    711	struct omap_dss_device *out = &dpi->output;
    712
    713	out->dev = &pdev->dev;
    714	out->id = OMAP_DSS_OUTPUT_DPI;
    715	out->output_type = OMAP_DISPLAY_TYPE_DPI;
    716	out->name = "dpi.0";
    717	out->dispc_channel = dpi_get_channel(0);
    718	out->ops.dpi = &dpi_ops;
    719	out->owner = THIS_MODULE;
    720
    721	omapdss_register_output(out);
    722}
    723
    724static void dpi_uninit_output(struct platform_device *pdev)
    725{
    726	struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
    727	struct omap_dss_device *out = &dpi->output;
    728
    729	omapdss_unregister_output(out);
    730}
    731
    732static void dpi_init_output_port(struct platform_device *pdev,
    733	struct device_node *port)
    734{
    735	struct dpi_data *dpi = port->data;
    736	struct omap_dss_device *out = &dpi->output;
    737	int r;
    738	u32 port_num;
    739
    740	r = of_property_read_u32(port, "reg", &port_num);
    741	if (r)
    742		port_num = 0;
    743
    744	switch (port_num) {
    745	case 2:
    746		out->name = "dpi.2";
    747		break;
    748	case 1:
    749		out->name = "dpi.1";
    750		break;
    751	case 0:
    752	default:
    753		out->name = "dpi.0";
    754		break;
    755	}
    756
    757	out->dev = &pdev->dev;
    758	out->id = OMAP_DSS_OUTPUT_DPI;
    759	out->output_type = OMAP_DISPLAY_TYPE_DPI;
    760	out->dispc_channel = dpi_get_channel(port_num);
    761	out->port_num = port_num;
    762	out->ops.dpi = &dpi_ops;
    763	out->owner = THIS_MODULE;
    764
    765	omapdss_register_output(out);
    766}
    767
    768static void dpi_uninit_output_port(struct device_node *port)
    769{
    770	struct dpi_data *dpi = port->data;
    771	struct omap_dss_device *out = &dpi->output;
    772
    773	omapdss_unregister_output(out);
    774}
    775
    776static int dpi_bind(struct device *dev, struct device *master, void *data)
    777{
    778	struct platform_device *pdev = to_platform_device(dev);
    779	struct dpi_data *dpi;
    780
    781	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
    782	if (!dpi)
    783		return -ENOMEM;
    784
    785	dpi->pdev = pdev;
    786
    787	platform_set_drvdata(pdev, dpi);
    788
    789	mutex_init(&dpi->lock);
    790
    791	dpi_init_output(pdev);
    792
    793	return 0;
    794}
    795
    796static void dpi_unbind(struct device *dev, struct device *master, void *data)
    797{
    798	struct platform_device *pdev = to_platform_device(dev);
    799
    800	dpi_uninit_output(pdev);
    801}
    802
    803static const struct component_ops dpi_component_ops = {
    804	.bind	= dpi_bind,
    805	.unbind	= dpi_unbind,
    806};
    807
    808static int dpi_probe(struct platform_device *pdev)
    809{
    810	return component_add(&pdev->dev, &dpi_component_ops);
    811}
    812
    813static int dpi_remove(struct platform_device *pdev)
    814{
    815	component_del(&pdev->dev, &dpi_component_ops);
    816	return 0;
    817}
    818
    819static struct platform_driver omap_dpi_driver = {
    820	.probe		= dpi_probe,
    821	.remove		= dpi_remove,
    822	.driver         = {
    823		.name   = "omapdss_dpi",
    824		.suppress_bind_attrs = true,
    825	},
    826};
    827
    828int __init dpi_init_platform_driver(void)
    829{
    830	return platform_driver_register(&omap_dpi_driver);
    831}
    832
    833void dpi_uninit_platform_driver(void)
    834{
    835	platform_driver_unregister(&omap_dpi_driver);
    836}
    837
    838int dpi_init_port(struct platform_device *pdev, struct device_node *port)
    839{
    840	struct dpi_data *dpi;
    841	struct device_node *ep;
    842	u32 datalines;
    843	int r;
    844
    845	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
    846	if (!dpi)
    847		return -ENOMEM;
    848
    849	ep = omapdss_of_get_next_endpoint(port, NULL);
    850	if (!ep)
    851		return 0;
    852
    853	r = of_property_read_u32(ep, "data-lines", &datalines);
    854	if (r) {
    855		DSSERR("failed to parse datalines\n");
    856		goto err_datalines;
    857	}
    858
    859	dpi->data_lines = datalines;
    860
    861	of_node_put(ep);
    862
    863	dpi->pdev = pdev;
    864	port->data = dpi;
    865
    866	mutex_init(&dpi->lock);
    867
    868	dpi_init_output_port(pdev, port);
    869
    870	dpi->port_initialized = true;
    871
    872	return 0;
    873
    874err_datalines:
    875	of_node_put(ep);
    876
    877	return r;
    878}
    879
    880void dpi_uninit_port(struct device_node *port)
    881{
    882	struct dpi_data *dpi = port->data;
    883
    884	if (!dpi->port_initialized)
    885		return;
    886
    887	dpi_uninit_output_port(port);
    888}