linux/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
<<
>>
Prefs
   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 <drm/drmP.h>
  12#include <drm/drm_atomic_helper.h>
  13#include <drm/drm_crtc.h>
  14#include <drm/drm_fb_helper.h>
  15#include <drm/drm_fb_cma_helper.h>
  16#include <drm/drm_gem_cma_helper.h>
  17#include <drm/drm_of.h>
  18#include <drm/drm_plane_helper.h>
  19#include <drm/drm_probe_helper.h>
  20#include <drm/drm_simple_kms_helper.h>
  21#include <linux/clk.h>
  22#include <linux/iopoll.h>
  23#include <linux/of_graph.h>
  24#include <linux/platform_data/simplefb.h>
  25#include <video/videomode.h>
  26
  27#include "mxsfb_drv.h"
  28#include "mxsfb_regs.h"
  29
  30#define MXS_SET_ADDR            0x4
  31#define MXS_CLR_ADDR            0x8
  32#define MODULE_CLKGATE          BIT(30)
  33#define MODULE_SFTRST           BIT(31)
  34/* 1 second delay should be plenty of time for block reset */
  35#define RESET_TIMEOUT           1000000
  36
  37static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
  38{
  39        return (val & mxsfb->devdata->hs_wdth_mask) <<
  40                mxsfb->devdata->hs_wdth_shift;
  41}
  42
  43/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
  44static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
  45{
  46        struct drm_crtc *crtc = &mxsfb->pipe.crtc;
  47        struct drm_device *drm = crtc->dev;
  48        const u32 format = crtc->primary->state->fb->format->format;
  49        u32 ctrl, ctrl1;
  50
  51        ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
  52
  53        /*
  54         * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
  55         * match the selected mode here. This differs from the original
  56         * MXSFB driver, which had the option to configure the bus width
  57         * to arbitrary value. This limitation should not pose an issue.
  58         */
  59
  60        /* CTRL1 contains IRQ config and status bits, preserve those. */
  61        ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
  62        ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
  63
  64        switch (format) {
  65        case DRM_FORMAT_RGB565:
  66                dev_dbg(drm->dev, "Setting up RGB565 mode\n");
  67                ctrl |= CTRL_SET_WORD_LENGTH(0);
  68                ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
  69                break;
  70        case DRM_FORMAT_XRGB8888:
  71                dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
  72                ctrl |= CTRL_SET_WORD_LENGTH(3);
  73                /* Do not use packed pixels = one pixel per word instead. */
  74                ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
  75                break;
  76        default:
  77                dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
  78                return -EINVAL;
  79        }
  80
  81        writel(ctrl1, mxsfb->base + LCDC_CTRL1);
  82        writel(ctrl, mxsfb->base + LCDC_CTRL);
  83
  84        return 0;
  85}
  86
  87static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
  88{
  89        struct drm_crtc *crtc = &mxsfb->pipe.crtc;
  90        struct drm_device *drm = crtc->dev;
  91        u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
  92        u32 reg;
  93
  94        reg = readl(mxsfb->base + LCDC_CTRL);
  95
  96        if (mxsfb->connector.display_info.num_bus_formats)
  97                bus_format = mxsfb->connector.display_info.bus_formats[0];
  98
  99        reg &= ~CTRL_BUS_WIDTH_MASK;
 100        switch (bus_format) {
 101        case MEDIA_BUS_FMT_RGB565_1X16:
 102                reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
 103                break;
 104        case MEDIA_BUS_FMT_RGB666_1X18:
 105                reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
 106                break;
 107        case MEDIA_BUS_FMT_RGB888_1X24:
 108                reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
 109                break;
 110        default:
 111                dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
 112                break;
 113        }
 114        writel(reg, mxsfb->base + LCDC_CTRL);
 115}
 116
 117static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
 118{
 119        u32 reg;
 120
 121        if (mxsfb->clk_disp_axi)
 122                clk_prepare_enable(mxsfb->clk_disp_axi);
 123        clk_prepare_enable(mxsfb->clk);
 124
 125        /* If it was disabled, re-enable the mode again */
 126        writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
 127
 128        /* Enable the SYNC signals first, then the DMA engine */
 129        reg = readl(mxsfb->base + LCDC_VDCTRL4);
 130        reg |= VDCTRL4_SYNC_SIGNALS_ON;
 131        writel(reg, mxsfb->base + LCDC_VDCTRL4);
 132
 133        writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
 134}
 135
 136static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
 137{
 138        u32 reg;
 139
 140        /*
 141         * Even if we disable the controller here, it will still continue
 142         * until its FIFOs are running out of data
 143         */
 144        writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
 145
 146        readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
 147                           0, 1000);
 148
 149        reg = readl(mxsfb->base + LCDC_VDCTRL4);
 150        reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
 151        writel(reg, mxsfb->base + LCDC_VDCTRL4);
 152
 153        clk_disable_unprepare(mxsfb->clk);
 154        if (mxsfb->clk_disp_axi)
 155                clk_disable_unprepare(mxsfb->clk_disp_axi);
 156}
 157
 158/*
 159 * Clear the bit and poll it cleared.  This is usually called with
 160 * a reset address and mask being either SFTRST(bit 31) or CLKGATE
 161 * (bit 30).
 162 */
 163static int clear_poll_bit(void __iomem *addr, u32 mask)
 164{
 165        u32 reg;
 166
 167        writel(mask, addr + MXS_CLR_ADDR);
 168        return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
 169}
 170
 171static int mxsfb_reset_block(void __iomem *reset_addr)
 172{
 173        int ret;
 174
 175        ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
 176        if (ret)
 177                return ret;
 178
 179        writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
 180
 181        ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
 182        if (ret)
 183                return ret;
 184
 185        return clear_poll_bit(reset_addr, MODULE_CLKGATE);
 186}
 187
 188static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
 189{
 190        struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
 191        struct drm_gem_cma_object *gem;
 192
 193        if (!fb)
 194                return 0;
 195
 196        gem = drm_fb_cma_get_gem_obj(fb, 0);
 197        if (!gem)
 198                return 0;
 199
 200        return gem->paddr;
 201}
 202
 203static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
 204{
 205        struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
 206        const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
 207        u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
 208        int err;
 209
 210        /*
 211         * It seems, you can't re-program the controller if it is still
 212         * running. This may lead to shifted pictures (FIFO issue?), so
 213         * first stop the controller and drain its FIFOs.
 214         */
 215
 216        /* Mandatory eLCDIF reset as per the Reference Manual */
 217        err = mxsfb_reset_block(mxsfb->base);
 218        if (err)
 219                return;
 220
 221        /* Clear the FIFOs */
 222        writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
 223
 224        err = mxsfb_set_pixel_fmt(mxsfb);
 225        if (err)
 226                return;
 227
 228        clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
 229
 230        writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
 231               TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
 232               mxsfb->base + mxsfb->devdata->transfer_count);
 233
 234        vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
 235
 236        vdctrl0 = VDCTRL0_ENABLE_PRESENT |      /* Always in DOTCLOCK mode */
 237                  VDCTRL0_VSYNC_PERIOD_UNIT |
 238                  VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
 239                  VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
 240        if (m->flags & DRM_MODE_FLAG_PHSYNC)
 241                vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
 242        if (m->flags & DRM_MODE_FLAG_PVSYNC)
 243                vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
 244        /* Make sure Data Enable is high active by default */
 245        if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
 246                vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
 247        /*
 248         * DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
 249         * controllers VDCTRL0_DOTCLK is display centric.
 250         * Drive on positive edge       -> display samples on falling edge
 251         * DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
 252         */
 253        if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
 254                vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
 255
 256        writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
 257
 258        mxsfb_set_bus_fmt(mxsfb);
 259
 260        /* Frame length in lines. */
 261        writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
 262
 263        /* Line length in units of clocks or pixels. */
 264        hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
 265        writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
 266               VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
 267               mxsfb->base + LCDC_VDCTRL2);
 268
 269        writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
 270               SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
 271               mxsfb->base + LCDC_VDCTRL3);
 272
 273        writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
 274               mxsfb->base + LCDC_VDCTRL4);
 275}
 276
 277void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
 278{
 279        dma_addr_t paddr;
 280
 281        mxsfb_enable_axi_clk(mxsfb);
 282        mxsfb_crtc_mode_set_nofb(mxsfb);
 283
 284        /* Write cur_buf as well to avoid an initial corrupt frame */
 285        paddr = mxsfb_get_fb_paddr(mxsfb);
 286        if (paddr) {
 287                writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
 288                writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
 289        }
 290
 291        mxsfb_enable_controller(mxsfb);
 292}
 293
 294void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
 295{
 296        mxsfb_disable_controller(mxsfb);
 297        mxsfb_disable_axi_clk(mxsfb);
 298}
 299
 300void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
 301                               struct drm_plane_state *state)
 302{
 303        struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
 304        struct drm_crtc *crtc = &pipe->crtc;
 305        struct drm_pending_vblank_event *event;
 306        dma_addr_t paddr;
 307
 308        spin_lock_irq(&crtc->dev->event_lock);
 309        event = crtc->state->event;
 310        if (event) {
 311                crtc->state->event = NULL;
 312
 313                if (drm_crtc_vblank_get(crtc) == 0) {
 314                        drm_crtc_arm_vblank_event(crtc, event);
 315                } else {
 316                        drm_crtc_send_vblank_event(crtc, event);
 317                }
 318        }
 319        spin_unlock_irq(&crtc->dev->event_lock);
 320
 321        paddr = mxsfb_get_fb_paddr(mxsfb);
 322        if (paddr) {
 323                mxsfb_enable_axi_clk(mxsfb);
 324                writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
 325                mxsfb_disable_axi_clk(mxsfb);
 326        }
 327}
 328