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 (15587B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2009 Nokia Corporation
      4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      5 *
      6 * Some code and ideas taken from drivers/video/omap/ driver
      7 * by Imre Deak.
      8 */
      9
     10#define DSS_SUBSYS_NAME "DPI"
     11
     12#include <linux/clk.h>
     13#include <linux/delay.h>
     14#include <linux/err.h>
     15#include <linux/errno.h>
     16#include <linux/export.h>
     17#include <linux/kernel.h>
     18#include <linux/of.h>
     19#include <linux/platform_device.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/string.h>
     22#include <linux/sys_soc.h>
     23
     24#include <drm/drm_bridge.h>
     25
     26#include "dss.h"
     27#include "omapdss.h"
     28
     29struct dpi_data {
     30	struct platform_device *pdev;
     31	enum dss_model dss_model;
     32	struct dss_device *dss;
     33	unsigned int id;
     34
     35	struct regulator *vdds_dsi_reg;
     36	enum dss_clk_source clk_src;
     37	struct dss_pll *pll;
     38
     39	struct dss_lcd_mgr_config mgr_config;
     40	unsigned long pixelclock;
     41	int data_lines;
     42
     43	struct omap_dss_device output;
     44	struct drm_bridge bridge;
     45};
     46
     47#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
     48
     49/* -----------------------------------------------------------------------------
     50 * Clock Handling and PLL
     51 */
     52
     53static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,
     54						  enum omap_channel channel)
     55{
     56	/*
     57	 * Possible clock sources:
     58	 * LCD1: FCK/PLL1_1/HDMI_PLL
     59	 * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)
     60	 * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)
     61	 */
     62
     63	switch (channel) {
     64	case OMAP_DSS_CHANNEL_LCD:
     65	{
     66		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))
     67			return DSS_CLK_SRC_PLL1_1;
     68		break;
     69	}
     70	case OMAP_DSS_CHANNEL_LCD2:
     71	{
     72		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
     73			return DSS_CLK_SRC_PLL1_3;
     74		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))
     75			return DSS_CLK_SRC_PLL2_3;
     76		break;
     77	}
     78	case OMAP_DSS_CHANNEL_LCD3:
     79	{
     80		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))
     81			return DSS_CLK_SRC_PLL2_1;
     82		if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
     83			return DSS_CLK_SRC_PLL1_3;
     84		break;
     85	}
     86	default:
     87		break;
     88	}
     89
     90	return DSS_CLK_SRC_FCK;
     91}
     92
     93static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)
     94{
     95	enum omap_channel channel = dpi->output.dispc_channel;
     96
     97	/*
     98	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
     99	 * would also be used for DISPC fclk. Meaning, when the DPI output is
    100	 * disabled, DISPC clock will be disabled, and TV out will stop.
    101	 */
    102	switch (dpi->dss_model) {
    103	case DSS_MODEL_OMAP2:
    104	case DSS_MODEL_OMAP3:
    105		return DSS_CLK_SRC_FCK;
    106
    107	case DSS_MODEL_OMAP4:
    108		switch (channel) {
    109		case OMAP_DSS_CHANNEL_LCD:
    110			return DSS_CLK_SRC_PLL1_1;
    111		case OMAP_DSS_CHANNEL_LCD2:
    112			return DSS_CLK_SRC_PLL2_1;
    113		default:
    114			return DSS_CLK_SRC_FCK;
    115		}
    116
    117	case DSS_MODEL_OMAP5:
    118		switch (channel) {
    119		case OMAP_DSS_CHANNEL_LCD:
    120			return DSS_CLK_SRC_PLL1_1;
    121		case OMAP_DSS_CHANNEL_LCD3:
    122			return DSS_CLK_SRC_PLL2_1;
    123		case OMAP_DSS_CHANNEL_LCD2:
    124		default:
    125			return DSS_CLK_SRC_FCK;
    126		}
    127
    128	case DSS_MODEL_DRA7:
    129		return dpi_get_clk_src_dra7xx(dpi, channel);
    130
    131	default:
    132		return DSS_CLK_SRC_FCK;
    133	}
    134}
    135
    136struct dpi_clk_calc_ctx {
    137	struct dpi_data *dpi;
    138	unsigned int clkout_idx;
    139
    140	/* inputs */
    141
    142	unsigned long pck_min, pck_max;
    143
    144	/* outputs */
    145
    146	struct dss_pll_clock_info pll_cinfo;
    147	unsigned long fck;
    148	struct dispc_clock_info dispc_cinfo;
    149};
    150
    151static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
    152		unsigned long pck, void *data)
    153{
    154	struct dpi_clk_calc_ctx *ctx = data;
    155
    156	/*
    157	 * Odd dividers give us uneven duty cycle, causing problem when level
    158	 * shifted. So skip all odd dividers when the pixel clock is on the
    159	 * higher side.
    160	 */
    161	if (ctx->pck_min >= 100000000) {
    162		if (lckd > 1 && lckd % 2 != 0)
    163			return false;
    164
    165		if (pckd > 1 && pckd % 2 != 0)
    166			return false;
    167	}
    168
    169	ctx->dispc_cinfo.lck_div = lckd;
    170	ctx->dispc_cinfo.pck_div = pckd;
    171	ctx->dispc_cinfo.lck = lck;
    172	ctx->dispc_cinfo.pck = pck;
    173
    174	return true;
    175}
    176
    177
    178static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
    179		void *data)
    180{
    181	struct dpi_clk_calc_ctx *ctx = data;
    182
    183	ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;
    184	ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;
    185
    186	return dispc_div_calc(ctx->dpi->dss->dispc, dispc,
    187			      ctx->pck_min, ctx->pck_max,
    188			      dpi_calc_dispc_cb, ctx);
    189}
    190
    191
    192static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
    193		unsigned long clkdco,
    194		void *data)
    195{
    196	struct dpi_clk_calc_ctx *ctx = data;
    197
    198	ctx->pll_cinfo.n = n;
    199	ctx->pll_cinfo.m = m;
    200	ctx->pll_cinfo.fint = fint;
    201	ctx->pll_cinfo.clkdco = clkdco;
    202
    203	return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,
    204		ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),
    205		dpi_calc_hsdiv_cb, ctx);
    206}
    207
    208static bool dpi_calc_dss_cb(unsigned long fck, void *data)
    209{
    210	struct dpi_clk_calc_ctx *ctx = data;
    211
    212	ctx->fck = fck;
    213
    214	return dispc_div_calc(ctx->dpi->dss->dispc, fck,
    215			      ctx->pck_min, ctx->pck_max,
    216			      dpi_calc_dispc_cb, ctx);
    217}
    218
    219static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,
    220		struct dpi_clk_calc_ctx *ctx)
    221{
    222	unsigned long clkin;
    223
    224	memset(ctx, 0, sizeof(*ctx));
    225	ctx->dpi = dpi;
    226	ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
    227
    228	clkin = clk_get_rate(dpi->pll->clkin);
    229
    230	if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
    231		unsigned long pll_min, pll_max;
    232
    233		ctx->pck_min = pck - 1000;
    234		ctx->pck_max = pck + 1000;
    235
    236		pll_min = 0;
    237		pll_max = 0;
    238
    239		return dss_pll_calc_a(ctx->dpi->pll, clkin,
    240				pll_min, pll_max,
    241				dpi_calc_pll_cb, ctx);
    242	} else { /* DSS_PLL_TYPE_B */
    243		dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);
    244
    245		ctx->dispc_cinfo.lck_div = 1;
    246		ctx->dispc_cinfo.pck_div = 1;
    247		ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];
    248		ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
    249
    250		return true;
    251	}
    252}
    253
    254static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,
    255			     struct dpi_clk_calc_ctx *ctx)
    256{
    257	int i;
    258
    259	/*
    260	 * DSS fck gives us very few possibilities, so finding a good pixel
    261	 * clock may not be possible. We try multiple times to find the clock,
    262	 * each time widening the pixel clock range we look for, up to
    263	 * +/- ~15MHz.
    264	 */
    265
    266	for (i = 0; i < 25; ++i) {
    267		bool ok;
    268
    269		memset(ctx, 0, sizeof(*ctx));
    270		ctx->dpi = dpi;
    271		if (pck > 1000 * i * i * i)
    272			ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
    273		else
    274			ctx->pck_min = 0;
    275		ctx->pck_max = pck + 1000 * i * i * i;
    276
    277		ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,
    278				  dpi_calc_dss_cb, ctx);
    279		if (ok)
    280			return ok;
    281	}
    282
    283	return false;
    284}
    285
    286
    287
    288static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)
    289{
    290	struct dpi_clk_calc_ctx ctx;
    291	int r;
    292	bool ok;
    293
    294	ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);
    295	if (!ok)
    296		return -EINVAL;
    297
    298	r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);
    299	if (r)
    300		return r;
    301
    302	dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
    303				  dpi->clk_src);
    304
    305	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
    306
    307	return 0;
    308}
    309
    310static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)
    311{
    312	struct dpi_clk_calc_ctx ctx;
    313	int r;
    314	bool ok;
    315
    316	ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);
    317	if (!ok)
    318		return -EINVAL;
    319
    320	r = dss_set_fck_rate(dpi->dss, ctx.fck);
    321	if (r)
    322		return r;
    323
    324	dpi->mgr_config.clock_info = ctx.dispc_cinfo;
    325
    326	return 0;
    327}
    328
    329static int dpi_set_mode(struct dpi_data *dpi)
    330{
    331	int r;
    332
    333	if (dpi->pll)
    334		r = dpi_set_pll_clk(dpi, dpi->pixelclock);
    335	else
    336		r = dpi_set_dispc_clk(dpi, dpi->pixelclock);
    337
    338	return r;
    339}
    340
    341static void dpi_config_lcd_manager(struct dpi_data *dpi)
    342{
    343	dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
    344
    345	dpi->mgr_config.stallmode = false;
    346	dpi->mgr_config.fifohandcheck = false;
    347
    348	dpi->mgr_config.video_port_width = dpi->data_lines;
    349
    350	dpi->mgr_config.lcden_sig_polarity = 0;
    351
    352	dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
    353}
    354
    355static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
    356{
    357	int lck_div, pck_div;
    358	unsigned long fck;
    359	struct dpi_clk_calc_ctx ctx;
    360
    361	if (dpi->pll) {
    362		if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
    363			return -EINVAL;
    364
    365		fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
    366	} else {
    367		if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
    368			return -EINVAL;
    369
    370		fck = ctx.fck;
    371	}
    372
    373	lck_div = ctx.dispc_cinfo.lck_div;
    374	pck_div = ctx.dispc_cinfo.pck_div;
    375
    376	*clock = fck / lck_div / pck_div;
    377
    378	return 0;
    379}
    380
    381static int dpi_verify_pll(struct dss_pll *pll)
    382{
    383	int r;
    384
    385	/* do initial setup with the PLL to see if it is operational */
    386
    387	r = dss_pll_enable(pll);
    388	if (r)
    389		return r;
    390
    391	dss_pll_disable(pll);
    392
    393	return 0;
    394}
    395
    396static void dpi_init_pll(struct dpi_data *dpi)
    397{
    398	struct dss_pll *pll;
    399
    400	if (dpi->pll)
    401		return;
    402
    403	dpi->clk_src = dpi_get_clk_src(dpi);
    404
    405	pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
    406	if (!pll)
    407		return;
    408
    409	if (dpi_verify_pll(pll)) {
    410		DSSWARN("PLL not operational\n");
    411		return;
    412	}
    413
    414	dpi->pll = pll;
    415}
    416
    417/* -----------------------------------------------------------------------------
    418 * DRM Bridge Operations
    419 */
    420
    421static int dpi_bridge_attach(struct drm_bridge *bridge,
    422			     enum drm_bridge_attach_flags flags)
    423{
    424	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    425
    426	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
    427		return -EINVAL;
    428
    429	dpi_init_pll(dpi);
    430
    431	return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
    432				 bridge, flags);
    433}
    434
    435static enum drm_mode_status
    436dpi_bridge_mode_valid(struct drm_bridge *bridge,
    437		       const struct drm_display_info *info,
    438		       const struct drm_display_mode *mode)
    439{
    440	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    441	unsigned long clock = mode->clock * 1000;
    442	int ret;
    443
    444	if (mode->hdisplay % 8 != 0)
    445		return MODE_BAD_WIDTH;
    446
    447	if (mode->clock == 0)
    448		return MODE_NOCLOCK;
    449
    450	ret = dpi_clock_update(dpi, &clock);
    451	if (ret < 0)
    452		return MODE_CLOCK_RANGE;
    453
    454	return MODE_OK;
    455}
    456
    457static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
    458				   const struct drm_display_mode *mode,
    459				   struct drm_display_mode *adjusted_mode)
    460{
    461	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    462	unsigned long clock = mode->clock * 1000;
    463	int ret;
    464
    465	ret = dpi_clock_update(dpi, &clock);
    466	if (ret < 0)
    467		return false;
    468
    469	adjusted_mode->clock = clock / 1000;
    470
    471	return true;
    472}
    473
    474static void dpi_bridge_mode_set(struct drm_bridge *bridge,
    475				 const struct drm_display_mode *mode,
    476				 const struct drm_display_mode *adjusted_mode)
    477{
    478	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    479
    480	dpi->pixelclock = adjusted_mode->clock * 1000;
    481}
    482
    483static void dpi_bridge_enable(struct drm_bridge *bridge)
    484{
    485	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    486	int r;
    487
    488	if (dpi->vdds_dsi_reg) {
    489		r = regulator_enable(dpi->vdds_dsi_reg);
    490		if (r)
    491			return;
    492	}
    493
    494	r = dispc_runtime_get(dpi->dss->dispc);
    495	if (r)
    496		goto err_get_dispc;
    497
    498	r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
    499	if (r)
    500		goto err_src_sel;
    501
    502	if (dpi->pll) {
    503		r = dss_pll_enable(dpi->pll);
    504		if (r)
    505			goto err_pll_init;
    506	}
    507
    508	r = dpi_set_mode(dpi);
    509	if (r)
    510		goto err_set_mode;
    511
    512	dpi_config_lcd_manager(dpi);
    513
    514	mdelay(2);
    515
    516	r = dss_mgr_enable(&dpi->output);
    517	if (r)
    518		goto err_mgr_enable;
    519
    520	return;
    521
    522err_mgr_enable:
    523err_set_mode:
    524	if (dpi->pll)
    525		dss_pll_disable(dpi->pll);
    526err_pll_init:
    527err_src_sel:
    528	dispc_runtime_put(dpi->dss->dispc);
    529err_get_dispc:
    530	if (dpi->vdds_dsi_reg)
    531		regulator_disable(dpi->vdds_dsi_reg);
    532}
    533
    534static void dpi_bridge_disable(struct drm_bridge *bridge)
    535{
    536	struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
    537
    538	dss_mgr_disable(&dpi->output);
    539
    540	if (dpi->pll) {
    541		dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
    542					  DSS_CLK_SRC_FCK);
    543		dss_pll_disable(dpi->pll);
    544	}
    545
    546	dispc_runtime_put(dpi->dss->dispc);
    547
    548	if (dpi->vdds_dsi_reg)
    549		regulator_disable(dpi->vdds_dsi_reg);
    550}
    551
    552static const struct drm_bridge_funcs dpi_bridge_funcs = {
    553	.attach = dpi_bridge_attach,
    554	.mode_valid = dpi_bridge_mode_valid,
    555	.mode_fixup = dpi_bridge_mode_fixup,
    556	.mode_set = dpi_bridge_mode_set,
    557	.enable = dpi_bridge_enable,
    558	.disable = dpi_bridge_disable,
    559};
    560
    561static void dpi_bridge_init(struct dpi_data *dpi)
    562{
    563	dpi->bridge.funcs = &dpi_bridge_funcs;
    564	dpi->bridge.of_node = dpi->pdev->dev.of_node;
    565	dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
    566
    567	drm_bridge_add(&dpi->bridge);
    568}
    569
    570static void dpi_bridge_cleanup(struct dpi_data *dpi)
    571{
    572	drm_bridge_remove(&dpi->bridge);
    573}
    574
    575/* -----------------------------------------------------------------------------
    576 * Initialisation and Cleanup
    577 */
    578
    579/*
    580 * Return a hardcoded channel for the DPI output. This should work for
    581 * current use cases, but this can be later expanded to either resolve
    582 * the channel in some more dynamic manner, or get the channel as a user
    583 * parameter.
    584 */
    585static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
    586{
    587	switch (dpi->dss_model) {
    588	case DSS_MODEL_OMAP2:
    589	case DSS_MODEL_OMAP3:
    590		return OMAP_DSS_CHANNEL_LCD;
    591
    592	case DSS_MODEL_DRA7:
    593		switch (dpi->id) {
    594		case 2:
    595			return OMAP_DSS_CHANNEL_LCD3;
    596		case 1:
    597			return OMAP_DSS_CHANNEL_LCD2;
    598		case 0:
    599		default:
    600			return OMAP_DSS_CHANNEL_LCD;
    601		}
    602
    603	case DSS_MODEL_OMAP4:
    604		return OMAP_DSS_CHANNEL_LCD2;
    605
    606	case DSS_MODEL_OMAP5:
    607		return OMAP_DSS_CHANNEL_LCD3;
    608
    609	default:
    610		DSSWARN("unsupported DSS version\n");
    611		return OMAP_DSS_CHANNEL_LCD;
    612	}
    613}
    614
    615static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
    616{
    617	struct omap_dss_device *out = &dpi->output;
    618	u32 port_num = 0;
    619	int r;
    620
    621	dpi_bridge_init(dpi);
    622
    623	of_property_read_u32(port, "reg", &port_num);
    624	dpi->id = port_num <= 2 ? port_num : 0;
    625
    626	switch (port_num) {
    627	case 2:
    628		out->name = "dpi.2";
    629		break;
    630	case 1:
    631		out->name = "dpi.1";
    632		break;
    633	case 0:
    634	default:
    635		out->name = "dpi.0";
    636		break;
    637	}
    638
    639	out->dev = &dpi->pdev->dev;
    640	out->id = OMAP_DSS_OUTPUT_DPI;
    641	out->type = OMAP_DISPLAY_TYPE_DPI;
    642	out->dispc_channel = dpi_get_channel(dpi);
    643	out->of_port = port_num;
    644
    645	r = omapdss_device_init_output(out, &dpi->bridge);
    646	if (r < 0) {
    647		dpi_bridge_cleanup(dpi);
    648		return r;
    649	}
    650
    651	omapdss_device_register(out);
    652
    653	return 0;
    654}
    655
    656static void dpi_uninit_output_port(struct device_node *port)
    657{
    658	struct dpi_data *dpi = port->data;
    659	struct omap_dss_device *out = &dpi->output;
    660
    661	omapdss_device_unregister(out);
    662	omapdss_device_cleanup_output(out);
    663
    664	dpi_bridge_cleanup(dpi);
    665}
    666
    667/* -----------------------------------------------------------------------------
    668 * Initialisation and Cleanup
    669 */
    670
    671static const struct soc_device_attribute dpi_soc_devices[] = {
    672	{ .machine = "OMAP3[456]*" },
    673	{ .machine = "[AD]M37*" },
    674	{ /* sentinel */ }
    675};
    676
    677static int dpi_init_regulator(struct dpi_data *dpi)
    678{
    679	struct regulator *vdds_dsi;
    680
    681	/*
    682	 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
    683	 * DM37xx only.
    684	 */
    685	if (!soc_device_match(dpi_soc_devices))
    686		return 0;
    687
    688	vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
    689	if (IS_ERR(vdds_dsi)) {
    690		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
    691			DSSERR("can't get VDDS_DSI regulator\n");
    692		return PTR_ERR(vdds_dsi);
    693	}
    694
    695	dpi->vdds_dsi_reg = vdds_dsi;
    696
    697	return 0;
    698}
    699
    700int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
    701		  struct device_node *port, enum dss_model dss_model)
    702{
    703	struct dpi_data *dpi;
    704	struct device_node *ep;
    705	u32 datalines;
    706	int r;
    707
    708	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
    709	if (!dpi)
    710		return -ENOMEM;
    711
    712	ep = of_get_next_child(port, NULL);
    713	if (!ep)
    714		return 0;
    715
    716	r = of_property_read_u32(ep, "data-lines", &datalines);
    717	of_node_put(ep);
    718	if (r) {
    719		DSSERR("failed to parse datalines\n");
    720		return r;
    721	}
    722
    723	dpi->data_lines = datalines;
    724
    725	dpi->pdev = pdev;
    726	dpi->dss_model = dss_model;
    727	dpi->dss = dss;
    728	port->data = dpi;
    729
    730	r = dpi_init_regulator(dpi);
    731	if (r)
    732		return r;
    733
    734	return dpi_init_output_port(dpi, port);
    735}
    736
    737void dpi_uninit_port(struct device_node *port)
    738{
    739	struct dpi_data *dpi = port->data;
    740
    741	if (!dpi)
    742		return;
    743
    744	dpi_uninit_output_port(port);
    745}