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

mxsfb_kms.c (21475B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
      4 *
      5 * This code is based on drivers/video/fbdev/mxsfb.c :
      6 * Copyright (C) 2010 Juergen Beisert, Pengutronix
      7 * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
      8 * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/io.h>
     13#include <linux/iopoll.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/spinlock.h>
     16
     17#include <drm/drm_atomic.h>
     18#include <drm/drm_atomic_helper.h>
     19#include <drm/drm_bridge.h>
     20#include <drm/drm_crtc.h>
     21#include <drm/drm_encoder.h>
     22#include <drm/drm_fb_cma_helper.h>
     23#include <drm/drm_fourcc.h>
     24#include <drm/drm_gem_atomic_helper.h>
     25#include <drm/drm_gem_cma_helper.h>
     26#include <drm/drm_plane.h>
     27#include <drm/drm_plane_helper.h>
     28#include <drm/drm_vblank.h>
     29
     30#include "mxsfb_drv.h"
     31#include "mxsfb_regs.h"
     32
     33/* 1 second delay should be plenty of time for block reset */
     34#define RESET_TIMEOUT		1000000
     35
     36/* -----------------------------------------------------------------------------
     37 * CRTC
     38 */
     39
     40static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
     41{
     42	return (val & mxsfb->devdata->hs_wdth_mask) <<
     43		mxsfb->devdata->hs_wdth_shift;
     44}
     45
     46/*
     47 * Setup the MXSFB registers for decoding the pixels out of the framebuffer and
     48 * outputting them on the bus.
     49 */
     50static void mxsfb_set_formats(struct mxsfb_drm_private *mxsfb,
     51			      const u32 bus_format)
     52{
     53	struct drm_device *drm = mxsfb->drm;
     54	const u32 format = mxsfb->crtc.primary->state->fb->format->format;
     55	u32 ctrl, ctrl1;
     56
     57	DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
     58			     bus_format);
     59
     60	ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
     61
     62	/* CTRL1 contains IRQ config and status bits, preserve those. */
     63	ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
     64	ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
     65
     66	switch (format) {
     67	case DRM_FORMAT_RGB565:
     68		dev_dbg(drm->dev, "Setting up RGB565 mode\n");
     69		ctrl |= CTRL_WORD_LENGTH_16;
     70		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
     71		break;
     72	case DRM_FORMAT_XRGB8888:
     73		dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
     74		ctrl |= CTRL_WORD_LENGTH_24;
     75		/* Do not use packed pixels = one pixel per word instead. */
     76		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
     77		break;
     78	}
     79
     80	switch (bus_format) {
     81	case MEDIA_BUS_FMT_RGB565_1X16:
     82		ctrl |= CTRL_BUS_WIDTH_16;
     83		break;
     84	case MEDIA_BUS_FMT_RGB666_1X18:
     85		ctrl |= CTRL_BUS_WIDTH_18;
     86		break;
     87	case MEDIA_BUS_FMT_RGB888_1X24:
     88		ctrl |= CTRL_BUS_WIDTH_24;
     89		break;
     90	default:
     91		dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format);
     92		break;
     93	}
     94
     95	writel(ctrl1, mxsfb->base + LCDC_CTRL1);
     96	writel(ctrl, mxsfb->base + LCDC_CTRL);
     97}
     98
     99static void mxsfb_set_mode(struct mxsfb_drm_private *mxsfb, u32 bus_flags)
    100{
    101	struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
    102	u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
    103
    104	writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
    105	       TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
    106	       mxsfb->base + mxsfb->devdata->transfer_count);
    107
    108	vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
    109
    110	vdctrl0 = VDCTRL0_ENABLE_PRESENT |	/* Always in DOTCLOCK mode */
    111		  VDCTRL0_VSYNC_PERIOD_UNIT |
    112		  VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
    113		  VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
    114	if (m->flags & DRM_MODE_FLAG_PHSYNC)
    115		vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
    116	if (m->flags & DRM_MODE_FLAG_PVSYNC)
    117		vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
    118	/* Make sure Data Enable is high active by default */
    119	if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
    120		vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
    121	/*
    122	 * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
    123	 * controllers VDCTRL0_DOTCLK is display centric.
    124	 * Drive on positive edge       -> display samples on falling edge
    125	 * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
    126	 */
    127	if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
    128		vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
    129
    130	writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
    131
    132	/* Frame length in lines. */
    133	writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
    134
    135	/* Line length in units of clocks or pixels. */
    136	hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
    137	writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
    138	       VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
    139	       mxsfb->base + LCDC_VDCTRL2);
    140
    141	writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
    142	       SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
    143	       mxsfb->base + LCDC_VDCTRL3);
    144
    145	writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
    146	       mxsfb->base + LCDC_VDCTRL4);
    147
    148}
    149
    150static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
    151{
    152	u32 reg;
    153
    154	if (mxsfb->clk_disp_axi)
    155		clk_prepare_enable(mxsfb->clk_disp_axi);
    156	clk_prepare_enable(mxsfb->clk);
    157
    158	/* Increase number of outstanding requests on all supported IPs */
    159	if (mxsfb->devdata->has_ctrl2) {
    160		reg = readl(mxsfb->base + LCDC_V4_CTRL2);
    161		reg &= ~CTRL2_SET_OUTSTANDING_REQS_MASK;
    162		reg |= CTRL2_SET_OUTSTANDING_REQS_16;
    163		writel(reg, mxsfb->base + LCDC_V4_CTRL2);
    164	}
    165
    166	/* If it was disabled, re-enable the mode again */
    167	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
    168
    169	/* Enable the SYNC signals first, then the DMA engine */
    170	reg = readl(mxsfb->base + LCDC_VDCTRL4);
    171	reg |= VDCTRL4_SYNC_SIGNALS_ON;
    172	writel(reg, mxsfb->base + LCDC_VDCTRL4);
    173
    174	/*
    175	 * Enable recovery on underflow.
    176	 *
    177	 * There is some sort of corner case behavior of the controller,
    178	 * which could rarely be triggered at least on i.MX6SX connected
    179	 * to 800x480 DPI panel and i.MX8MM connected to DPI->DSI->LVDS
    180	 * bridged 1920x1080 panel (and likely on other setups too), where
    181	 * the image on the panel shifts to the right and wraps around.
    182	 * This happens either when the controller is enabled on boot or
    183	 * even later during run time. The condition does not correct
    184	 * itself automatically, i.e. the display image remains shifted.
    185	 *
    186	 * It seems this problem is known and is due to sporadic underflows
    187	 * of the LCDIF FIFO. While the LCDIF IP does have underflow/overflow
    188	 * IRQs, neither of the IRQs trigger and neither IRQ status bit is
    189	 * asserted when this condition occurs.
    190	 *
    191	 * All known revisions of the LCDIF IP have CTRL1 RECOVER_ON_UNDERFLOW
    192	 * bit, which is described in the reference manual since i.MX23 as
    193	 * "
    194	 *   Set this bit to enable the LCDIF block to recover in the next
    195	 *   field/frame if there was an underflow in the current field/frame.
    196	 * "
    197	 * Enable this bit to mitigate the sporadic underflows.
    198	 */
    199	reg = readl(mxsfb->base + LCDC_CTRL1);
    200	reg |= CTRL1_RECOVER_ON_UNDERFLOW;
    201	writel(reg, mxsfb->base + LCDC_CTRL1);
    202
    203	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
    204}
    205
    206static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
    207{
    208	u32 reg;
    209
    210	/*
    211	 * Even if we disable the controller here, it will still continue
    212	 * until its FIFOs are running out of data
    213	 */
    214	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
    215
    216	readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
    217			   0, 1000);
    218
    219	reg = readl(mxsfb->base + LCDC_VDCTRL4);
    220	reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
    221	writel(reg, mxsfb->base + LCDC_VDCTRL4);
    222
    223	clk_disable_unprepare(mxsfb->clk);
    224	if (mxsfb->clk_disp_axi)
    225		clk_disable_unprepare(mxsfb->clk_disp_axi);
    226}
    227
    228/*
    229 * Clear the bit and poll it cleared.  This is usually called with
    230 * a reset address and mask being either SFTRST(bit 31) or CLKGATE
    231 * (bit 30).
    232 */
    233static int clear_poll_bit(void __iomem *addr, u32 mask)
    234{
    235	u32 reg;
    236
    237	writel(mask, addr + REG_CLR);
    238	return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
    239}
    240
    241static int mxsfb_reset_block(struct mxsfb_drm_private *mxsfb)
    242{
    243	int ret;
    244
    245	/*
    246	 * It seems, you can't re-program the controller if it is still
    247	 * running. This may lead to shifted pictures (FIFO issue?), so
    248	 * first stop the controller and drain its FIFOs.
    249	 */
    250
    251	ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
    252	if (ret)
    253		return ret;
    254
    255	writel(CTRL_CLKGATE, mxsfb->base + LCDC_CTRL + REG_CLR);
    256
    257	ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_SFTRST);
    258	if (ret)
    259		return ret;
    260
    261	ret = clear_poll_bit(mxsfb->base + LCDC_CTRL, CTRL_CLKGATE);
    262	if (ret)
    263		return ret;
    264
    265	/* Clear the FIFOs */
    266	writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
    267	readl(mxsfb->base + LCDC_CTRL1);
    268	writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_CLR);
    269	readl(mxsfb->base + LCDC_CTRL1);
    270
    271	if (mxsfb->devdata->has_overlay)
    272		writel(0, mxsfb->base + LCDC_AS_CTRL);
    273
    274	return 0;
    275}
    276
    277static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb,
    278				     struct drm_bridge_state *bridge_state,
    279				     const u32 bus_format)
    280{
    281	struct drm_device *drm = mxsfb->crtc.dev;
    282	struct drm_display_mode *m = &mxsfb->crtc.state->adjusted_mode;
    283	u32 bus_flags = mxsfb->connector->display_info.bus_flags;
    284	int err;
    285
    286	if (mxsfb->bridge && mxsfb->bridge->timings)
    287		bus_flags = mxsfb->bridge->timings->input_bus_flags;
    288	else if (bridge_state)
    289		bus_flags = bridge_state->input_bus_cfg.flags;
    290
    291	DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
    292			     m->crtc_clock,
    293			     (int)(clk_get_rate(mxsfb->clk) / 1000));
    294	DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
    295			     bus_flags);
    296	DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
    297
    298	/* Mandatory eLCDIF reset as per the Reference Manual */
    299	err = mxsfb_reset_block(mxsfb);
    300	if (err)
    301		return;
    302
    303	mxsfb_set_formats(mxsfb, bus_format);
    304
    305	clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
    306
    307	mxsfb_set_mode(mxsfb, bus_flags);
    308}
    309
    310static int mxsfb_crtc_atomic_check(struct drm_crtc *crtc,
    311				   struct drm_atomic_state *state)
    312{
    313	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
    314									  crtc);
    315	bool has_primary = crtc_state->plane_mask &
    316			   drm_plane_mask(crtc->primary);
    317
    318	/* The primary plane has to be enabled when the CRTC is active. */
    319	if (crtc_state->active && !has_primary)
    320		return -EINVAL;
    321
    322	/* TODO: Is this needed ? */
    323	return drm_atomic_add_affected_planes(state, crtc);
    324}
    325
    326static void mxsfb_crtc_atomic_flush(struct drm_crtc *crtc,
    327				    struct drm_atomic_state *state)
    328{
    329	struct drm_pending_vblank_event *event;
    330
    331	event = crtc->state->event;
    332	crtc->state->event = NULL;
    333
    334	if (!event)
    335		return;
    336
    337	spin_lock_irq(&crtc->dev->event_lock);
    338	if (drm_crtc_vblank_get(crtc) == 0)
    339		drm_crtc_arm_vblank_event(crtc, event);
    340	else
    341		drm_crtc_send_vblank_event(crtc, event);
    342	spin_unlock_irq(&crtc->dev->event_lock);
    343}
    344
    345static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
    346				     struct drm_atomic_state *state)
    347{
    348	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
    349	struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
    350									    crtc->primary);
    351	struct drm_bridge_state *bridge_state = NULL;
    352	struct drm_device *drm = mxsfb->drm;
    353	u32 bus_format = 0;
    354	dma_addr_t paddr;
    355
    356	pm_runtime_get_sync(drm->dev);
    357	mxsfb_enable_axi_clk(mxsfb);
    358
    359	drm_crtc_vblank_on(crtc);
    360
    361	/* If there is a bridge attached to the LCDIF, use its bus format */
    362	if (mxsfb->bridge) {
    363		bridge_state =
    364			drm_atomic_get_new_bridge_state(state,
    365							mxsfb->bridge);
    366		if (!bridge_state)
    367			bus_format = MEDIA_BUS_FMT_FIXED;
    368		else
    369			bus_format = bridge_state->input_bus_cfg.format;
    370
    371		if (bus_format == MEDIA_BUS_FMT_FIXED) {
    372			dev_warn_once(drm->dev,
    373				      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
    374				      "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
    375			bus_format = MEDIA_BUS_FMT_RGB888_1X24;
    376		}
    377	}
    378
    379	/* If there is no bridge, use bus format from connector */
    380	if (!bus_format && mxsfb->connector->display_info.num_bus_formats)
    381		bus_format = mxsfb->connector->display_info.bus_formats[0];
    382
    383	/* If all else fails, default to RGB888_1X24 */
    384	if (!bus_format)
    385		bus_format = MEDIA_BUS_FMT_RGB888_1X24;
    386
    387	mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format);
    388
    389	/* Write cur_buf as well to avoid an initial corrupt frame */
    390	paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
    391	if (paddr) {
    392		writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
    393		writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
    394	}
    395
    396	mxsfb_enable_controller(mxsfb);
    397}
    398
    399static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
    400				      struct drm_atomic_state *state)
    401{
    402	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
    403	struct drm_device *drm = mxsfb->drm;
    404	struct drm_pending_vblank_event *event;
    405
    406	mxsfb_disable_controller(mxsfb);
    407
    408	spin_lock_irq(&drm->event_lock);
    409	event = crtc->state->event;
    410	if (event) {
    411		crtc->state->event = NULL;
    412		drm_crtc_send_vblank_event(crtc, event);
    413	}
    414	spin_unlock_irq(&drm->event_lock);
    415
    416	drm_crtc_vblank_off(crtc);
    417
    418	mxsfb_disable_axi_clk(mxsfb);
    419	pm_runtime_put_sync(drm->dev);
    420}
    421
    422static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
    423{
    424	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
    425
    426	/* Clear and enable VBLANK IRQ */
    427	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
    428	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
    429
    430	return 0;
    431}
    432
    433static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
    434{
    435	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
    436
    437	/* Disable and clear VBLANK IRQ */
    438	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
    439	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
    440}
    441
    442static int mxsfb_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
    443{
    444	struct mxsfb_drm_private *mxsfb;
    445
    446	if (!crtc)
    447		return -ENODEV;
    448
    449	mxsfb = to_mxsfb_drm_private(crtc->dev);
    450
    451	if (source && strcmp(source, "auto") == 0)
    452		mxsfb->crc_active = true;
    453	else if (!source)
    454		mxsfb->crc_active = false;
    455	else
    456		return -EINVAL;
    457
    458	return 0;
    459}
    460
    461static int mxsfb_crtc_verify_crc_source(struct drm_crtc *crtc,
    462					const char *source, size_t *values_cnt)
    463{
    464	if (!crtc)
    465		return -ENODEV;
    466
    467	if (source && strcmp(source, "auto") != 0) {
    468		DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
    469				 source, crtc->name);
    470		return -EINVAL;
    471	}
    472
    473	*values_cnt = 1;
    474	return 0;
    475}
    476
    477static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
    478	.atomic_check = mxsfb_crtc_atomic_check,
    479	.atomic_flush = mxsfb_crtc_atomic_flush,
    480	.atomic_enable = mxsfb_crtc_atomic_enable,
    481	.atomic_disable = mxsfb_crtc_atomic_disable,
    482};
    483
    484static const struct drm_crtc_funcs mxsfb_crtc_funcs = {
    485	.reset = drm_atomic_helper_crtc_reset,
    486	.destroy = drm_crtc_cleanup,
    487	.set_config = drm_atomic_helper_set_config,
    488	.page_flip = drm_atomic_helper_page_flip,
    489	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
    490	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
    491	.enable_vblank = mxsfb_crtc_enable_vblank,
    492	.disable_vblank = mxsfb_crtc_disable_vblank,
    493};
    494
    495static const struct drm_crtc_funcs mxsfb_crtc_with_crc_funcs = {
    496	.reset = drm_atomic_helper_crtc_reset,
    497	.destroy = drm_crtc_cleanup,
    498	.set_config = drm_atomic_helper_set_config,
    499	.page_flip = drm_atomic_helper_page_flip,
    500	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
    501	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
    502	.enable_vblank = mxsfb_crtc_enable_vblank,
    503	.disable_vblank = mxsfb_crtc_disable_vblank,
    504	.set_crc_source = mxsfb_crtc_set_crc_source,
    505	.verify_crc_source = mxsfb_crtc_verify_crc_source,
    506};
    507
    508/* -----------------------------------------------------------------------------
    509 * Encoder
    510 */
    511
    512static const struct drm_encoder_funcs mxsfb_encoder_funcs = {
    513	.destroy = drm_encoder_cleanup,
    514};
    515
    516/* -----------------------------------------------------------------------------
    517 * Planes
    518 */
    519
    520static int mxsfb_plane_atomic_check(struct drm_plane *plane,
    521				    struct drm_atomic_state *state)
    522{
    523	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
    524									     plane);
    525	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
    526	struct drm_crtc_state *crtc_state;
    527
    528	crtc_state = drm_atomic_get_new_crtc_state(state,
    529						   &mxsfb->crtc);
    530
    531	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
    532						   DRM_PLANE_HELPER_NO_SCALING,
    533						   DRM_PLANE_HELPER_NO_SCALING,
    534						   false, true);
    535}
    536
    537static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane,
    538					      struct drm_atomic_state *state)
    539{
    540	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
    541	struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
    542									    plane);
    543	dma_addr_t paddr;
    544
    545	paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
    546	if (paddr)
    547		writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
    548}
    549
    550static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane,
    551					      struct drm_atomic_state *state)
    552{
    553	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
    554									    plane);
    555	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev);
    556	struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
    557									    plane);
    558	dma_addr_t paddr;
    559	u32 ctrl;
    560
    561	paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0);
    562	if (!paddr) {
    563		writel(0, mxsfb->base + LCDC_AS_CTRL);
    564		return;
    565	}
    566
    567	/*
    568	 * HACK: The hardware seems to output 64 bytes of data of unknown
    569	 * origin, and then to proceed with the framebuffer. Until the reason
    570	 * is understood, live with the 16 initial invalid pixels on the first
    571	 * line and start 64 bytes within the framebuffer.
    572	 */
    573	paddr += 64;
    574
    575	writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF);
    576
    577	/*
    578	 * If the plane was previously disabled, write LCDC_AS_BUF as well to
    579	 * provide the first buffer.
    580	 */
    581	if (!old_pstate->fb)
    582		writel(paddr, mxsfb->base + LCDC_AS_BUF);
    583
    584	ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255);
    585
    586	switch (new_pstate->fb->format->format) {
    587	case DRM_FORMAT_XRGB4444:
    588		ctrl |= AS_CTRL_FORMAT_RGB444 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
    589		break;
    590	case DRM_FORMAT_ARGB4444:
    591		ctrl |= AS_CTRL_FORMAT_ARGB4444 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
    592		break;
    593	case DRM_FORMAT_XRGB1555:
    594		ctrl |= AS_CTRL_FORMAT_RGB555 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
    595		break;
    596	case DRM_FORMAT_ARGB1555:
    597		ctrl |= AS_CTRL_FORMAT_ARGB1555 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
    598		break;
    599	case DRM_FORMAT_RGB565:
    600		ctrl |= AS_CTRL_FORMAT_RGB565 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
    601		break;
    602	case DRM_FORMAT_XRGB8888:
    603		ctrl |= AS_CTRL_FORMAT_RGB888 | AS_CTRL_ALPHA_CTRL_OVERRIDE;
    604		break;
    605	case DRM_FORMAT_ARGB8888:
    606		ctrl |= AS_CTRL_FORMAT_ARGB8888 | AS_CTRL_ALPHA_CTRL_EMBEDDED;
    607		break;
    608	}
    609
    610	writel(ctrl, mxsfb->base + LCDC_AS_CTRL);
    611}
    612
    613static bool mxsfb_format_mod_supported(struct drm_plane *plane,
    614				       uint32_t format,
    615				       uint64_t modifier)
    616{
    617	return modifier == DRM_FORMAT_MOD_LINEAR;
    618}
    619
    620static const struct drm_plane_helper_funcs mxsfb_plane_primary_helper_funcs = {
    621	.atomic_check = mxsfb_plane_atomic_check,
    622	.atomic_update = mxsfb_plane_primary_atomic_update,
    623};
    624
    625static const struct drm_plane_helper_funcs mxsfb_plane_overlay_helper_funcs = {
    626	.atomic_check = mxsfb_plane_atomic_check,
    627	.atomic_update = mxsfb_plane_overlay_atomic_update,
    628};
    629
    630static const struct drm_plane_funcs mxsfb_plane_funcs = {
    631	.format_mod_supported	= mxsfb_format_mod_supported,
    632	.update_plane		= drm_atomic_helper_update_plane,
    633	.disable_plane		= drm_atomic_helper_disable_plane,
    634	.destroy		= drm_plane_cleanup,
    635	.reset			= drm_atomic_helper_plane_reset,
    636	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
    637	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
    638};
    639
    640static const uint32_t mxsfb_primary_plane_formats[] = {
    641	DRM_FORMAT_RGB565,
    642	DRM_FORMAT_XRGB8888,
    643};
    644
    645static const uint32_t mxsfb_overlay_plane_formats[] = {
    646	DRM_FORMAT_XRGB4444,
    647	DRM_FORMAT_ARGB4444,
    648	DRM_FORMAT_XRGB1555,
    649	DRM_FORMAT_ARGB1555,
    650	DRM_FORMAT_RGB565,
    651	DRM_FORMAT_XRGB8888,
    652	DRM_FORMAT_ARGB8888,
    653};
    654
    655static const uint64_t mxsfb_modifiers[] = {
    656	DRM_FORMAT_MOD_LINEAR,
    657	DRM_FORMAT_MOD_INVALID
    658};
    659
    660/* -----------------------------------------------------------------------------
    661 * Initialization
    662 */
    663
    664int mxsfb_kms_init(struct mxsfb_drm_private *mxsfb)
    665{
    666	struct drm_encoder *encoder = &mxsfb->encoder;
    667	struct drm_crtc *crtc = &mxsfb->crtc;
    668	int ret;
    669
    670	drm_plane_helper_add(&mxsfb->planes.primary,
    671			     &mxsfb_plane_primary_helper_funcs);
    672	ret = drm_universal_plane_init(mxsfb->drm, &mxsfb->planes.primary, 1,
    673				       &mxsfb_plane_funcs,
    674				       mxsfb_primary_plane_formats,
    675				       ARRAY_SIZE(mxsfb_primary_plane_formats),
    676				       mxsfb_modifiers, DRM_PLANE_TYPE_PRIMARY,
    677				       NULL);
    678	if (ret)
    679		return ret;
    680
    681	if (mxsfb->devdata->has_overlay) {
    682		drm_plane_helper_add(&mxsfb->planes.overlay,
    683				     &mxsfb_plane_overlay_helper_funcs);
    684		ret = drm_universal_plane_init(mxsfb->drm,
    685					       &mxsfb->planes.overlay, 1,
    686					       &mxsfb_plane_funcs,
    687					       mxsfb_overlay_plane_formats,
    688					       ARRAY_SIZE(mxsfb_overlay_plane_formats),
    689					       mxsfb_modifiers, DRM_PLANE_TYPE_OVERLAY,
    690					       NULL);
    691		if (ret)
    692			return ret;
    693	}
    694
    695	drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
    696	if (mxsfb->devdata->has_crc32) {
    697		ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
    698						&mxsfb->planes.primary, NULL,
    699						&mxsfb_crtc_with_crc_funcs,
    700						NULL);
    701	} else {
    702		ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
    703						&mxsfb->planes.primary, NULL,
    704						&mxsfb_crtc_funcs, NULL);
    705	}
    706	if (ret)
    707		return ret;
    708
    709	encoder->possible_crtcs = drm_crtc_mask(crtc);
    710	return drm_encoder_init(mxsfb->drm, encoder, &mxsfb_encoder_funcs,
    711				DRM_MODE_ENCODER_NONE, NULL);
    712}