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

mdp4_lcdc_encoder.c (14612B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Red Hat
      4 * Author: Rob Clark <robdclark@gmail.com>
      5 * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
      6 */
      7
      8#include <linux/delay.h>
      9
     10#include <drm/drm_crtc.h>
     11#include <drm/drm_probe_helper.h>
     12
     13#include "mdp4_kms.h"
     14
     15struct mdp4_lcdc_encoder {
     16	struct drm_encoder base;
     17	struct device_node *panel_node;
     18	struct drm_panel *panel;
     19	struct clk *lcdc_clk;
     20	unsigned long int pixclock;
     21	struct regulator *regs[3];
     22	bool enabled;
     23	uint32_t bsc;
     24};
     25#define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_encoder, base)
     26
     27static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
     28{
     29	struct msm_drm_private *priv = encoder->dev->dev_private;
     30	return to_mdp4_kms(to_mdp_kms(priv->kms));
     31}
     32
     33static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder)
     34{
     35	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
     36			to_mdp4_lcdc_encoder(encoder);
     37	drm_encoder_cleanup(encoder);
     38	kfree(mdp4_lcdc_encoder);
     39}
     40
     41static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
     42	.destroy = mdp4_lcdc_encoder_destroy,
     43};
     44
     45/* this should probably be a helper: */
     46static struct drm_connector *get_connector(struct drm_encoder *encoder)
     47{
     48	struct drm_device *dev = encoder->dev;
     49	struct drm_connector *connector;
     50
     51	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
     52		if (connector->encoder == encoder)
     53			return connector;
     54
     55	return NULL;
     56}
     57
     58static void setup_phy(struct drm_encoder *encoder)
     59{
     60	struct drm_device *dev = encoder->dev;
     61	struct drm_connector *connector = get_connector(encoder);
     62	struct mdp4_kms *mdp4_kms = get_kms(encoder);
     63	uint32_t lvds_intf = 0, lvds_phy_cfg0 = 0;
     64	int bpp, nchan, swap;
     65
     66	if (!connector)
     67		return;
     68
     69	bpp = 3 * connector->display_info.bpc;
     70
     71	if (!bpp)
     72		bpp = 18;
     73
     74	/* TODO, these should come from panel somehow: */
     75	nchan = 1;
     76	swap = 0;
     77
     78	switch (bpp) {
     79	case 24:
     80		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
     81				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
     82				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
     83				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
     84				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
     85		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
     86				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
     87				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
     88				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
     89		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
     90				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
     91				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
     92				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
     93				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
     94		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
     95				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
     96				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
     97				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
     98		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
     99				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
    100				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
    101				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
    102				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
    103		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
    104				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
    105				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
    106				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
    107		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
    108				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
    109				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
    110				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
    111				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
    112		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
    113				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
    114				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
    115				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
    116		if (nchan == 2) {
    117			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN |
    118					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
    119					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
    120					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
    121					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
    122					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
    123					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
    124					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
    125		} else {
    126			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
    127					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
    128					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
    129					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
    130		}
    131		break;
    132
    133	case 18:
    134		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
    135				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
    136				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
    137				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
    138				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
    139		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
    140				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
    141				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
    142				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
    143		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
    144				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
    145				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
    146				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
    147				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
    148		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
    149				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
    150				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
    151				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
    152		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
    153				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
    154				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
    155				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
    156				MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
    157		mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
    158				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
    159				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
    160				MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
    161		if (nchan == 2) {
    162			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
    163					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
    164					MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
    165					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
    166					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
    167					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
    168		} else {
    169			lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
    170					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
    171					MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
    172		}
    173		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT;
    174		break;
    175
    176	default:
    177		DRM_DEV_ERROR(dev->dev, "unknown bpp: %d\n", bpp);
    178		return;
    179	}
    180
    181	switch (nchan) {
    182	case 1:
    183		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0;
    184		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN |
    185				MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL;
    186		break;
    187	case 2:
    188		lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0 |
    189				MDP4_LVDS_PHY_CFG0_CHANNEL1;
    190		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN |
    191				MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
    192		break;
    193	default:
    194		DRM_DEV_ERROR(dev->dev, "unknown # of channels: %d\n", nchan);
    195		return;
    196	}
    197
    198	if (swap)
    199		lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP;
    200
    201	lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_ENABLE;
    202
    203	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
    204	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_INTF_CTL, lvds_intf);
    205	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG2, 0x30);
    206
    207	mb();
    208	udelay(1);
    209	lvds_phy_cfg0 |= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE;
    210	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
    211}
    212
    213static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
    214		struct drm_display_mode *mode,
    215		struct drm_display_mode *adjusted_mode)
    216{
    217	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
    218			to_mdp4_lcdc_encoder(encoder);
    219	struct mdp4_kms *mdp4_kms = get_kms(encoder);
    220	uint32_t lcdc_hsync_skew, vsync_period, vsync_len, ctrl_pol;
    221	uint32_t display_v_start, display_v_end;
    222	uint32_t hsync_start_x, hsync_end_x;
    223
    224	mode = adjusted_mode;
    225
    226	DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
    227
    228	mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
    229
    230	DBG("pixclock=%lu", mdp4_lcdc_encoder->pixclock);
    231
    232	ctrl_pol = 0;
    233	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
    234		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW;
    235	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
    236		ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW;
    237	/* probably need to get DATA_EN polarity from panel.. */
    238
    239	lcdc_hsync_skew = 0;  /* get this from panel? */
    240
    241	hsync_start_x = (mode->htotal - mode->hsync_start);
    242	hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
    243
    244	vsync_period = mode->vtotal * mode->htotal;
    245	vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
    246	display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + lcdc_hsync_skew;
    247	display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + lcdc_hsync_skew - 1;
    248
    249	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_CTRL,
    250			MDP4_LCDC_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
    251			MDP4_LCDC_HSYNC_CTRL_PERIOD(mode->htotal));
    252	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_PERIOD, vsync_period);
    253	mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_LEN, vsync_len);
    254	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_HCTRL,
    255			MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x) |
    256			MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x));
    257	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VSTART, display_v_start);
    258	mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VEND, display_v_end);
    259	mdp4_write(mdp4_kms, REG_MDP4_LCDC_BORDER_CLR, 0);
    260	mdp4_write(mdp4_kms, REG_MDP4_LCDC_UNDERFLOW_CLR,
    261			MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY |
    262			MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
    263	mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_SKEW, lcdc_hsync_skew);
    264	mdp4_write(mdp4_kms, REG_MDP4_LCDC_CTRL_POLARITY, ctrl_pol);
    265	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_HCTL,
    266			MDP4_LCDC_ACTIVE_HCTL_START(0) |
    267			MDP4_LCDC_ACTIVE_HCTL_END(0));
    268	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VSTART, 0);
    269	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
    270}
    271
    272static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
    273{
    274	struct drm_device *dev = encoder->dev;
    275	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
    276			to_mdp4_lcdc_encoder(encoder);
    277	struct mdp4_kms *mdp4_kms = get_kms(encoder);
    278	struct drm_panel *panel;
    279	int i, ret;
    280
    281	if (WARN_ON(!mdp4_lcdc_encoder->enabled))
    282		return;
    283
    284	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
    285
    286	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
    287	if (!IS_ERR(panel)) {
    288		drm_panel_disable(panel);
    289		drm_panel_unprepare(panel);
    290	}
    291
    292	/*
    293	 * Wait for a vsync so we know the ENABLE=0 latched before
    294	 * the (connector) source of the vsync's gets disabled,
    295	 * otherwise we end up in a funny state if we re-enable
    296	 * before the disable latches, which results that some of
    297	 * the settings changes for the new modeset (like new
    298	 * scanout buffer) don't latch properly..
    299	 */
    300	mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
    301
    302	clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
    303
    304	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
    305		ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
    306		if (ret)
    307			DRM_DEV_ERROR(dev->dev, "failed to disable regulator: %d\n", ret);
    308	}
    309
    310	mdp4_lcdc_encoder->enabled = false;
    311}
    312
    313static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
    314{
    315	struct drm_device *dev = encoder->dev;
    316	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
    317			to_mdp4_lcdc_encoder(encoder);
    318	unsigned long pc = mdp4_lcdc_encoder->pixclock;
    319	struct mdp4_kms *mdp4_kms = get_kms(encoder);
    320	struct drm_panel *panel;
    321	uint32_t config;
    322	int i, ret;
    323
    324	if (WARN_ON(mdp4_lcdc_encoder->enabled))
    325		return;
    326
    327	/* TODO: hard-coded for 18bpp: */
    328	config =
    329		MDP4_DMA_CONFIG_R_BPC(BPC6) |
    330		MDP4_DMA_CONFIG_G_BPC(BPC6) |
    331		MDP4_DMA_CONFIG_B_BPC(BPC6) |
    332		MDP4_DMA_CONFIG_PACK(0x21) |
    333		MDP4_DMA_CONFIG_DEFLKR_EN |
    334		MDP4_DMA_CONFIG_DITHER_EN;
    335
    336	if (!of_property_read_bool(dev->dev->of_node, "qcom,lcdc-align-lsb"))
    337		config |= MDP4_DMA_CONFIG_PACK_ALIGN_MSB;
    338
    339	mdp4_crtc_set_config(encoder->crtc, config);
    340	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
    341
    342	for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
    343		ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
    344		if (ret)
    345			DRM_DEV_ERROR(dev->dev, "failed to enable regulator: %d\n", ret);
    346	}
    347
    348	DBG("setting lcdc_clk=%lu", pc);
    349	ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
    350	if (ret)
    351		DRM_DEV_ERROR(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
    352	ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
    353	if (ret)
    354		DRM_DEV_ERROR(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
    355
    356	panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
    357	if (!IS_ERR(panel)) {
    358		drm_panel_prepare(panel);
    359		drm_panel_enable(panel);
    360	}
    361
    362	setup_phy(encoder);
    363
    364	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
    365
    366	mdp4_lcdc_encoder->enabled = true;
    367}
    368
    369static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
    370	.mode_set = mdp4_lcdc_encoder_mode_set,
    371	.disable = mdp4_lcdc_encoder_disable,
    372	.enable = mdp4_lcdc_encoder_enable,
    373};
    374
    375long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
    376{
    377	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
    378			to_mdp4_lcdc_encoder(encoder);
    379	return clk_round_rate(mdp4_lcdc_encoder->lcdc_clk, rate);
    380}
    381
    382/* initialize encoder */
    383struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
    384		struct device_node *panel_node)
    385{
    386	struct drm_encoder *encoder = NULL;
    387	struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
    388	struct regulator *reg;
    389	int ret;
    390
    391	mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL);
    392	if (!mdp4_lcdc_encoder) {
    393		ret = -ENOMEM;
    394		goto fail;
    395	}
    396
    397	mdp4_lcdc_encoder->panel_node = panel_node;
    398
    399	encoder = &mdp4_lcdc_encoder->base;
    400
    401	drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
    402			 DRM_MODE_ENCODER_LVDS, NULL);
    403	drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
    404
    405	/* TODO: do we need different pll in other cases? */
    406	mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
    407	if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
    408		DRM_DEV_ERROR(dev->dev, "failed to get lvds_clk\n");
    409		ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
    410		goto fail;
    411	}
    412
    413	/* TODO: different regulators in other cases? */
    414	reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
    415	if (IS_ERR(reg)) {
    416		ret = PTR_ERR(reg);
    417		DRM_DEV_ERROR(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
    418		goto fail;
    419	}
    420	mdp4_lcdc_encoder->regs[0] = reg;
    421
    422	reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
    423	if (IS_ERR(reg)) {
    424		ret = PTR_ERR(reg);
    425		DRM_DEV_ERROR(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
    426		goto fail;
    427	}
    428	mdp4_lcdc_encoder->regs[1] = reg;
    429
    430	reg = devm_regulator_get(dev->dev, "lvds-vdda");
    431	if (IS_ERR(reg)) {
    432		ret = PTR_ERR(reg);
    433		DRM_DEV_ERROR(dev->dev, "failed to get lvds-vdda: %d\n", ret);
    434		goto fail;
    435	}
    436	mdp4_lcdc_encoder->regs[2] = reg;
    437
    438	return encoder;
    439
    440fail:
    441	if (encoder)
    442		mdp4_lcdc_encoder_destroy(encoder);
    443
    444	return ERR_PTR(ret);
    445}