Message ID | 1425905045-14007-4-git-send-email-Zubair.Kakakhel@imgtec.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Mar 09, 2015 at 12:44:03PM +0000, Zubair Lutfullah Kakakhel wrote: > Add drm driver for the Ingenic JZ4780 SoC. > > Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> This driver neither supports universal planes nor atomic. Imo adding new drivers using old internal interfaces and only supporting legacy abis is fairly pointless. Please convert it to the latest and greatest, thanks. -Daniel > > --- > V1 -> V2 > > Fixed Module_License macro > Fix in makefile and a #include drm_flip_work > Rebased to 4.0-rc3 > Removed you should have received a copy of license etc. > --- > drivers/gpu/drm/Kconfig | 2 + > drivers/gpu/drm/Makefile | 1 + > drivers/gpu/drm/jz4780/Kconfig | 12 + > drivers/gpu/drm/jz4780/Makefile | 3 + > drivers/gpu/drm/jz4780/jz4780_crtc.c | 719 +++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/jz4780/jz4780_drv.c | 388 +++++++++++++++++++ > drivers/gpu/drm/jz4780/jz4780_drv.h | 82 ++++ > drivers/gpu/drm/jz4780/jz4780_regs.h | 694 +++++++++++++++++++++++++++++++++ > 8 files changed, 1901 insertions(+) > create mode 100644 drivers/gpu/drm/jz4780/Kconfig > create mode 100644 drivers/gpu/drm/jz4780/Makefile > create mode 100644 drivers/gpu/drm/jz4780/jz4780_crtc.c > create mode 100644 drivers/gpu/drm/jz4780/jz4780_drv.c > create mode 100644 drivers/gpu/drm/jz4780/jz4780_drv.h > create mode 100644 drivers/gpu/drm/jz4780/jz4780_regs.h > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig > index 151a050..77edd60 100644 > --- a/drivers/gpu/drm/Kconfig > +++ b/drivers/gpu/drm/Kconfig > @@ -208,3 +208,5 @@ source "drivers/gpu/drm/sti/Kconfig" > source "drivers/gpu/drm/amd/amdkfd/Kconfig" > > source "drivers/gpu/drm/imx/Kconfig" > + > +source "drivers/gpu/drm/jz4780/Kconfig" > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > index 2c239b9..f8403e1 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -66,6 +66,7 @@ obj-$(CONFIG_DRM_MSM) += msm/ > obj-$(CONFIG_DRM_TEGRA) += tegra/ > obj-$(CONFIG_DRM_STI) += sti/ > obj-$(CONFIG_DRM_IMX) += imx/ > +obj-$(CONFIG_DRM_JZ4780) += jz4780/ > obj-y += i2c/ > obj-y += panel/ > obj-y += bridge/ > diff --git a/drivers/gpu/drm/jz4780/Kconfig b/drivers/gpu/drm/jz4780/Kconfig > new file mode 100644 > index 0000000..ae417d1 > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/Kconfig > @@ -0,0 +1,12 @@ > +config DRM_JZ4780 > + tristate "DRM Support for Ingenic JZ4780 LCDC Display Controller" > + depends on DRM && OF > + select DRM_KMS_HELPER > + select DRM_KMS_FB_HELPER > + select DRM_KMS_CMA_HELPER > + select DRM_GEM_CMA_HELPER > + select VIDEOMODE_HELPERS > + help > + Choose this option if you have an Ingenic JZ4780 SoC with LCDC display > + controller, for example the MIPS Creator CI20 board > + > diff --git a/drivers/gpu/drm/jz4780/Makefile b/drivers/gpu/drm/jz4780/Makefile > new file mode 100644 > index 0000000..3e896c5 > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/Makefile > @@ -0,0 +1,3 @@ > +jz4780-y := jz4780_crtc.o jz4780_drv.o > + > +obj-$(CONFIG_DRM_JZ4780) += jz4780.o > diff --git a/drivers/gpu/drm/jz4780/jz4780_crtc.c b/drivers/gpu/drm/jz4780/jz4780_crtc.c > new file mode 100644 > index 0000000..da3f63a > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/jz4780_crtc.c > @@ -0,0 +1,719 @@ > +/* > + * Copyright (C) 2014 Imagination Technologies > + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> > + * > + * LCDC CRTC driver for Ingenic JZ4780, based on the tilcdc driver > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#include <linux/component.h> > + > +#include <drm/drm_flip_work.h> > +#include <drm/drm_plane_helper.h> > + > +#include "jz4780_drv.h" > +#include "jz4780_regs.h" > + > +/** > + * @next: physical address of next frame descriptor > + * @databuf: physical address of buffer > + * @id: frame ID > + * @cmd: DMA command and buffer length(in word) > + * @offsize: DMA off size, in word > + * @page_width: DMA page width, in word > + * @cpos: smart LCD mode is commands' number, other is bpp, > + * premulti and position of foreground 0, 1 > + * @desc_size: alpha and size of foreground 0, 1 > + */ > +struct jz4780_framedesc { > + uint32_t next; > + uint32_t databuf; > + uint32_t id; > + uint32_t cmd; > + uint32_t offsize; > + uint32_t page_width; > + uint32_t cpos; > + uint32_t desc_size; > +} __packed; > + > +struct jz4780_crtc { > + struct drm_crtc base; > + struct device *dev; > + struct drm_device *drm_dev; > + > + const struct jz4780_panel_info *info; > + uint32_t dirty; > + > + struct drm_pending_vblank_event *event; > + int dpms; > + wait_queue_head_t frame_done_wq; > + bool frame_done; > + > + /* fb currently set to scanout 0/1: */ > + struct drm_framebuffer *scanout[2]; > + > + /* for deferred fb unref's: */ > + struct drm_flip_work unref_work; > + > + /* DMA descriptors */ > + struct jz4780_framedesc *framedesc; > + dma_addr_t framedesc_phys; > +}; > +#define to_jz4780_crtc(x) container_of(x, struct jz4780_crtc, base) > + > +static void unref_worker(struct drm_flip_work *work, void *val) > +{ > + struct jz4780_crtc *jz4780_crtc = > + container_of(work, struct jz4780_crtc, unref_work); > + struct drm_device *dev = jz4780_crtc->base.dev; > + > + mutex_lock(&dev->mode_config.mutex); > + drm_framebuffer_unreference(val); > + mutex_unlock(&dev->mode_config.mutex); > +} > + > +static void set_scanout(struct drm_crtc *crtc, int n) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_device *dev = crtc->dev; > + struct jz4780_drm_private *priv = dev->dev_private; > + struct drm_framebuffer *fb = crtc->primary->fb; > + struct jz4780_framedesc *framedesc = jz4780_crtc->framedesc; > + struct drm_gem_cma_object *gem; > + unsigned int depth, bpp; > + int fg0_line_size; > + int fg0_frm_size; > + int height_width; > + > + gem = drm_fb_cma_get_gem_obj(fb, 0); > + drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); > + pm_runtime_get_sync(dev->dev); > + > + /* lcd display area */ > + fg0_line_size = crtc->mode.hdisplay * bpp >> 3; > + /* word aligned and in word */ > + fg0_line_size = ALIGN(fg0_line_size, 4) >> 2; > + fg0_frm_size = fg0_line_size * crtc->mode.vdisplay; > + > + height_width = (crtc->mode.vdisplay - 1) << LCDC_DESSIZE_HEIGHT_BIT > + & LCDC_DESSIZE_HEIGHT_MASK; > + height_width |= ((crtc->mode.hdisplay - 1) << LCDC_DESSIZE_WIDTH_BIT > + & LCDC_DESSIZE_WIDTH_MASK); > + > + if (n == 0) { > + framedesc[0].next = jz4780_crtc->framedesc_phys > + + sizeof(struct jz4780_framedesc); > + framedesc[0].databuf = gem->paddr; > + framedesc[0].id = 0xda0; > + framedesc[0].cmd = LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN > + | fg0_frm_size; > + framedesc[0].offsize = 0; > + framedesc[0].page_width = 0; > + framedesc[0].cpos = 0x2d000000; > + framedesc[0].desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; > + framedesc[0].desc_size |= height_width; > + > + jz4780_write(dev, LCDC_DA0, framedesc[0].next); > + } else { > + framedesc[1].next = jz4780_crtc->framedesc_phys; > + framedesc[1].id = 0xda1; > + framedesc[1].databuf = gem->paddr; > + framedesc[1].offsize = 0; > + framedesc[1].page_width = 0; > + framedesc[1].cmd = (LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN) > + | fg0_frm_size; > + > + framedesc[1].desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; > + framedesc[1].desc_size |= height_width; > + > + framedesc[1].cpos = 0x2f000000; > + jz4780_write(dev, LCDC_DA1, framedesc[1].next); > + } > + > + if (jz4780_crtc->scanout[n]) { > + drm_flip_work_queue(&jz4780_crtc->unref_work, > + jz4780_crtc->scanout[n]); > + drm_flip_work_commit(&jz4780_crtc->unref_work, priv->wq); > + } > + jz4780_crtc->scanout[n] = crtc->primary->fb; > + drm_framebuffer_reference(jz4780_crtc->scanout[n]); > + pm_runtime_put_sync(dev->dev); > +} > + > +static void update_scanout(struct drm_crtc *crtc) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_device *dev = crtc->dev; > + > + if (jz4780_crtc->dpms == DRM_MODE_DPMS_ON) { > + drm_vblank_get(dev, 0); > + } else { > + /* not enabled yet, so update registers immediately: */ > + jz4780_write(dev, LCDC_STATE, 0); > + set_scanout(crtc, 0); > + set_scanout(crtc, 1); > + } > +} > + > +static void start(struct drm_crtc *crtc) > +{ > + struct drm_device *dev = crtc->dev; > + uint32_t ctrl; > + > + jz4780_write(dev, LCDC_STATE, 0); > + jz4780_write(dev, LCDC_OSDS, 0); > + ctrl = jz4780_read(dev, LCDC_CTRL); > + ctrl |= LCDC_CTRL_ENA; > + ctrl &= ~LCDC_CTRL_DIS; > + jz4780_write(dev, LCDC_CTRL, ctrl); > + > +} > + > +static void stop(struct drm_crtc *crtc) > +{ > + struct drm_device *dev = crtc->dev; > + int count = 5; > + uint32_t ctrl; > + > + ctrl = jz4780_read(dev, LCDC_CTRL); > + ctrl |= LCDC_CTRL_DIS; > + jz4780_write(dev, LCDC_CTRL, ctrl); > + while (!(jz4780_read(dev, LCDC_STATE) & LCDC_STATE_LDD) > + && count--) { > + usleep_range(1000, 2000); > + } > + if (count >= 0) { > + ctrl = jz4780_read(dev, LCDC_STATE); > + ctrl &= ~LCDC_STATE_LDD; > + jz4780_write(dev, LCDC_STATE, ctrl); > + } else { > + DRM_DEBUG_DRIVER("LCDC normal disable state wrong"); > + } > + > +} > + > +static void jz4780_crtc_destroy(struct drm_crtc *crtc) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + > + drm_crtc_cleanup(crtc); > + drm_flip_work_cleanup(&jz4780_crtc->unref_work); > + > +} > + > +static int jz4780_crtc_page_flip(struct drm_crtc *crtc, > + struct drm_framebuffer *fb, > + struct drm_pending_vblank_event *event, > + uint32_t page_flip_flags) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_device *dev = crtc->dev; > + > + if (jz4780_crtc->event) { > + dev_err(dev->dev, "already pending page flip!\n"); > + return -EBUSY; > + } > + > + crtc->primary->fb = fb; > + jz4780_crtc->event = event; > + update_scanout(crtc); > + > + return 0; > +} > + > +static void jz4780_crtc_dpms(struct drm_crtc *crtc, int mode) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_device *dev = crtc->dev; > + > + /* we really only care about on or off: */ > + if (mode != DRM_MODE_DPMS_ON) > + mode = DRM_MODE_DPMS_OFF; > + > + if (jz4780_crtc->dpms == mode) > + return; > + > + jz4780_crtc->dpms = mode; > + > + pm_runtime_get_sync(dev->dev); > + > + if (mode == DRM_MODE_DPMS_ON) { > + pm_runtime_forbid(dev->dev); > + start(crtc); > + } else { > + jz4780_crtc->frame_done = false; > + stop(crtc); > + pm_runtime_allow(dev->dev); > + } > + > + pm_runtime_put_sync(dev->dev); > +} > + > +static bool jz4780_crtc_mode_fixup(struct drm_crtc *crtc, > + const struct drm_display_mode *mode, > + struct drm_display_mode *adjusted_mode) > +{ > + DRM_DEBUG_DRIVER("Mode Fixup not supported by driver yet\n"); > + return true; > +} > + > +static void jz4780_crtc_prepare(struct drm_crtc *crtc) > +{ > + > + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); > +} > + > +static void jz4780_crtc_commit(struct drm_crtc *crtc) > +{ > + > + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_ON); > +} > + > +static int jz4780_crtc_mode_set(struct drm_crtc *crtc, > + struct drm_display_mode *mode, > + struct drm_display_mode *adjusted_mode, > + int x, int y, > + struct drm_framebuffer *old_fb) > +{ > + struct drm_device *dev = crtc->dev; > + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; > + int ret; > + uint32_t pcfg; > + > + uint16_t hds, vds; > + uint16_t hde, vde; > + uint16_t ht, vt; > + uint32_t cfg, ctrl; > + unsigned int rgb_ctrl; > + > + ret = jz4780_crtc_mode_valid(crtc, mode); > + if (WARN_ON(ret)) > + return ret; > + > + pm_runtime_get_sync(dev->dev); > + > + /* Configure timings: */ > + hbp = mode->htotal - mode->hsync_end; > + hfp = mode->hsync_start - mode->hdisplay; > + hsw = mode->hsync_end - mode->hsync_start; > + vbp = mode->vtotal - mode->vsync_end; > + vfp = mode->vsync_start - mode->vdisplay; > + vsw = mode->vsync_end - mode->vsync_start; > + > + hds = hsw + hbp; > + hde = hds + mode->hdisplay; > + ht = hde + hfp; > + > + vds = vsw + vbp; > + vde = vds + mode->vdisplay; > + vt = vde + vfp; > + > + cfg = LCDC_CFG_NEWDES | LCDC_CFG_RECOVER | LCDC_CFG_MODE_TFT_24BIT; > + cfg |= LCDC_CFG_PSM; > + cfg |= LCDC_CFG_CLSM; > + cfg |= LCDC_CFG_SPLM; > + cfg |= LCDC_CFG_REVM; > + cfg |= LCDC_CFG_PCP; > + > + ctrl = LCDC_CTRL_BST_64 | LCDC_CTRL_OFUM; > + > + /* magic number */ > + pcfg = 0xC0000000 | (511<<18) | (400<<9) | (256<<0); > + > + jz4780_write(dev, LCDC_VAT, (ht << 16) | vt); > + jz4780_write(dev, LCDC_DAH, (hds << 16) | hde); > + jz4780_write(dev, LCDC_DAV, (vds << 16) | vde); > + > + jz4780_write(dev, LCDC_HSYNC, hsw); > + jz4780_write(dev, LCDC_VSYNC, vsw); > + > + jz4780_write(dev, LCDC_CFG, cfg); > + ctrl |= jz4780_read(dev, LCDC_CTRL); > + jz4780_write(dev, LCDC_CTRL, ctrl); > + jz4780_write(dev, LCDC_PCFG, pcfg); > + > + rgb_ctrl = LCDC_RGBC_RGBFMT | LCDC_RGBC_ODD_RGB | > + LCDC_RGBC_EVEN_RGB; > + > + jz4780_write(dev, LCDC_RGBC, rgb_ctrl); > + > + update_scanout(crtc); > + jz4780_crtc_update_clk(crtc); > + > + pm_runtime_put_sync(dev->dev); > + > + return 0; > +} > + > +static const struct drm_crtc_funcs jz4780_crtc_funcs = { > + .destroy = jz4780_crtc_destroy, > + .set_config = drm_crtc_helper_set_config, > + .page_flip = jz4780_crtc_page_flip, > +}; > + > +static const struct drm_crtc_helper_funcs jz4780_crtc_helper_funcs = { > + .dpms = jz4780_crtc_dpms, > + .mode_fixup = jz4780_crtc_mode_fixup, > + .prepare = jz4780_crtc_prepare, > + .commit = jz4780_crtc_commit, > + .mode_set = jz4780_crtc_mode_set, > +}; > + > +int jz4780_crtc_max_width(struct drm_crtc *crtc) > +{ > + return 2048; > +} > + > +int jz4780_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) > +{ > + struct jz4780_drm_private *priv = crtc->dev->dev_private; > + unsigned int bandwidth; > + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; > + > + /* > + * check to see if the width is within the range that > + * the LCD Controller physically supports > + */ > + if (mode->hdisplay > 2048) > + return MODE_VIRTUAL_X; > + > + /* width must be multiple of 16 */ > + if (mode->hdisplay & 0xf) > + return MODE_VIRTUAL_X; > + > + if (mode->vdisplay > 2048) > + return MODE_VIRTUAL_Y; > + > + DRM_DEBUG_DRIVER("Processing mode %dx%d@%d with pixel clock %d", > + mode->hdisplay, mode->vdisplay, > + drm_mode_vrefresh(mode), mode->clock); > + > + hbp = mode->htotal - mode->hsync_end; > + hfp = mode->hsync_start - mode->hdisplay; > + hsw = mode->hsync_end - mode->hsync_start; > + vbp = mode->vtotal - mode->vsync_end; > + vfp = mode->vsync_start - mode->vdisplay; > + vsw = mode->vsync_end - mode->vsync_start; > + > + if ((hbp-1) & ~0x3ff) { > + DRM_DEBUG_DRIVER("Prune: Horizontal Back Porch out of range"); > + return MODE_HBLANK_WIDE; > + } > + > + if ((hfp-1) & ~0x3ff) { > + DRM_DEBUG_DRIVER("Prune: Horizontal Front Porch out of range"); > + return MODE_HBLANK_WIDE; > + } > + > + if ((hsw-1) & ~0x3ff) { > + DRM_DEBUG_DRIVER("Prune: Horizontal Sync Width out of range"); > + return MODE_HSYNC_WIDE; > + } > + > + if (vbp & ~0xff) { > + DRM_DEBUG_DRIVER("Prune: Vertical Back Porch out of range"); > + return MODE_VBLANK_WIDE; > + } > + > + if (vfp & ~0xff) { > + DRM_DEBUG_DRIVER("Prune: Vertical Front Porch out of range"); > + return MODE_VBLANK_WIDE; > + } > + > + if ((vsw-1) & ~0x3f) { > + DRM_DEBUG_DRIVER("Prune: Vertical Sync Width out of range"); > + return MODE_VSYNC_WIDE; > + } > + > + /* > + * some devices have a maximum allowed pixel clock > + * configured from the DT > + */ > + if (mode->clock > priv->max_pixelclock) { > + DRM_DEBUG_DRIVER("Prune: pixel clock too high"); > + return MODE_CLOCK_HIGH; > + } > + > + /* > + * some devices further limit the max horizontal resolution > + * configured from the DT > + */ > + if (mode->hdisplay > priv->max_width) { > + DRM_DEBUG_DRIVER("Prune: Bad width"); > + return MODE_BAD_WIDTH; > + } > + > + /* filter out modes that would require too much memory bandwidth: */ > + bandwidth = mode->hdisplay * mode->vdisplay * > + drm_mode_vrefresh(mode); > + if (bandwidth > priv->max_bandwidth) { > + DRM_DEBUG_DRIVER("Prune: exceeds defined bandwidth limit %d", > + bandwidth); > + return MODE_BAD; > + } > + > + return MODE_OK; > +} > + > +void jz4780_crtc_update_clk(struct drm_crtc *crtc) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_device *dev = crtc->dev; > + struct jz4780_drm_private *priv = dev->dev_private; > + int dpms = jz4780_crtc->dpms; > + unsigned int lcd_clk; > + int ret; > + > + pm_runtime_get_sync(dev->dev); > + > + if (dpms == DRM_MODE_DPMS_ON) > + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); > + > + /* in raster mode, minimum divisor is 2: */ > + ret = clk_set_rate(priv->disp_clk, crtc->mode.clock * 1000); > + if (ret) { > + dev_err(dev->dev, "failed to set display clock rate to: %d\n", > + crtc->mode.clock); > + goto out; > + } > + > + lcd_clk = clk_get_rate(priv->clk); > + > + DRM_DEBUG_DRIVER("lcd_clk=%u, mode clock=%d", lcd_clk, > + crtc->mode.clock); > + DRM_DEBUG_DRIVER("fck=%lu, dpll_disp_ck=%lu", clk_get_rate(priv->clk), > + clk_get_rate(priv->disp_clk)); > + > + if (dpms == DRM_MODE_DPMS_ON) > + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_ON); > + > +out: > + pm_runtime_put_sync(dev->dev); > +} > + > +irqreturn_t jz4780_crtc_irq(struct drm_crtc *crtc) > +{ > + struct drm_device *dev = crtc->dev; > + unsigned int state; > + unsigned int tmp; > + > + state = jz4780_read(dev, LCDC_STATE); > + > + if (state & LCDC_STATE_EOF) { > + jz4780_write(dev, LCDC_STATE, state & ~LCDC_STATE_EOF); > + update_scanout(crtc); > + } > + > + if (state & LCDC_STATE_OFU) { > + DRM_DEBUG_DRIVER("Out FiFo underrun\n"); > + jz4780_write(dev, LCDC_STATE, state & ~LCDC_STATE_OFU); > + tmp = jz4780_read(dev, LCDC_CTRL); > + jz4780_write(dev, LCDC_CTRL, tmp & ~LCDC_CTRL_OFUM); > + update_scanout(crtc); > + start(crtc); > + } > + > + return IRQ_HANDLED; > +} > + > +void jz4780_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) > +{ > + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); > + struct drm_pending_vblank_event *event; > + struct drm_device *dev = crtc->dev; > + unsigned long flags; > + > + /* Destroy the pending vertical blanking event associated with the > + * pending page flip, if any, and disable vertical blanking interrupts. > + */ > + spin_lock_irqsave(&dev->event_lock, flags); > + event = jz4780_crtc->event; > + if (event && event->base.file_priv == file) { > + jz4780_crtc->event = NULL; > + event->base.destroy(&event->base); > + drm_vblank_put(dev, 0); > + } > + spin_unlock_irqrestore(&dev->event_lock, flags); > +} > + > +struct drm_crtc *jz4780_crtc_create(struct jz4780_crtc *jz4780_crtc) > +{ > + > + struct drm_crtc *crtc; > + struct device_node *port; > + struct drm_device *drm_dev = jz4780_crtc->drm_dev; > + struct device *dev = jz4780_crtc->dev; > + int ret; > + > + jz4780_crtc->framedesc = dma_alloc_coherent(dev, > + sizeof(struct jz4780_framedesc) * 2, > + &jz4780_crtc->framedesc_phys, > + GFP_KERNEL | GFP_ATOMIC); > + if (!jz4780_crtc->framedesc) { > + dev_err(dev, "desc allocation failed\n"); > + return NULL; > + } > + > + crtc = &jz4780_crtc->base; > + > + jz4780_crtc->dpms = DRM_MODE_DPMS_OFF; > + init_waitqueue_head(&jz4780_crtc->frame_done_wq); > + > + drm_flip_work_init(&jz4780_crtc->unref_work, > + "unref", unref_worker); > + > + > + ret = drm_crtc_init(drm_dev, crtc, &jz4780_crtc_funcs); > + if (ret < 0) > + goto fail; > + > + drm_crtc_helper_add(crtc, &jz4780_crtc_helper_funcs); > + > + port = of_get_child_by_name(dev->of_node, "port"); > + if (!port) { > + DRM_ERROR("no port node found in %s\n", > + dev->of_node->full_name); > + goto fail; > + } > + > + crtc->port = port; > + > + return crtc; > + > +fail: > + jz4780_crtc_destroy(crtc); > + return NULL; > +} > + > +static const struct of_device_id jz4780_driver_dt_match[] = { > + { .compatible = "ingenic,jz4780-lcd", > + .data = NULL }, > + {}, > +}; > + > +static int jz4780_crtc_bind(struct device *dev, struct device *master, > + void *data) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + const struct of_device_id *of_id; > + struct drm_device *drm_dev = data; > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + struct resource *res; > + struct device_node *node = dev->of_node; > + struct jz4780_crtc *jz4780_crtc; > + > + jz4780_crtc = devm_kzalloc(dev, sizeof(*jz4780_crtc), GFP_KERNEL); > + if (!jz4780_crtc) > + return -ENOMEM; > + > + jz4780_crtc->dev = dev; > + jz4780_crtc->drm_dev = drm_dev; > + dev_set_drvdata(dev, jz4780_crtc); > + > + of_id = of_match_device(jz4780_driver_dt_match, dev); > + if (!of_id) > + return -ENODEV; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + DRM_DEBUG_DRIVER("failed to get memory resource\n"); > + return -EINVAL; > + } > + > + priv->mmio = ioremap_nocache(res->start, resource_size(res)); > + if (!priv->mmio) { > + DRM_DEBUG_DRIVER("failed to ioremap\n"); > + return -ENOMEM; > + } > + > + priv->clk = devm_clk_get(dev, "lcd_clk"); > + if (IS_ERR(priv->clk)) { > + DRM_DEBUG_DRIVER("failed to get lcd clock\n"); > + return -ENODEV; > + } > + > + clk_prepare_enable(priv->clk); > + > + priv->disp_clk = devm_clk_get(dev, "lcd_pixclk"); > + if (IS_ERR(priv->clk)) { > + DRM_DEBUG_DRIVER("failed to get pixel clock\n"); > + return -ENODEV; > + } > + > + clk_prepare_enable(priv->disp_clk); > + > + if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) > + priv->max_bandwidth = JZ4780_DEFAULT_MAX_BANDWIDTH; > + > + if (of_property_read_u32(node, "max-width", &priv->max_width)) > + priv->max_width = JZ4780_DEFAULT_MAX_WIDTH; > + > + if (of_property_read_u32(node, "max-pixelclock", > + &priv->max_pixelclock)) > + priv->max_pixelclock = JZ4780_DEFAULT_MAX_PIXELCLOCK; > + > + drm_irq_install(drm_dev, platform_get_irq(pdev, 0)); > + > + priv->crtc = jz4780_crtc_create(jz4780_crtc); > + > + pm_runtime_enable(&pdev->dev); > + > + return 0; > +} > + > +static void jz4780_crtc_unbind(struct device *dev, struct device *master, > + void *data) > +{ > + struct jz4780_crtc *jz4780_crtc = dev_get_drvdata(dev); > + > + pm_runtime_disable(dev); > + jz4780_crtc_destroy(&jz4780_crtc->base); > +} > + > +static const struct component_ops jz4780_crtc_component_ops = { > + .bind = jz4780_crtc_bind, > + .unbind = jz4780_crtc_unbind, > +}; > + > +static int jz4780_crtc_probe(struct platform_device *pdev) > +{ > + > + struct device *dev = &pdev->dev; > + > + if (!dev->of_node) { > + dev_err(dev, "can't find jz4780 crtc devices\n"); > + return -ENODEV; > + } > + > + return component_add(dev, &jz4780_crtc_component_ops); > +} > + > +static int jz4780_crtc_remove(struct platform_device *pdev) > +{ > + > + component_del(&pdev->dev, &jz4780_crtc_component_ops); > + > + return 0; > +} > + > +struct platform_driver jz4780_crtc_platform_driver = { > + .probe = jz4780_crtc_probe, > + .remove = jz4780_crtc_remove, > + .driver = { > + .name = "jz4780-lcd-crtc", > + .owner = THIS_MODULE, > + .of_match_table = of_match_ptr(jz4780_driver_dt_match), > + }, > +}; > + > +module_platform_driver(jz4780_crtc_platform_driver); > + > diff --git a/drivers/gpu/drm/jz4780/jz4780_drv.c b/drivers/gpu/drm/jz4780/jz4780_drv.c > new file mode 100644 > index 0000000..3040e04 > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/jz4780_drv.c > @@ -0,0 +1,388 @@ > +/* > + * Copyright (C) 2015 Imagination Technologies > + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> > + * > + * DRM driver for Ingenic JZ4780 > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_fb_helper.h> > +#include <linux/of_graph.h> > +#include <linux/component.h> > + > +#include "jz4780_drv.h" > +#include "jz4780_regs.h" > + > +static void jz4780_fb_output_poll_changed(struct drm_device *drm_dev) > +{ > + > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + > + if (priv->fbdev) > + drm_fbdev_cma_hotplug_event(priv->fbdev); > +} > + > +static const struct drm_mode_config_funcs jz4780_mode_config_funcs = { > + .fb_create = drm_fb_cma_create, > + .output_poll_changed = jz4780_fb_output_poll_changed, > +}; > + > +void jz4780_drm_mode_config_init(struct drm_device *drm_dev) > +{ > + > + drm_dev->mode_config.min_width = 0; > + drm_dev->mode_config.min_height = 0; > + drm_dev->mode_config.max_width = 2048; > + drm_dev->mode_config.max_height = 2048; > + drm_dev->mode_config.funcs = &jz4780_mode_config_funcs; > +} > + > +/* > + * DRM operations: > + */ > + > +static int jz4780_unload(struct drm_device *drm_dev) > +{ > + > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + struct device *dev = drm_dev->dev; > + > + drm_kms_helper_poll_fini(drm_dev); > + drm_mode_config_cleanup(drm_dev); > + drm_vblank_cleanup(drm_dev); > + > + component_unbind_all(dev, drm_dev); > + > + flush_workqueue(priv->wq); > + destroy_workqueue(priv->wq); > + > + drm_dev->dev_private = NULL; > + pm_runtime_disable(drm_dev->dev); > + > + return 0; > +} > + > +static int jz4780_load(struct drm_device *drm_dev, unsigned long flags) > +{ > + struct device *dev = drm_dev->dev; > + struct jz4780_drm_private *priv; > + int ret; > + > + priv = devm_kzalloc(drm_dev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) { > + DRM_DEBUG_DRIVER("failed to allocate private data\n"); > + return -ENOMEM; > + } > + > + platform_set_drvdata(drm_dev->platformdev, drm_dev); > + drm_dev->dev_private = priv; > + > + priv->wq = alloc_ordered_workqueue("jz4780", 0); > + > + drm_mode_config_init(drm_dev); > + > + jz4780_drm_mode_config_init(drm_dev); > + > + /* Try to bind all sub drivers. */ > + ret = component_bind_all(dev, drm_dev); > + if (ret) > + goto err_config_cleanup; > + > + ret = drm_vblank_init(drm_dev, 1); > + if (ret < 0) { > + DRM_DEBUG_DRIVER("failed to initialize vblank\n"); > + goto err_vblank_cleanup; > + } > + > + priv->fbdev = drm_fbdev_cma_init(drm_dev, 32, > + drm_dev->mode_config.num_crtc, > + drm_dev->mode_config.num_connector); > + > + drm_kms_helper_poll_init(drm_dev); > + > + return 0; > + > +err_vblank_cleanup: > + drm_vblank_cleanup(drm_dev); > + component_unbind_all(dev, drm_dev); > +err_config_cleanup: > + drm_mode_config_cleanup(drm_dev); > + return ret; > +} > + > +static void jz4780_preclose(struct drm_device *drm_dev, struct drm_file *file) > +{ > + > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + > + jz4780_crtc_cancel_page_flip(priv->crtc, file); > +} > + > +static void jz4780_lastclose(struct drm_device *drm_dev) > +{ > + > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + > + drm_fbdev_cma_restore_mode(priv->fbdev); > +} > + > +static irqreturn_t jz4780_irq(int irq, void *arg) > +{ > + > + struct drm_device *drm_dev = arg; > + struct jz4780_drm_private *priv = drm_dev->dev_private; > + > + return jz4780_crtc_irq(priv->crtc); > +} > + > +static void jz4780_enable_disable_vblank(struct drm_device *drm_dev, > + bool enable) > +{ > + > + u32 tmp; > + > + /* clear previous EOF flag */ > + tmp = jz4780_read(drm_dev, LCDC_STATE); > + jz4780_write(drm_dev, LCDC_STATE, tmp & ~LCDC_STATE_EOF); > + > + /* enable end of frame interrupt */ > + tmp = jz4780_read(drm_dev, LCDC_CTRL); > + if (enable) > + jz4780_write(drm_dev, LCDC_CTRL, tmp | LCDC_CTRL_EOFM); > + else > + jz4780_write(drm_dev, LCDC_CTRL, tmp & ~LCDC_CTRL_EOFM); > + > +} > + > +static int jz4780_enable_vblank(struct drm_device *drm_dev, int crtc) > +{ > + > + jz4780_enable_disable_vblank(drm_dev, true); > + return 0; > +} > + > +static void jz4780_disable_vblank(struct drm_device *drm_dev, int crtc) > +{ > + > + jz4780_enable_disable_vblank(drm_dev, false); > +} > + > +static const struct file_operations fops = { > + .owner = THIS_MODULE, > + .open = drm_open, > + .release = drm_release, > + .unlocked_ioctl = drm_ioctl, > +#ifdef CONFIG_COMPAT > + .compat_ioctl = drm_compat_ioctl, > +#endif > + .poll = drm_poll, > + .read = drm_read, > + .llseek = no_llseek, > + .mmap = drm_gem_cma_mmap, > +}; > + > +static struct drm_driver jz4780_driver = { > + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, > + .load = jz4780_load, > + .unload = jz4780_unload, > + .preclose = jz4780_preclose, > + .lastclose = jz4780_lastclose, > + .set_busid = drm_platform_set_busid, > + .irq_handler = jz4780_irq, > + .get_vblank_counter = drm_vblank_count, > + .enable_vblank = jz4780_enable_vblank, > + .disable_vblank = jz4780_disable_vblank, > + .gem_free_object = drm_gem_cma_free_object, > + .gem_vm_ops = &drm_gem_cma_vm_ops, > + .dumb_create = drm_gem_cma_dumb_create, > + .dumb_map_offset = drm_gem_cma_dumb_map_offset, > + .dumb_destroy = drm_gem_dumb_destroy, > + .fops = &fops, > + .name = "jz4780", > + .desc = "Ingenic LCD Controller DRM", > + .date = "20140623", > + .major = 1, > + .minor = 0, > +}; > + > +static int compare_of(struct device *dev, void *data) > +{ > + > + struct device_node *np = data; > + > + return dev->of_node == np; > +} > + > +static void jz4780_add_endpoints(struct device *dev, > + struct component_match **match, > + struct device_node *port) > +{ > + > + struct device_node *ep, *remote; > + > + for_each_child_of_node(port, ep) { > + remote = of_graph_get_remote_port_parent(ep); > + if (!remote || !of_device_is_available(remote)) { > + of_node_put(remote); > + continue; > + } else if (!of_device_is_available(remote->parent)) { > + dev_warn(dev, "parent device of %s is not available\n", > + remote->full_name); > + of_node_put(remote); > + continue; > + } > + > + component_match_add(dev, match, compare_of, remote); > + of_node_put(remote); > + } > +} > + > +static int jz4780_drm_bind(struct device *dev) > +{ > + > + struct drm_device *drm; > + struct platform_device *pdev = dev_get_drvdata(dev); > + int ret; > + > + drm = drm_dev_alloc(&jz4780_driver, dev); > + if (!drm) > + return -ENOMEM; > + > + ret = drm_dev_set_unique(drm, "%s", dev_name(dev)); > + if (ret) > + goto err_free; > + > + drm->platformdev = pdev; > + > + ret = drm_dev_register(drm, 0); > + if (ret) > + goto err_free; > + > + dev_set_drvdata(dev, drm); > + > + return 0; > + > +err_free: > + drm_dev_unref(drm); > + return ret; > +} > + > +static void jz4780_drm_unbind(struct device *dev) > +{ > + > + struct drm_device *drm = dev_get_drvdata(dev); > + > + drm_dev_unregister(drm); > + drm_dev_unref(drm); > + dev_set_drvdata(dev, NULL); > +} > + > +static const struct component_master_ops jz4780_drm_ops = { > + .bind = jz4780_drm_bind, > + .unbind = jz4780_drm_unbind, > +}; > + > +/* > + * Platform driver: > + */ > +static int jz4780_pdev_probe(struct platform_device *pdev) > +{ > + > + struct device *dev = &pdev->dev; > + struct component_match *match = NULL; > + struct device_node *np = dev->of_node; > + struct device_node *port; > + int i; > + > + if (!np) > + return -ENODEV; > + > + /* > + * Bind the crtc ports first, so that > + * drm_of_find_possible_crtcs called from encoder .bind callbacks > + * works as expected. > + */ > + for (i = 0;; i++) { > + port = of_parse_phandle(np, "ports", i); > + if (!port) > + break; > + > + if (!of_device_is_available(port->parent)) { > + of_node_put(port); > + continue; > + } > + > + component_match_add(dev, &match, compare_of, port->parent); > + of_node_put(port); > + } > + > + if (i == 0) { > + dev_err(dev, "missing 'ports' property\n"); > + return -ENODEV; > + } > + > + if (!match) { > + dev_err(dev, "No available crtc found for display-subsystem.\n"); > + return -ENODEV; > + } > + /* > + * For each bound crtc, bind the encoders attached to its > + * remote endpoint. > + */ > + for (i = 0;; i++) { > + port = of_parse_phandle(np, "ports", i); > + if (!port) > + break; > + > + if (!of_device_is_available(port->parent)) { > + of_node_put(port); > + continue; > + } > + > + jz4780_add_endpoints(dev, &match, port); > + of_node_put(port); > + } > + > + dev_set_drvdata(dev, pdev); > + return component_master_add_with_match(dev, &jz4780_drm_ops, match); > +} > + > +static int jz4780_pdev_remove(struct platform_device *pdev) > +{ > + > + component_master_del(&pdev->dev, &jz4780_drm_ops); > + return 0; > +} > + > +static const struct of_device_id jz4780_of_match[] = { > + { .compatible = "ingenic,jz4780-display-subsystem", }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, jz4780_of_match); > + > +static struct platform_driver jz4780_platform_driver = { > + .probe = jz4780_pdev_probe, > + .remove = jz4780_pdev_remove, > + .driver = { > + .owner = THIS_MODULE, > + .name = "ingenic-jz4780-drm", > + .of_match_table = jz4780_of_match, > + }, > +}; > + > +module_platform_driver(jz4780_platform_driver); > + > +MODULE_AUTHOR("Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>"); > +MODULE_DESCRIPTION("Ingenic JZ4780 LCD/HDMI Driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/gpu/drm/jz4780/jz4780_drv.h b/drivers/gpu/drm/jz4780/jz4780_drv.h > new file mode 100644 > index 0000000..c63997c > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/jz4780_drv.h > @@ -0,0 +1,82 @@ > +/* > + * Copyright (C) 2014 Imagination Technologies > + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#ifndef __jz4780_DRV_H__ > +#define __jz4780_DRV_H__ > + > +#include <linux/clk.h> > +#include <linux/cpufreq.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/pm.h> > +#include <linux/pm_runtime.h> > +#include <linux/slab.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/list.h> > + > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_gem_cma_helper.h> > +#include <drm/drm_fb_cma_helper.h> > + > +/* Defaulting to maximum capability of JZ4780 */ > +#define JZ4780_DEFAULT_MAX_PIXELCLOCK 200000 > +#define JZ4780_DEFAULT_MAX_WIDTH 2048 > +#define JZ4780_DEFAULT_MAX_BANDWIDTH (1920*1080*60) > + > + > +struct jz4780_drm_private { > + void __iomem *mmio; > + > + struct clk *disp_clk; /* display dpll */ > + struct clk *clk; /* functional clock */ > + int rev; /* IP revision */ > + > + /* don't attempt resolutions w/ higher W * H * Hz: */ > + uint32_t max_bandwidth; > + /* > + * Pixel Clock will be restricted to some value as > + * defined in the device datasheet measured in KHz > + */ > + uint32_t max_pixelclock; > + /* > + * Max allowable width is limited on a per device basis > + * measured in pixels > + */ > + uint32_t max_width; > + > + struct workqueue_struct *wq; > + > + struct drm_fbdev_cma *fbdev; > + > + struct drm_crtc *crtc; > + > + unsigned int num_encoders; > + struct drm_encoder *encoders[8]; > + > + unsigned int num_connectors; > + struct drm_connector *connectors[8]; > +}; > + > +void jz4780_crtc_cancel_page_flip(struct drm_crtc *crtc, > + struct drm_file *file); > +irqreturn_t jz4780_crtc_irq(struct drm_crtc *crtc); > +void jz4780_crtc_update_clk(struct drm_crtc *crtc); > +int jz4780_crtc_mode_valid(struct drm_crtc *crtc, > + struct drm_display_mode *mode); > +int jz4780_crtc_max_width(struct drm_crtc *crtc); > + > +#endif /* __jz4780_DRV_H__ */ > diff --git a/drivers/gpu/drm/jz4780/jz4780_regs.h b/drivers/gpu/drm/jz4780/jz4780_regs.h > new file mode 100644 > index 0000000..2e273f9 > --- /dev/null > +++ b/drivers/gpu/drm/jz4780/jz4780_regs.h > @@ -0,0 +1,694 @@ > +/* > + * Copyright (c) 2014 Imagination Technologies > + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#ifndef __JZ4780_REGS_H__ > +#define __JZ4780_REGS_H__ > + > +/* LCDC register definitions */ > + > +#include <linux/bitops.h> > + > +#include "jz4780_drv.h" > + > +/* Register Map Of LCDC */ > +#define LCDC_CFG 0x00 > +#define LCDC_CTRL 0x30 > +#define LCDC_STATE 0x34 > +#define LCDC_OSDC 0x100 > +#define LCDC_OSDCTRL 0x104 > +#define LCDC_OSDS 0x108 > +#define LCDC_BGC0 0x10c > +#define LCDC_BGC1 0x2c4 > +#define LCDC_KEY0 0x110 > +#define LCDC_KEY1 0x114 > +#define LCDC_ALPHA 0x118 > +#define LCDC_IPUR 0x11c > +#define LCDC_RGBC 0x90 > +#define LCDC_VAT 0x0c > +#define LCDC_DAH 0x10 > +#define LCDC_DAV 0x14 > +#define LCDC_XYP0 0x120 > +#define LCDC_XYP1 0x124 > +#define LCDC_SIZE0 0x128 > +#define LCDC_SIZE1 0x12c > +#define LCDC_VSYNC 0x04 > +#define LCDC_HSYNC 0x08 > +#define LCDC_PS 0x18 > +#define LCDC_CLS 0x1c > +#define LCDC_SPL 0x20 > +#define LCDC_REV 0x24 > +#define LCDC_IID 0x38 > +#define LCDC_DA0 0x40 > +#define LCDC_SA0 0x44 > +#define LCDC_FID0 0x48 > +#define LCDC_CMD0 0x4c > +#define LCDC_OFFS0 0x60 > +#define LCDC_PW0 0x64 > +#define LCDC_CNUM0 0x68 > +#define LCDC_CPOS0 0x68 > +#define LCDC_DESSIZE0 0x6c > +#define LCDC_DA1 0x50 > +#define LCDC_SA1 0x54 > +#define LCDC_FID1 0x58 > +#define LCDC_CMD1 0x5c > +#define LCDC_OFFS1 0x70 > +#define LCDC_PW1 0x74 > +#define LCDC_CNUM1 0x78 > +#define LCDC_CPOS1 0x78 > +#define LCDC_DESSIZE1 0x7c > +#define LCDC_PCFG 0x2c0 > +#define LCDC_DUAL_CTRL 0x2c8 > +#define LCDC_ENH_CFG 0x400 > +#define LCDC_ENH_CSCCFG 0x404 > +#define LCDC_ENH_LUMACFG 0x408 > +#define LCDC_ENH_CHROCFG0 0x40c > +#define LCDC_ENH_CHROCFG1 0x410 > +#define LCDC_ENH_DITHERCFG 0x414 > +#define LCDC_ENH_STATUS 0x418 > +#define LCDC_ENH_GAMMA 0x800 > +#define LCDC_ENH_VEE 0x1000 > + > +/* LCD Configure Register */ > +#define LCDC_CFG_LCDPIN_BIT 31 > +#define LCDC_CFG_LCDPIN_MASK (0x1 << LCDC_CFG_LCDPIN_BIT) > +#define LCDC_CFG_LCDPIN_LCD (0x0 << LCDC_CFG_LCDPIN_BIT) > +#define LCDC_CFG_LCDPIN_SLCD (0x1 << LCDC_CFG_LCDPIN_BIT) > +#define LCDC_CFG_TVEPEH BIT(30) > +#define LCDC_CFG_NEWDES BIT(28) > +#define LCDC_CFG_PALBP BIT(27) > +#define LCDC_CFG_TVEN BIT(26) > +#define LCDC_CFG_RECOVER BIT(25) > + > +#define LCDC_CFG_PSM BIT(23) > +#define LCDC_CFG_CLSM BIT(22) > +#define LCDC_CFG_SPLM BIT(21) > +#define LCDC_CFG_REVM BIT(20) > +#define LCDC_CFG_HSYNM BIT(19) > +#define LCDC_CFG_PCLKM BIT(18) > +#define LCDC_CFG_INVDAT BIT(17) > +#define LCDC_CFG_SYNDIR_IN BIT(16) > +#define LCDC_CFG_PSP BIT(15) > +#define LCDC_CFG_CLSP BIT(14) > +#define LCDC_CFG_SPLP BIT(13) > +#define LCDC_CFG_REVP BIT(12) > +#define LCDC_CFG_HSP BIT(11) > +#define LCDC_CFG_PCP BIT(10) > +#define LCDC_CFG_DEP BIT(9) > +#define LCDC_CFG_VSP BIT(8) > +#define LCDC_CFG_MODE_TFT_18BIT BIT(7) > +#define LCDC_CFG_MODE_TFT_16BIT (0 << 7) > +#define LCDC_CFG_MODE_TFT_24BIT BIT(6) > + > +#define LCDC_CFG_MODE_BIT 0 > +#define LCDC_CFG_MODE_MASK (0x0f << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_GENERIC_TFT (0 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_SPECIAL_TFT_1 (1 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_SPECIAL_TFT_2 (2 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_SPECIAL_TFT_3 (3 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_NONINTER_CCIR656 (4 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_INTER_CCIR656 (6 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_SERIAL_TFT (12 << LCDC_CFG_MODE_BIT) > +#define LCDC_CFG_MODE_LCM (13 << LCDC_CFG_MODE_BIT) > + > +/* LCD Control Register */ > +#define LCDC_CTRL_PINMD BIT(31) > +#define LCDC_CTRL_BST_BIT 28 > +#define LCDC_CTRL_BST_MASK (0x7 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_BST_4 (0 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_BST_8 (1 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_BST_16 (2 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_BST_32 (3 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_BST_64 (4 << LCDC_CTRL_BST_BIT) > +#define LCDC_CTRL_RGB565 (0 << 27) > +#define LCDC_CTRL_RGB555 BIT(27) > +#define LCDC_CTRL_OFUP BIT(26) > +#define LCDC_CTRL_PDD_BIT 16 > +#define LCDC_CTRL_PDD_MASK (0xff << LCDC_CTRL_PDD_BIT) > + > +#define LCDC_CTRL_DACTE BIT(14) > +#define LCDC_CTRL_EOFM BIT(13) > +#define LCDC_CTRL_SOFM BIT(12) > +#define LCDC_CTRL_OFUM BIT(11) > +#define LCDC_CTRL_IFUM0 BIT(10) > +#define LCDC_CTRL_IFUM1 BIT(9) > +#define LCDC_CTRL_LDDM BIT(8) > +#define LCDC_CTRL_QDM BIT(7) > +#define LCDC_CTRL_BEDN BIT(6) > +#define LCDC_CTRL_PEDN BIT(5) > +#define LCDC_CTRL_DIS BIT(4) > +#define LCDC_CTRL_ENA BIT(3) > +#define LCDC_CTRL_BPP_BIT 0 > +#define LCDC_CTRL_BPP_MASK (0x07 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_1 (0 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_2 (1 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_4 (2 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_8 (3 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_16 (4 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_18_24 (5 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_CMPS_24 (6 << LCDC_CTRL_BPP_BIT) > +#define LCDC_CTRL_BPP_30 (7 << LCDC_CTRL_BPP_BIT) > + > +#define LCD_TYPE_GENERIC_24_BIT (0 | 1 << 6) > + > +/* LCD Status Register */ > +#define LCDC_STATE_QD BIT(7) > +#define LCDC_STATE_EOF BIT(5) > +#define LCDC_STATE_SOF BIT(4) > +#define LCDC_STATE_OFU BIT(3) > +#define LCDC_STATE_IFU0 BIT(2) > +#define LCDC_STATE_IFU1 BIT(1) > +#define LCDC_STATE_LDD BIT(0) > + > +/* OSD Configure Register */ > +#define LCDC_OSDC_PREMULTI1 BIT(23) > +#define LCDC_OSDC_COEF_SLE1_BIT 21 > +#define LCDC_OSDC_COEF_SLE1_MASK (0x03 << LCDC_OSDC_COEF_SLE1_BIT) > +#define LCDC_OSDC_COEF_SLE1_0 (0 << LCDC_OSDC_COEF_SLE1_BIT) > +#define LCDC_OSDC_COEF_SLE1_1 (1 << LCDC_OSDC_COEF_SLE1_BIT) > +#define LCDC_OSDC_COEF_SLE1_2 (2 << LCDC_OSDC_COEF_SLE1_BIT) > +#define LCDC_OSDC_COEF_SLE1_3 (3 << LCDC_OSDC_COEF_SLE1_BIT) > + > +#define LCDC_OSDC_PREMULTI0 BIT(20) > +#define LCDC_OSDC_COEF_SLE0_BIT 18 > +#define LCDC_OSDC_COEF_SLE0_MASK (0x03 << LCDC_OSDC_COEF_SLE0_BIT) > +#define LCDC_OSDC_COEF_SLE0_0 (0 << LCDC_OSDC_COEF_SLE0_BIT) > +#define LCDC_OSDC_COEF_SLE0_1 (1 << LCDC_OSDC_COEF_SLE0_BIT) > +#define LCDC_OSDC_COEF_SLE0_2 (2 << LCDC_OSDC_COEF_SLE0_BIT) > +#define LCDC_OSDC_COEF_SLE0_3 (3 << LCDC_OSDC_COEF_SLE0_BIT) > +#define LCDC_OSDC_ALPHAMD1 BIT(17) > + > +#define LCDC_OSDC_SOFM1 BIT(15) > +#define LCDC_OSDC_EOFM1 BIT(14) > +#define LCDC_OSDC_SOFM0 BIT(11) > +#define LCDC_OSDC_EOFM0 BIT(10) > +#define LCDC_OSDC_DENDM BIT(9) > +#define LCDC_OSDC_F1EN BIT(4) > +#define LCDC_OSDC_F0EN BIT(3) > +#define LCDC_OSDC_ALPHAEN BIT(2) > +#define LCDC_OSDC_ALPHAMD0 BIT(1) > +#define LCDC_OSDC_OSDEN BIT(0) > + > +/* OSD Control Register */ > +#define LCDC_OSDCTRL_IPU_CLKEN BIT(15) > +#define LCDC_OSDCTRL_RGB0_RGB565 (0 << 5) > +#define LCDC_OSDCTRL_RGB0_RGB555 BIT(5) > +#define LCDC_OSDCTRL_RGB1_RGB565 (0 << 4) > +#define LCDC_OSDCTRL_RGB1_RGB555 BIT(4) > + > +#define LCDC_OSDCTRL_BPP_BIT 0 > +#define LCDC_OSDCTRL_BPP_MASK (0x7 << LCDC_OSDCTRL_BPP_BIT) > +#define LCDC_OSDCTRL_BPP_15_16 (4 << LCDC_OSDCTRL_BPP_BIT) > +#define LCDC_OSDCTRL_BPP_18_24 (5 << LCDC_OSDCTRL_BPP_BIT) > +#define LCDC_OSDCTRL_BPP_CMPS_24 (6 << LCDC_OSDCTRL_BPP_BIT) > +#define LCDC_OSDCTRL_BPP_30 (7 << LCDC_OSDCTRL_BPP_BIT) > + > +/* OSD State Register */ > +#define LCDC_OSDS_SOF1 BIT(15) > +#define LCDC_OSDS_EOF1 BIT(14) > +#define LCDC_OSDS_SOF0 BIT(11) > +#define LCDC_OSDS_EOF0 BIT(10) > +#define LCDC_OSDS_DEND BIT(8) > + > +/* Background 0 or Background 1 Color Register */ > +#define LCDC_BGC_RED_OFFSET 16 > +#define LCDC_BGC_RED_MASK (0xFF << LCDC_BGC_RED_OFFSET) > +#define LCDC_BGC_GREEN_OFFSET 8 > +#define LCDC_BGC_GREEN_MASK (0xFF << LCDC_BGC_GREEN_OFFSET) > +#define LCDC_BGC_BLUE_OFFSET 0 > +#define LCDC_BGC_BLUE_MASK (0xFF << LCDC_BGC_BLUE_OFFSET) > + > +/* Foreground 0 or Foreground 1 Color Key Register */ > +#define LCDC_KEY_KEYEN BIT(31) > +#define LCDC_KEY_KEYMD BIT(30) > +#define LCDC_KEY_RED_OFFSET 16 > +#define LCDC_KEY_RED_MASK (0xFF << LCDC_KEY_RED_OFFSET) > +#define LCDC_KEY_GREEN_OFFSET 8 > +#define LCDC_KEY_GREEN_MASK (0xFF << LCDC_KEY_GREEN_OFFSET) > +#define LCDC_KEY_BLUE_OFFSET 0 > +#define LCDC_KEY_BLUE_MASK (0xFF << LCDC_KEY_BLUE_OFFSET) > +#define LCDC_KEY_MASK (LCDC_KEY_RED_MASK | \ > + | LCDC_KEY_GREEN_MASK \ > + | LCDC_KEY_BLUE_MASK) > + > +/* ALPHA Register */ > +#define LCDC_ALPHA1_OFFSET 8 > +#define LCDC_ALPHA1_MASK (0xFF << LCDC_ALPHA1_OFFSET) > +#define LCDC_ALPHA0_OFFSET 0 > +#define LCDC_ALPHA0_MASK (0xFF << LCDC_ALPHA0_OFFSET) > + > +/* IPU Restart Register */ > +#define LCDC_IPUR_IPUREN BIT(31) > +#define LCDC_IPUR_IPURMASK 0xFFFFFF > + > +/* RGB Control Register */ > +#define LCDC_RGBC_RGBDM BIT(15) > +#define LCDC_RGBC_DMM BIT(14) > +#define LCDC_RGBC_422 BIT(8) > +#define LCDC_RGBC_RGBFMT BIT(7) > +#define LCDC_RGBC_ODDRGB_BIT 4 > +#define LCDC_RGBC_ODDRGB_MASK (0x7 << LCDC_RGBC_ODDRGB_BIT) > +#define LCDC_RGBC_ODD_RGB (0 << LCDC_RGBC_ODDRGB_BIT) /* RGB */ > +#define LCDC_RGBC_ODD_RBG (1 << LCDC_RGBC_ODDRGB_BIT) /* RBG */ > +#define LCDC_RGBC_ODD_GRB (2 << LCDC_RGBC_ODDRGB_BIT) /* GRB */ > +#define LCDC_RGBC_ODD_GBR (3 << LCDC_RGBC_ODDRGB_BIT) /* GBR */ > +#define LCDC_RGBC_ODD_BRG (4 << LCDC_RGBC_ODDRGB_BIT) /* BRG */ > +#define LCDC_RGBC_ODD_BGR (5 << LCDC_RGBC_ODDRGB_BIT) /* BGR */ > + > +#define LCDC_RGBC_EVENRGB_BIT 0 > +#define LCDC_RGBC_EVENRGB_MASK (0x7 << LCDC_RGBC_EVENRGB_BIT) > +#define LCDC_RGBC_EVEN_RGB 0 /* RGB */ > +#define LCDC_RGBC_EVEN_RBG 1 /* RBG */ > +#define LCDC_RGBC_EVEN_GRB 2 /* GRB */ > +#define LCDC_RGBC_EVEN_GBR 3 /* GBR */ > +#define LCDC_RGBC_EVEN_BRG 4 /* BRG */ > +#define LCDC_RGBC_EVEN_BGR 5 /* BGR */ > + > +/* Vertical Synchronize Register */ > +#define LCDC_VSYNC_VPS_BIT 16 > +#define LCDC_VSYNC_VPS_MASK (0xfff << LCDC_VSYNC_VPS_BIT) > +#define LCDC_VSYNC_VPE_BIT 0 > +#define LCDC_VSYNC_VPE_MASK (0xfff << LCDC_VSYNC_VPE_BIT) > + > +/* Horizontal Synchronize Register */ > +#define LCDC_HSYNC_HPS_BIT 16 > +#define LCDC_HSYNC_HPS_MASK (0xfff << LCDC_HSYNC_HPS_BIT) > +#define LCDC_HSYNC_HPE_BIT 0 > +#define LCDC_HSYNC_HPE_MASK (0xfff << LCDC_HSYNC_HPE_BIT) > + > +/* Virtual Area Setting Register */ > +#define LCDC_VAT_HT_BIT 16 > +#define LCDC_VAT_HT_MASK (0xfff << LCDC_VAT_HT_BIT) > +#define LCDC_VAT_VT_BIT 0 > +#define LCDC_VAT_VT_MASK (0xfff << LCDC_VAT_VT_BIT) > + > +/* Display Area Horizontal Start/End Point Register */ > +#define LCDC_DAH_HDS_BIT 16 > +#define LCDC_DAH_HDS_MASK (0xfff << LCDC_DAH_HDS_BIT) > +#define LCDC_DAH_HDE_BIT 0 > +#define LCDC_DAH_HDE_MASK (0xfff << LCDC_DAH_HDE_BIT) > + > +/* Display Area Vertical Start/End Point Register */ > +#define LCDC_DAV_VDS_BIT 16 > +#define LCDC_DAV_VDS_MASK (0xfff << LCDC_DAV_VDS_BIT) > +#define LCDC_DAV_VDE_BIT 0 > +#define LCDC_DAV_VDE_MASK (0xfff << LCDC_DAV_VDE_BIT) > + > +/* Foreground 0 or Foreground 1 XY Position Register */ > +#define LCDC_XYP_YPOS_BIT 16 > +#define LCDC_XYP_YPOS_MASK (0xfff << LCDC_XYP_YPOS_BIT) > +#define LCDC_XYP_XPOS_BIT 0 > +#define LCDC_XYP_XPOS_MASK (0xfff << LCDC_XYP_XPOS_BIT) > + > +/* Foreground 0 or Foreground 1 Size Register */ > +#define LCDC_SIZE_HEIGHT_BIT 16 > +#define LCDC_SIZE_HEIGHT_MASK (0xfff << LCDC_SIZE_HEIGHT_BIT) > +#define LCDC_SIZE_WIDTH_BIT 0 > +#define LCDC_SIZE_WIDTH_MASK (0xfff << LCDC_SIZE_WIDTH_BIT) > + > +/* PS Signal Setting */ > +#define LCDC_PS_PSS_BIT 16 > +#define LCDC_PS_PSS_MASK (0xfff << LCDC_PS_PSS_BIT) > +#define LCDC_PS_PSE_BIT 0 > +#define LCDC_PS_PSE_MASK (0xfff << LCDC_PS_PSE_BIT) > + > +/* CLS Signal Setting */ > +#define LCDC_CLS_CLSS_BIT 16 > +#define LCDC_CLS_CLSS_MASK (0xfff << LCDC_CLS_CLSS_BIT) > +#define LCDC_CLS_CLSE_BIT 0 > +#define LCDC_CLS_CLSE_MASK (0xfff << LCDC_CLS_CLSE_BIT) > + > +/* SPL Signal Setting */ > +#define LCDC_SPL_SPLS_BIT 16 > +#define LCDC_SPL_SPLS_MASK (0xfff << LCDC_SPL_SPLS_BIT) > +#define LCDC_SPL_SPLE_BIT 0 > +#define LCDC_SPL_SPLE_MASK (0xfff << LCDC_SPL_SPLE_BIT) > + > +/* REV Signal Setting */ > +#define LCDC_REV_REVS_BIT 16 > +#define LCDC_REV_REVS_MASK (0xfff << LCDC_REV_REVS_BIT) > + > +/* DMA Command 0 or 1 Register */ > +#define LCDC_CMD_SOFINT BIT(31) > +#define LCDC_CMD_EOFINT BIT(30) > +#define LCDC_CMD_CMD BIT(29) > +#define LCDC_CMD_PAL BIT(28) > +#define LCDC_CMD_COMPEN BIT(27) > +#define LCDC_CMD_FRM_EN BIT(26) > +#define LCDC_CMD_FIELD_SEL BIT(25) > +#define LCDC_CMD_16X16BLOCK BIT(24) > +#define LCDC_CMD_LEN_BIT 0 > +#define LCDC_CMD_LEN_MASK (0xffffff << LCDC_CMD_LEN_BIT) > + > +/* DMA Offsize Register 0,1 */ > +#define LCDC_OFFS_BIT 0 > +#define LCDC_OFFS_OFFSIZE_MASK (0xffffff << LCDC_OFFS_BIT) > + > +/* DMA Page Width Register 0,1 */ > +#define LCDC_PW_BIT 0 > +#define LCDC_PW_PAGEWIDTH_MASK (0xffffff << LCDC_PW_BIT) > + > +/* DMA Command Counter Register 0,1 */ > +#define LCDC_CNUM_BIT 0 > +#define LCDC_CNUM_CNUM_MASK (0xff << LCDC_CNUM_BIT) > + > +/* DMA Command Counter Register */ > +#define LCDC_CPOS_ALPHAMD1 BIT(31) > +#define LCDC_CPOS_RGB_RGB565 (0 << 30) > +#define LCDC_CPOS_RGB_RGB555 BIT(30) > + > +#define LCDC_CPOS_BPP_BIT 27 > +#define LCDC_CPOS_BPP_MASK (0x07 << LCDC_CPOS_BPP_BIT) > +#define LCDC_CPOS_BPP_16 (4 << LCDC_CPOS_BPP_BIT) > +#define LCDC_CPOS_BPP_18_24 (5 << LCDC_CPOS_BPP_BIT) > +#define LCDC_CPOS_BPP_CMPS_24 (6 << LCDC_CPOS_BPP_BIT) > +#define LCDC_CPOS_BPP_30 (7 << LCDC_CPOS_BPP_BIT) > + > +#define LCDC_CPOS_PREMULTI BIT(26) > +#define LCDC_CPOS_COEF_SLE_BIT 24 > +#define LCDC_CPOS_COEF_SLE_MASK (0x3 << LCDC_CPOS_COEF_SLE_BIT) > +#define LCDC_CPOS_COEF_SLE_0 (0 << LCDC_CPOS_COEF_SLE_BIT) > +#define LCDC_CPOS_COEF_SLE_1 (1 << LCDC_CPOS_COEF_SLE_BIT) > +#define LCDC_CPOS_COEF_SLE_2 (2 << LCDC_CPOS_COEF_SLE_BIT) > +#define LCDC_CPOS_COEF_SLE_3 (3 << LCDC_CPOS_COEF_SLE_BIT) > + > +#define LCDC_CPOS_YPOS_BIT 12 > +#define LCDC_CPOS_YPOS_MASK (0xfff << LCDC_CPOS_YPOS_BIT) > +#define LCDC_CPOS_XPOS_BIT 0 > +#define LCDC_CPOS_XPOS_MASK (0xfff << LCDC_CPOS_XPOS_BIT) > + > +/* Foreground 0,1 Size Register */ > +#define LCDC_DESSIZE_ALPHA_BIT 24 > +#define LCDC_DESSIZE_ALPHA_MASK (0xff << LCDC_DESSIZE_ALPHA_BIT) > +#define LCDC_DESSIZE_HEIGHT_BIT 12 > +#define LCDC_DESSIZE_HEIGHT_MASK (0xfff << LCDC_DESSIZE_HEIGHT_BIT) > +#define LCDC_DESSIZE_WIDTH_BIT 0 > +#define LCDC_DESSIZE_WIDTH_MASK (0xfff << LCDC_DESSIZE_WIDTH_BIT) > + > +/* Priority level threshold configure Register */ > +#define LCDC_PCFG_LCDC_PRI_MD BIT(31) > + > +#define LCDC_PCFG_HP_BST_BIT 28 > +#define LCDC_PCFG_HP_BST_MASK (0x7 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_4 (0 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_8 (1 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_16 (2 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_32 (3 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_C16 (5 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_64 (4 << LCDC_PCFG_HP_BST_BIT) > +#define LCDC_PCFG_HP_BST_DIS (7 << LCDC_PCFG_HP_BST_BIT) > + > +#define LCDC_PCFG_PCFG2_BIT 18 > +#define LCDC_PCFG_PCFG2_MASK (0x1ff << LCDC_PCFG_PCFG2_BIT) > +#define LCDC_PCFG_PCFG1_BIT 9 > +#define LCDC_PCFG_PCFG1_MASK (0x1ff << LCDC_PCFG_PCFG1_BIT) > +#define LCDC_PCFG_PCFG0_BIT 0 > +#define LCDC_PCFG_PCFG0_MASK (0x1ff << LCDC_PCFG_PCFG0_BIT) > + > +/* Dual LCDC Channel Control register */ > +/* > + * Select which IPU is able to write back, this field is just > + * available in lcdc1. 0:ipu1; 1:ipu0 > + */ > +#define LCDC_DUAL_CTRL_IPU_WR_SEL BIT(8) > +/* > + * Select which controller output to the tft/slcd panel, this field is just > + * available in lcdc1. 0:lcdc1; 1:lcdc0 > + */ > +#define LCDC_DUAL_CTRL_TFT_SEL BIT(6) > +/* > + * 1: fix the priority of ipu0/1 in lcd internal arbiter; > + * 0: use priority of ipu0/1 generated by lcd in lcd internal arbiter > + */ > +#define LCDC_DUAL_CTRL_PRI_IPU_EN BIT(5) > +#define LCDC_DUAL_CTRL_PRI_IPU_BIT 3 > +#define LCDC_DUAL_CTRL_PRI_IPU_MASK (0x3 << LCDC_DUAL_CTRL_PRI_IPU_BIT) > +/* > + * 1: fix the priority of lcd0/1 in lcd internal arbiter; > + * 0: use priority of lcd0/1 generated by lcd in lcd internal arbiter > + */ > +#define LCDC_DUAL_CTRL_PRI_LCD_EN BIT(2) > +#define LCDC_DUAL_CTRL_PRI_LCD_BIT 0 > +#define LCDC_DUAL_CTRL_PRI_LCD_MASK (0x3 << LCDC_DUAL_CTRL_PRI_LCD_BIT) > + > +/* Image Enhancement CFG Register */ > +#define LCDC_ENH_CFG_DITHER_EN BIT(9) > +#define LCDC_ENH_CFG_YCC2RGB_EN BIT(8) > +#define LCDC_ENH_CFG_SATURATION_EN BIT(7) > +#define LCDC_ENH_CFG_VEE_EN BIT(6) > +#define LCDC_ENH_CFG_HUE_EN BIT(5) > +#define LCDC_ENH_CFG_BRIGHTNESS_EN BIT(4) > +#define LCDC_ENH_CFG_CONTRAST_EN BIT(3) > +#define LCDC_ENH_CFG_RGB2YCC_EN BIT(2) > +#define LCDC_ENH_CFG_GAMMA_EN BIT(1) > +#define LCDC_ENH_CFG_ENH_EN BIT(0) > + > +/* Color Space Conversion CFG Register */ > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_BIT 2 /* YCbCr to RGB */ > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_MASK (0x03 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_0 (0 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_1 (1 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_2 (2 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) > +#define LCDC_ENH_CSCCFG_YCC2RGBMD_3 (3 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) > +/* > + * 00:601WIDE; 01:601NARROW > + * 10:709WIDE; 11:709NARROW > + * WIDE:RGB range 16-235 > + * NARROW:RGB range 0-255 > +*/ > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_BIT 0 /* RGB to YCbCr*/ > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_MASK (0x03 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_0 (0 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_1 (1 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_2 (2 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) > +#define LCDC_ENH_CSCCFG_RGB2YCCMD_3 (3 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) > + > +/* LUMA CFG Register */ > +#define LCDC_ENH_LUMACFG_BRIGHT_BIT 16 /* > + * Brightness value :0x0-0x7ff > + * means 0.9999~-0.9999 > + */ > +#define LCDC_ENH_LUMACFG_BRIGHT_MASK (0x7ff << LCDC_ENH_LUMACFG_BRIGHT_BIT) > + > +#define LCDC_ENH_LUMACFG_CONTRAST_BIT 0 /* > + * Contrast value :0x0-0x7ff > + * means 0~1.9999 > + */ > +#define LCDC_ENH_LUMACFG_CONTRAST_MASK (0x7ff << LCDC_ENH_LUMACFG_CONTRAST_BIT) > + > +/* CHROMA0 CFG Register */ > +#define LCDC_ENH_CHROCFG0_HUE_SIN_BIT 16 > +#define LCDC_ENH_CHROCFG0_HUE_SIN_MASK (0xfff << LCDC_ENH_CHROCFG0_HUE_SIN_BIT) > +#define LCDC_ENH_CHROCFG0_HUE_COS_BIT 0 > +#define LCDC_ENH_CHROCFG0_HUE_COS_MASK (0xfff << LCDC_ENH_CHROCFG0_HUE_COS_BIT) > + > +/* CHROMA1 CFG Register */ > +#define LCDC_ENH_CHROCFG1_SATUR_BIT 0 > +#define LCDC_ENH_CHROCFG1_SATUR_MASK (0x7ff << LCDC_ENH_CHROCFG1_SATUR_BIT) > + > +/* DITHER CFG Register */ > +/* > + * 00:8bit dither > + * 01:6bit dither > + * 10:5bit dither > + * 11:4bit dither > +*/ > +#define LCDC_ENH_DITHERCFG_RED_BIT 4 > +#define LCDC_ENH_DITHERCFG_RED_MASK (0x03 << LCDC_ENH_DITHERCFG_RED_BIT) > +#define LCDC_ENH_DITHERCFG_GREEN_BIT 2 > +#define LCDC_ENH_DITHERCFG_GREEN_MASK (0x03 << LCDC_ENH_DITHERCFG_GREEN_BIT) > +#define LCDC_ENH_DITHERCFG_BLUE_BIT 0 > +#define LCDC_ENH_DITHERCFG_BLUE_MASK (0x03 << LCDC_ENH_DITHERCFG_BLUE_BIT) > + > +/* Enhance Status Register */ > +#define LCDC_ENH_STATUS_DITHER_DIS BIT(9) > +#define LCDC_ENH_STATUS_YCC2RGB_DIS BIT(8) > +#define LCDC_ENH_STATUS_SATURATION_DIS BIT(7) > +#define LCDC_ENH_STATUS_VEE_DIS BIT(6) > +#define LCDC_ENH_STATUS_HUE_DIS BIT(5) > +#define LCDC_ENH_STATUS_BRIGHTNESS_DIS BIT(4) > +#define LCDC_ENH_STATUS_CONTRAST_DIS BIT(3) > +#define LCDC_ENH_STATUS_RGB2YCC_DIS BIT(2) > +#define LCDC_ENH_STATUS_GAMMA_DIS BIT(1) > + > +/* GAMMA CFG Register */ > +#define LCDC_ENH_GAMMA_DATA1_BIT 16 > +#define LCDC_ENH_GAMMA_DATA1_MASK (0x3ff << LCDC_ENH_GAMMA_DATA1_BIT) > +#define LCDC_ENH_GAMMA_DATA0_BIT 0 > +#define LCDC_ENH_GAMMA_DATA0_MASK (0x3ff << LCDC_ENH_GAMMA_DATA0_BIT) > +#define LCDC_ENH_GAMMA_LEN 0x800 > + > +/* VEE CFG Register */ > +#define LCDC_ENH_VEE_VEE_DATA1_BIT 16 > +#define LCDC_ENH_VEE_VEE_DATA1_MASK (0x3ff << LCDC_ENH_VEE_VEE_DATA1_BIT) > +#define LCDC_ENH_VEE_VEE_DATA0_BIT 0 > +#define LCDC_ENH_VEE_VEE_DATA0_MASK (0x3ff << LCDC_ENH_VEE_VEE_DATA0_BIT) > +#define LCDC_ENH_VEE_LEN 0x800 > + > +/* Register Map Of SLCD (Smart LCD Controller) */ > +#define SLCDC_CFG 0xA0 > +#define SLCDC_CTRL 0xA4 > +#define SLCDC_STATE 0xA8 > +#define SLCDC_DATA 0xAc > + > +/* SLCD Configure Register */ > +#define SLCDC_CFG_DWIDTH_BIT 10 > +#define SLCDC_CFG_DWIDTH_MASK (0x7 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_18BIT (0 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_16BIT (1 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_8BIT_x3 (2 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_8BIT_x2 (3 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_8BIT_x1 (4 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_24BIT (5 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_DWIDTH_9BIT_x2 (7 << SLCDC_CFG_DWIDTH_BIT) > +#define SLCDC_CFG_CWIDTH_BIT 8 > +#define SLCDC_CFG_CWIDTH_MASK (0x3 << SLCDC_CFG_CWIDTH_BIT) > +#define SLCDC_CFG_CWIDTH_16BIT (0 << SLCDC_CFG_CWIDTH_BIT) > +#define SLCDC_CFG_CWIDTH_8BIT (1 << SLCDC_CFG_CWIDTH_BIT) > +#define SLCDC_CFG_CWIDTH_18BIT (2 << SLCDC_CFG_CWIDTH_BIT) > +#define SLCDC_CFG_CWIDTH_24BIT (3 << SLCDC_CFG_CWIDTH_BIT) > +#define SLCDC_CFG_CS_ACTIVE_LOW (0 << 4) > +#define SLCDC_CFG_CS_ACTIVE_HIGH BIT(4) > +#define SLCDC_CFG_RS_CMD_LOW (0 << 3) > +#define SLCDC_CFG_RS_CMD_HIGH BIT(3) > +#define SLCDC_CFG_CLK_ACTIVE_FALLING (0 << 1) > +#define SLCDC_CFG_CLK_ACTIVE_RISING BIT(1) > +#define SLCDC_CFG_TYPE_PARALLEL (0 << 0) > +#define SLCDC_CFG_TYPE_SERIAL BIT(0) > + > +/* SLCD Control Register */ > +#define SLCDC_CTRL_DMA_MODE BIT(2) > +#define SLCDC_CTRL_DMA_START BIT(1) > +#define SLCDC_CTRL_DMA_EN BIT(0) > + > +/* SLCD Status Register */ > +#define SLCDC_STATE_BUSY BIT(0) > + > +/* SLCD Data Register */ > +#define SLCDC_DATA_RS_DATA (0 << 31) > +#define SLCDC_DATA_RS_COMMAND BIT(31) > + > +/* Register Map Of LVDSC (LVDS Controller) */ > +#define LVDS_TXCTRL 0x3c0 > +#define LVDS_TXPLL0 0x3c4 > +#define LVDS_TXPLL1 0x3c8 > +#define LVDS_TXECTRL 0x3cc > + > +/* TXCTRL (LVDS Transmitter Control Register) */ > +#define LVDS_MODEL_SEL BIT(31) > +#define LVDS_TX_PDB BIT(30) > +#define LVDS_TX_PDB_CK BIT(29) > +#define LVDS_RESERVE(n) (1 << 20 + (n)) > +#define LVDS_TX_RSTB BIT(18) > +#define LVDS_TX_CKBIT_PHA_SEL BIT(17) > +#define LVDS_TX_CKBYTE_PHA_SEL BIT(16) > + > +#define LVDS_TX_CKOUT_PHA_S_BIT 13 > +#define LVDS_TX_CKOUT_PHA_S_MASK (0x07 << LVDS_TX_CKOUT_PHA_S_BIT) > + > +#define LVDS_TX_CKOUT_SET BIT(12) > +#define LVDS_TX_OUT_SEL BIT(11) > +#define LVDS_TX_DLY_SEL_BIT 8 > +#define LVDS_TX_DLY_SEL_MASK (0x07 << LVDS_TX_DLY_SEL_BIT) > +#define LVDS_TX_AMP_ADJ BIT(7) > +#define LVDS_TX_LVDS BIT(6) > +#define LVDS_TX_CR_BIT 3 > +#define LVDS_TX_CR_MASK (0x07 << LVDS_TX_CR_BIT) > +#define LVDS_TX_CR_CK BIT(2) > +#define LVDS_TX_OD_S BIT(1) > +#define LVDS_TX_OD_EN BIT(0) > + > +/* TXPLL0 (LVDS Transmitter's PLL Control Register 0 */ > + > +#define LVDS_PLL_LOCK BIT(31) > +#define LVDS_PLL_EN BIT(30) > +#define LVDS_BG_PWD BIT(29) > +#define LVDS_PLL_SSC_EN BIT(27) > +#define LVDS_PLL_SSC_MODE BIT(26) > +#define LVDS_PLL_TEST BIT(25) > +#define LVDS_PLL_POST_DIVA_BIT 21 > +#define LVDS_PLL_POST_DIVA_MASK (0x03 << LVDS_PLL_POST_DIVA_BIT) > +#define LVDS_PLL_POST_DIVB_BIT 16 > +#define LVDS_PLL_POST_DIVB_MASK (0x1f << LVDS_PLL_POST_DIVB_BIT) > +#define LVDS_PLL_PLLN_BIT 8 > +#define LVDS_PLL_PLLN_MASK (0x7f << LVDS_PLL_PLLN_BIT) > +#define LVDS_PLL_TEST_DIV_BIT 6 > +#define LVDS_PLL_TEST_DIV_MASK (0x03 << LVDS_PLL_TEST_DIV_BIT) > +#define LVDS_PLL_TEST_DIV_2 (0 << LVDS_PLL_TEST_DIV_BIT) > +#define LVDS_PLL_TEST_DIV_4 (1 << LVDS_PLL_TEST_DIV_BIT) > +#define LVDS_PLL_TEST_DIV_8 (2 << LVDS_PLL_TEST_DIV_BIT) > +#define LVDS_PLL_TEST_DIV_16 (3 << LVDS_PLL_TEST_DIV_BIT) > +#define LVDS_PLL_IN_BYPASS (1 << 5) > +#define LVDS_PLL_INDIV_BIT 0 > +#define LVDS_PLL_INDIV_MASK (0x1f << LVDS_PLL_INDIV_BIT) > + > +/* TXPLL1 (LVDS Transmitter's PLL Control Register 1 */ > + > +#define LVDS_PLL_ICP_SEL_BIT 29 > +#define LVDS_PLL_ICP_SEL_MASK (0x07 << LVDS_PLL_ICP_SEL_BIT) > +#define LVDS_PLL_KVCO_BIT 26 > +#define LVDS_PLL_KVCO_MASK (0x03 << LVDS_PLL_KVCO_BIT) > +#define LVDS_PLL_IVCO_SEL_BIT 24 > +#define LVDS_PLL_IVCO_SEL_MASK (0x03 << LVDS_PLL_IVCO_SEL_BIT) > +#define LVDS_PLL_SSCN_BIT 17 > +#define LVDS_PLL_SSCN_MASK (0x7f << LVDS_PLL_SSCN_BIT) > +#define LVDS_PLL_COUNT_BIT 4 > +#define LVDS_PLL_COUNT_MASK (0x1fff << LVDS_PLL_COUNT_BIT) > +#define LVDS_PLL_GAIN_BIT 0 > +#define LVDS_PLL_GAIN_MASK (0x0f << LVDS_PLL_GAIN_BIT) > + > +/* TXECTRL (LVDS Transmitter's Enhance Control */ > + > +#define LVDS_TX_EM_S_BIT 9 > +#define LVDS_TX_EM_S_MASK (0x03 << LVDS_TX_EM_S_BIT) > +#define LVDS_TX_EM_EN BIT(8) > +#define LVDS_TX_LDO_VO_S_BIT 5 > +#define LVDS_TX_LDO_VO_S_MASK (0x03 << LVDS_TX_LDO_VO_S_BIT) > +#define LVDS_TX_LDO_VO_S_0 (0x00 << LVDS_TX_LDO_VO_S_BIT) > +#define LVDS_TX_LDO_VO_S_1 (0x01 << LVDS_TX_LDO_VO_S_BIT) > +#define LVDS_TX_LDO_VO_S_2 (0x02 << LVDS_TX_LDO_VO_S_BIT) > +#define LVDS_TX_LDO_VO_S_3 (0x03 << LVDS_TX_LDO_VO_S_BIT) > +#define LVDS_PLL_PL_BP BIT(4) > + > +/* > + * Internal 7x clock phase fine tuning for data > + * setup/hold time optimization > + */ > +#define LVDS_TX_CK_PHA_FINE_BIT 2 > +#define LVDS_TX_CK_PHA_FINE_MASK (0x03 << LVDS_TX_CK_PHA_FINE_BIT) > +/* > + * Internal 7x clock phase coarse tuning for data > + * setup/hold time optimization > + */ > +#define LVDS_TX_CK_PHA_COAR_BIT 0 > +#define LVDS_TX_CK_PHA_COAR_MASK (0x03 << LVDS_TX_CK_PHA_COAR_BIT) > + > +/* > + * Helpers: > + */ > + > +static inline unsigned long jz4780_read(struct drm_device *dev, u32 reg) > +{ > + struct jz4780_drm_private *priv = dev->dev_private; > + > + return ioread32(priv->mmio + reg); > +} > + > +static inline void jz4780_write(struct drm_device *dev, u32 reg, u32 data) > +{ > + struct jz4780_drm_private *priv = dev->dev_private; > + > + iowrite32(data, priv->mmio + reg); > +} > +#endif /* __JZ4780_REGS_H__ */ > -- > 1.9.1 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 151a050..77edd60 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -208,3 +208,5 @@ source "drivers/gpu/drm/sti/Kconfig" source "drivers/gpu/drm/amd/amdkfd/Kconfig" source "drivers/gpu/drm/imx/Kconfig" + +source "drivers/gpu/drm/jz4780/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 2c239b9..f8403e1 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-$(CONFIG_DRM_STI) += sti/ obj-$(CONFIG_DRM_IMX) += imx/ +obj-$(CONFIG_DRM_JZ4780) += jz4780/ obj-y += i2c/ obj-y += panel/ obj-y += bridge/ diff --git a/drivers/gpu/drm/jz4780/Kconfig b/drivers/gpu/drm/jz4780/Kconfig new file mode 100644 index 0000000..ae417d1 --- /dev/null +++ b/drivers/gpu/drm/jz4780/Kconfig @@ -0,0 +1,12 @@ +config DRM_JZ4780 + tristate "DRM Support for Ingenic JZ4780 LCDC Display Controller" + depends on DRM && OF + select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select VIDEOMODE_HELPERS + help + Choose this option if you have an Ingenic JZ4780 SoC with LCDC display + controller, for example the MIPS Creator CI20 board + diff --git a/drivers/gpu/drm/jz4780/Makefile b/drivers/gpu/drm/jz4780/Makefile new file mode 100644 index 0000000..3e896c5 --- /dev/null +++ b/drivers/gpu/drm/jz4780/Makefile @@ -0,0 +1,3 @@ +jz4780-y := jz4780_crtc.o jz4780_drv.o + +obj-$(CONFIG_DRM_JZ4780) += jz4780.o diff --git a/drivers/gpu/drm/jz4780/jz4780_crtc.c b/drivers/gpu/drm/jz4780/jz4780_crtc.c new file mode 100644 index 0000000..da3f63a --- /dev/null +++ b/drivers/gpu/drm/jz4780/jz4780_crtc.c @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2014 Imagination Technologies + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * LCDC CRTC driver for Ingenic JZ4780, based on the tilcdc driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/component.h> + +#include <drm/drm_flip_work.h> +#include <drm/drm_plane_helper.h> + +#include "jz4780_drv.h" +#include "jz4780_regs.h" + +/** + * @next: physical address of next frame descriptor + * @databuf: physical address of buffer + * @id: frame ID + * @cmd: DMA command and buffer length(in word) + * @offsize: DMA off size, in word + * @page_width: DMA page width, in word + * @cpos: smart LCD mode is commands' number, other is bpp, + * premulti and position of foreground 0, 1 + * @desc_size: alpha and size of foreground 0, 1 + */ +struct jz4780_framedesc { + uint32_t next; + uint32_t databuf; + uint32_t id; + uint32_t cmd; + uint32_t offsize; + uint32_t page_width; + uint32_t cpos; + uint32_t desc_size; +} __packed; + +struct jz4780_crtc { + struct drm_crtc base; + struct device *dev; + struct drm_device *drm_dev; + + const struct jz4780_panel_info *info; + uint32_t dirty; + + struct drm_pending_vblank_event *event; + int dpms; + wait_queue_head_t frame_done_wq; + bool frame_done; + + /* fb currently set to scanout 0/1: */ + struct drm_framebuffer *scanout[2]; + + /* for deferred fb unref's: */ + struct drm_flip_work unref_work; + + /* DMA descriptors */ + struct jz4780_framedesc *framedesc; + dma_addr_t framedesc_phys; +}; +#define to_jz4780_crtc(x) container_of(x, struct jz4780_crtc, base) + +static void unref_worker(struct drm_flip_work *work, void *val) +{ + struct jz4780_crtc *jz4780_crtc = + container_of(work, struct jz4780_crtc, unref_work); + struct drm_device *dev = jz4780_crtc->base.dev; + + mutex_lock(&dev->mode_config.mutex); + drm_framebuffer_unreference(val); + mutex_unlock(&dev->mode_config.mutex); +} + +static void set_scanout(struct drm_crtc *crtc, int n) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct jz4780_drm_private *priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->primary->fb; + struct jz4780_framedesc *framedesc = jz4780_crtc->framedesc; + struct drm_gem_cma_object *gem; + unsigned int depth, bpp; + int fg0_line_size; + int fg0_frm_size; + int height_width; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + pm_runtime_get_sync(dev->dev); + + /* lcd display area */ + fg0_line_size = crtc->mode.hdisplay * bpp >> 3; + /* word aligned and in word */ + fg0_line_size = ALIGN(fg0_line_size, 4) >> 2; + fg0_frm_size = fg0_line_size * crtc->mode.vdisplay; + + height_width = (crtc->mode.vdisplay - 1) << LCDC_DESSIZE_HEIGHT_BIT + & LCDC_DESSIZE_HEIGHT_MASK; + height_width |= ((crtc->mode.hdisplay - 1) << LCDC_DESSIZE_WIDTH_BIT + & LCDC_DESSIZE_WIDTH_MASK); + + if (n == 0) { + framedesc[0].next = jz4780_crtc->framedesc_phys + + sizeof(struct jz4780_framedesc); + framedesc[0].databuf = gem->paddr; + framedesc[0].id = 0xda0; + framedesc[0].cmd = LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN + | fg0_frm_size; + framedesc[0].offsize = 0; + framedesc[0].page_width = 0; + framedesc[0].cpos = 0x2d000000; + framedesc[0].desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; + framedesc[0].desc_size |= height_width; + + jz4780_write(dev, LCDC_DA0, framedesc[0].next); + } else { + framedesc[1].next = jz4780_crtc->framedesc_phys; + framedesc[1].id = 0xda1; + framedesc[1].databuf = gem->paddr; + framedesc[1].offsize = 0; + framedesc[1].page_width = 0; + framedesc[1].cmd = (LCDC_CMD_EOFINT | LCDC_CMD_FRM_EN) + | fg0_frm_size; + + framedesc[1].desc_size = 0xff << LCDC_DESSIZE_ALPHA_BIT; + framedesc[1].desc_size |= height_width; + + framedesc[1].cpos = 0x2f000000; + jz4780_write(dev, LCDC_DA1, framedesc[1].next); + } + + if (jz4780_crtc->scanout[n]) { + drm_flip_work_queue(&jz4780_crtc->unref_work, + jz4780_crtc->scanout[n]); + drm_flip_work_commit(&jz4780_crtc->unref_work, priv->wq); + } + jz4780_crtc->scanout[n] = crtc->primary->fb; + drm_framebuffer_reference(jz4780_crtc->scanout[n]); + pm_runtime_put_sync(dev->dev); +} + +static void update_scanout(struct drm_crtc *crtc) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_device *dev = crtc->dev; + + if (jz4780_crtc->dpms == DRM_MODE_DPMS_ON) { + drm_vblank_get(dev, 0); + } else { + /* not enabled yet, so update registers immediately: */ + jz4780_write(dev, LCDC_STATE, 0); + set_scanout(crtc, 0); + set_scanout(crtc, 1); + } +} + +static void start(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + uint32_t ctrl; + + jz4780_write(dev, LCDC_STATE, 0); + jz4780_write(dev, LCDC_OSDS, 0); + ctrl = jz4780_read(dev, LCDC_CTRL); + ctrl |= LCDC_CTRL_ENA; + ctrl &= ~LCDC_CTRL_DIS; + jz4780_write(dev, LCDC_CTRL, ctrl); + +} + +static void stop(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + int count = 5; + uint32_t ctrl; + + ctrl = jz4780_read(dev, LCDC_CTRL); + ctrl |= LCDC_CTRL_DIS; + jz4780_write(dev, LCDC_CTRL, ctrl); + while (!(jz4780_read(dev, LCDC_STATE) & LCDC_STATE_LDD) + && count--) { + usleep_range(1000, 2000); + } + if (count >= 0) { + ctrl = jz4780_read(dev, LCDC_STATE); + ctrl &= ~LCDC_STATE_LDD; + jz4780_write(dev, LCDC_STATE, ctrl); + } else { + DRM_DEBUG_DRIVER("LCDC normal disable state wrong"); + } + +} + +static void jz4780_crtc_destroy(struct drm_crtc *crtc) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + + drm_crtc_cleanup(crtc); + drm_flip_work_cleanup(&jz4780_crtc->unref_work); + +} + +static int jz4780_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_device *dev = crtc->dev; + + if (jz4780_crtc->event) { + dev_err(dev->dev, "already pending page flip!\n"); + return -EBUSY; + } + + crtc->primary->fb = fb; + jz4780_crtc->event = event; + update_scanout(crtc); + + return 0; +} + +static void jz4780_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_device *dev = crtc->dev; + + /* we really only care about on or off: */ + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + if (jz4780_crtc->dpms == mode) + return; + + jz4780_crtc->dpms = mode; + + pm_runtime_get_sync(dev->dev); + + if (mode == DRM_MODE_DPMS_ON) { + pm_runtime_forbid(dev->dev); + start(crtc); + } else { + jz4780_crtc->frame_done = false; + stop(crtc); + pm_runtime_allow(dev->dev); + } + + pm_runtime_put_sync(dev->dev); +} + +static bool jz4780_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + DRM_DEBUG_DRIVER("Mode Fixup not supported by driver yet\n"); + return true; +} + +static void jz4780_crtc_prepare(struct drm_crtc *crtc) +{ + + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void jz4780_crtc_commit(struct drm_crtc *crtc) +{ + + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +} + +static int jz4780_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; + int ret; + uint32_t pcfg; + + uint16_t hds, vds; + uint16_t hde, vde; + uint16_t ht, vt; + uint32_t cfg, ctrl; + unsigned int rgb_ctrl; + + ret = jz4780_crtc_mode_valid(crtc, mode); + if (WARN_ON(ret)) + return ret; + + pm_runtime_get_sync(dev->dev); + + /* Configure timings: */ + hbp = mode->htotal - mode->hsync_end; + hfp = mode->hsync_start - mode->hdisplay; + hsw = mode->hsync_end - mode->hsync_start; + vbp = mode->vtotal - mode->vsync_end; + vfp = mode->vsync_start - mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + + hds = hsw + hbp; + hde = hds + mode->hdisplay; + ht = hde + hfp; + + vds = vsw + vbp; + vde = vds + mode->vdisplay; + vt = vde + vfp; + + cfg = LCDC_CFG_NEWDES | LCDC_CFG_RECOVER | LCDC_CFG_MODE_TFT_24BIT; + cfg |= LCDC_CFG_PSM; + cfg |= LCDC_CFG_CLSM; + cfg |= LCDC_CFG_SPLM; + cfg |= LCDC_CFG_REVM; + cfg |= LCDC_CFG_PCP; + + ctrl = LCDC_CTRL_BST_64 | LCDC_CTRL_OFUM; + + /* magic number */ + pcfg = 0xC0000000 | (511<<18) | (400<<9) | (256<<0); + + jz4780_write(dev, LCDC_VAT, (ht << 16) | vt); + jz4780_write(dev, LCDC_DAH, (hds << 16) | hde); + jz4780_write(dev, LCDC_DAV, (vds << 16) | vde); + + jz4780_write(dev, LCDC_HSYNC, hsw); + jz4780_write(dev, LCDC_VSYNC, vsw); + + jz4780_write(dev, LCDC_CFG, cfg); + ctrl |= jz4780_read(dev, LCDC_CTRL); + jz4780_write(dev, LCDC_CTRL, ctrl); + jz4780_write(dev, LCDC_PCFG, pcfg); + + rgb_ctrl = LCDC_RGBC_RGBFMT | LCDC_RGBC_ODD_RGB | + LCDC_RGBC_EVEN_RGB; + + jz4780_write(dev, LCDC_RGBC, rgb_ctrl); + + update_scanout(crtc); + jz4780_crtc_update_clk(crtc); + + pm_runtime_put_sync(dev->dev); + + return 0; +} + +static const struct drm_crtc_funcs jz4780_crtc_funcs = { + .destroy = jz4780_crtc_destroy, + .set_config = drm_crtc_helper_set_config, + .page_flip = jz4780_crtc_page_flip, +}; + +static const struct drm_crtc_helper_funcs jz4780_crtc_helper_funcs = { + .dpms = jz4780_crtc_dpms, + .mode_fixup = jz4780_crtc_mode_fixup, + .prepare = jz4780_crtc_prepare, + .commit = jz4780_crtc_commit, + .mode_set = jz4780_crtc_mode_set, +}; + +int jz4780_crtc_max_width(struct drm_crtc *crtc) +{ + return 2048; +} + +int jz4780_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct jz4780_drm_private *priv = crtc->dev->dev_private; + unsigned int bandwidth; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; + + /* + * check to see if the width is within the range that + * the LCD Controller physically supports + */ + if (mode->hdisplay > 2048) + return MODE_VIRTUAL_X; + + /* width must be multiple of 16 */ + if (mode->hdisplay & 0xf) + return MODE_VIRTUAL_X; + + if (mode->vdisplay > 2048) + return MODE_VIRTUAL_Y; + + DRM_DEBUG_DRIVER("Processing mode %dx%d@%d with pixel clock %d", + mode->hdisplay, mode->vdisplay, + drm_mode_vrefresh(mode), mode->clock); + + hbp = mode->htotal - mode->hsync_end; + hfp = mode->hsync_start - mode->hdisplay; + hsw = mode->hsync_end - mode->hsync_start; + vbp = mode->vtotal - mode->vsync_end; + vfp = mode->vsync_start - mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + + if ((hbp-1) & ~0x3ff) { + DRM_DEBUG_DRIVER("Prune: Horizontal Back Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hfp-1) & ~0x3ff) { + DRM_DEBUG_DRIVER("Prune: Horizontal Front Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hsw-1) & ~0x3ff) { + DRM_DEBUG_DRIVER("Prune: Horizontal Sync Width out of range"); + return MODE_HSYNC_WIDE; + } + + if (vbp & ~0xff) { + DRM_DEBUG_DRIVER("Prune: Vertical Back Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if (vfp & ~0xff) { + DRM_DEBUG_DRIVER("Prune: Vertical Front Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if ((vsw-1) & ~0x3f) { + DRM_DEBUG_DRIVER("Prune: Vertical Sync Width out of range"); + return MODE_VSYNC_WIDE; + } + + /* + * some devices have a maximum allowed pixel clock + * configured from the DT + */ + if (mode->clock > priv->max_pixelclock) { + DRM_DEBUG_DRIVER("Prune: pixel clock too high"); + return MODE_CLOCK_HIGH; + } + + /* + * some devices further limit the max horizontal resolution + * configured from the DT + */ + if (mode->hdisplay > priv->max_width) { + DRM_DEBUG_DRIVER("Prune: Bad width"); + return MODE_BAD_WIDTH; + } + + /* filter out modes that would require too much memory bandwidth: */ + bandwidth = mode->hdisplay * mode->vdisplay * + drm_mode_vrefresh(mode); + if (bandwidth > priv->max_bandwidth) { + DRM_DEBUG_DRIVER("Prune: exceeds defined bandwidth limit %d", + bandwidth); + return MODE_BAD; + } + + return MODE_OK; +} + +void jz4780_crtc_update_clk(struct drm_crtc *crtc) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct jz4780_drm_private *priv = dev->dev_private; + int dpms = jz4780_crtc->dpms; + unsigned int lcd_clk; + int ret; + + pm_runtime_get_sync(dev->dev); + + if (dpms == DRM_MODE_DPMS_ON) + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + /* in raster mode, minimum divisor is 2: */ + ret = clk_set_rate(priv->disp_clk, crtc->mode.clock * 1000); + if (ret) { + dev_err(dev->dev, "failed to set display clock rate to: %d\n", + crtc->mode.clock); + goto out; + } + + lcd_clk = clk_get_rate(priv->clk); + + DRM_DEBUG_DRIVER("lcd_clk=%u, mode clock=%d", lcd_clk, + crtc->mode.clock); + DRM_DEBUG_DRIVER("fck=%lu, dpll_disp_ck=%lu", clk_get_rate(priv->clk), + clk_get_rate(priv->disp_clk)); + + if (dpms == DRM_MODE_DPMS_ON) + jz4780_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + +out: + pm_runtime_put_sync(dev->dev); +} + +irqreturn_t jz4780_crtc_irq(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + unsigned int state; + unsigned int tmp; + + state = jz4780_read(dev, LCDC_STATE); + + if (state & LCDC_STATE_EOF) { + jz4780_write(dev, LCDC_STATE, state & ~LCDC_STATE_EOF); + update_scanout(crtc); + } + + if (state & LCDC_STATE_OFU) { + DRM_DEBUG_DRIVER("Out FiFo underrun\n"); + jz4780_write(dev, LCDC_STATE, state & ~LCDC_STATE_OFU); + tmp = jz4780_read(dev, LCDC_CTRL); + jz4780_write(dev, LCDC_CTRL, tmp & ~LCDC_CTRL_OFUM); + update_scanout(crtc); + start(crtc); + } + + return IRQ_HANDLED; +} + +void jz4780_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) +{ + struct jz4780_crtc *jz4780_crtc = to_jz4780_crtc(crtc); + struct drm_pending_vblank_event *event; + struct drm_device *dev = crtc->dev; + unsigned long flags; + + /* Destroy the pending vertical blanking event associated with the + * pending page flip, if any, and disable vertical blanking interrupts. + */ + spin_lock_irqsave(&dev->event_lock, flags); + event = jz4780_crtc->event; + if (event && event->base.file_priv == file) { + jz4780_crtc->event = NULL; + event->base.destroy(&event->base); + drm_vblank_put(dev, 0); + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +struct drm_crtc *jz4780_crtc_create(struct jz4780_crtc *jz4780_crtc) +{ + + struct drm_crtc *crtc; + struct device_node *port; + struct drm_device *drm_dev = jz4780_crtc->drm_dev; + struct device *dev = jz4780_crtc->dev; + int ret; + + jz4780_crtc->framedesc = dma_alloc_coherent(dev, + sizeof(struct jz4780_framedesc) * 2, + &jz4780_crtc->framedesc_phys, + GFP_KERNEL | GFP_ATOMIC); + if (!jz4780_crtc->framedesc) { + dev_err(dev, "desc allocation failed\n"); + return NULL; + } + + crtc = &jz4780_crtc->base; + + jz4780_crtc->dpms = DRM_MODE_DPMS_OFF; + init_waitqueue_head(&jz4780_crtc->frame_done_wq); + + drm_flip_work_init(&jz4780_crtc->unref_work, + "unref", unref_worker); + + + ret = drm_crtc_init(drm_dev, crtc, &jz4780_crtc_funcs); + if (ret < 0) + goto fail; + + drm_crtc_helper_add(crtc, &jz4780_crtc_helper_funcs); + + port = of_get_child_by_name(dev->of_node, "port"); + if (!port) { + DRM_ERROR("no port node found in %s\n", + dev->of_node->full_name); + goto fail; + } + + crtc->port = port; + + return crtc; + +fail: + jz4780_crtc_destroy(crtc); + return NULL; +} + +static const struct of_device_id jz4780_driver_dt_match[] = { + { .compatible = "ingenic,jz4780-lcd", + .data = NULL }, + {}, +}; + +static int jz4780_crtc_bind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + const struct of_device_id *of_id; + struct drm_device *drm_dev = data; + struct jz4780_drm_private *priv = drm_dev->dev_private; + struct resource *res; + struct device_node *node = dev->of_node; + struct jz4780_crtc *jz4780_crtc; + + jz4780_crtc = devm_kzalloc(dev, sizeof(*jz4780_crtc), GFP_KERNEL); + if (!jz4780_crtc) + return -ENOMEM; + + jz4780_crtc->dev = dev; + jz4780_crtc->drm_dev = drm_dev; + dev_set_drvdata(dev, jz4780_crtc); + + of_id = of_match_device(jz4780_driver_dt_match, dev); + if (!of_id) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + DRM_DEBUG_DRIVER("failed to get memory resource\n"); + return -EINVAL; + } + + priv->mmio = ioremap_nocache(res->start, resource_size(res)); + if (!priv->mmio) { + DRM_DEBUG_DRIVER("failed to ioremap\n"); + return -ENOMEM; + } + + priv->clk = devm_clk_get(dev, "lcd_clk"); + if (IS_ERR(priv->clk)) { + DRM_DEBUG_DRIVER("failed to get lcd clock\n"); + return -ENODEV; + } + + clk_prepare_enable(priv->clk); + + priv->disp_clk = devm_clk_get(dev, "lcd_pixclk"); + if (IS_ERR(priv->clk)) { + DRM_DEBUG_DRIVER("failed to get pixel clock\n"); + return -ENODEV; + } + + clk_prepare_enable(priv->disp_clk); + + if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) + priv->max_bandwidth = JZ4780_DEFAULT_MAX_BANDWIDTH; + + if (of_property_read_u32(node, "max-width", &priv->max_width)) + priv->max_width = JZ4780_DEFAULT_MAX_WIDTH; + + if (of_property_read_u32(node, "max-pixelclock", + &priv->max_pixelclock)) + priv->max_pixelclock = JZ4780_DEFAULT_MAX_PIXELCLOCK; + + drm_irq_install(drm_dev, platform_get_irq(pdev, 0)); + + priv->crtc = jz4780_crtc_create(jz4780_crtc); + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static void jz4780_crtc_unbind(struct device *dev, struct device *master, + void *data) +{ + struct jz4780_crtc *jz4780_crtc = dev_get_drvdata(dev); + + pm_runtime_disable(dev); + jz4780_crtc_destroy(&jz4780_crtc->base); +} + +static const struct component_ops jz4780_crtc_component_ops = { + .bind = jz4780_crtc_bind, + .unbind = jz4780_crtc_unbind, +}; + +static int jz4780_crtc_probe(struct platform_device *pdev) +{ + + struct device *dev = &pdev->dev; + + if (!dev->of_node) { + dev_err(dev, "can't find jz4780 crtc devices\n"); + return -ENODEV; + } + + return component_add(dev, &jz4780_crtc_component_ops); +} + +static int jz4780_crtc_remove(struct platform_device *pdev) +{ + + component_del(&pdev->dev, &jz4780_crtc_component_ops); + + return 0; +} + +struct platform_driver jz4780_crtc_platform_driver = { + .probe = jz4780_crtc_probe, + .remove = jz4780_crtc_remove, + .driver = { + .name = "jz4780-lcd-crtc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(jz4780_driver_dt_match), + }, +}; + +module_platform_driver(jz4780_crtc_platform_driver); + diff --git a/drivers/gpu/drm/jz4780/jz4780_drv.c b/drivers/gpu/drm/jz4780/jz4780_drv.c new file mode 100644 index 0000000..3040e04 --- /dev/null +++ b/drivers/gpu/drm/jz4780/jz4780_drv.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * DRM driver for Ingenic JZ4780 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> +#include <linux/of_graph.h> +#include <linux/component.h> + +#include "jz4780_drv.h" +#include "jz4780_regs.h" + +static void jz4780_fb_output_poll_changed(struct drm_device *drm_dev) +{ + + struct jz4780_drm_private *priv = drm_dev->dev_private; + + if (priv->fbdev) + drm_fbdev_cma_hotplug_event(priv->fbdev); +} + +static const struct drm_mode_config_funcs jz4780_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .output_poll_changed = jz4780_fb_output_poll_changed, +}; + +void jz4780_drm_mode_config_init(struct drm_device *drm_dev) +{ + + drm_dev->mode_config.min_width = 0; + drm_dev->mode_config.min_height = 0; + drm_dev->mode_config.max_width = 2048; + drm_dev->mode_config.max_height = 2048; + drm_dev->mode_config.funcs = &jz4780_mode_config_funcs; +} + +/* + * DRM operations: + */ + +static int jz4780_unload(struct drm_device *drm_dev) +{ + + struct jz4780_drm_private *priv = drm_dev->dev_private; + struct device *dev = drm_dev->dev; + + drm_kms_helper_poll_fini(drm_dev); + drm_mode_config_cleanup(drm_dev); + drm_vblank_cleanup(drm_dev); + + component_unbind_all(dev, drm_dev); + + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + + drm_dev->dev_private = NULL; + pm_runtime_disable(drm_dev->dev); + + return 0; +} + +static int jz4780_load(struct drm_device *drm_dev, unsigned long flags) +{ + struct device *dev = drm_dev->dev; + struct jz4780_drm_private *priv; + int ret; + + priv = devm_kzalloc(drm_dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + DRM_DEBUG_DRIVER("failed to allocate private data\n"); + return -ENOMEM; + } + + platform_set_drvdata(drm_dev->platformdev, drm_dev); + drm_dev->dev_private = priv; + + priv->wq = alloc_ordered_workqueue("jz4780", 0); + + drm_mode_config_init(drm_dev); + + jz4780_drm_mode_config_init(drm_dev); + + /* Try to bind all sub drivers. */ + ret = component_bind_all(dev, drm_dev); + if (ret) + goto err_config_cleanup; + + ret = drm_vblank_init(drm_dev, 1); + if (ret < 0) { + DRM_DEBUG_DRIVER("failed to initialize vblank\n"); + goto err_vblank_cleanup; + } + + priv->fbdev = drm_fbdev_cma_init(drm_dev, 32, + drm_dev->mode_config.num_crtc, + drm_dev->mode_config.num_connector); + + drm_kms_helper_poll_init(drm_dev); + + return 0; + +err_vblank_cleanup: + drm_vblank_cleanup(drm_dev); + component_unbind_all(dev, drm_dev); +err_config_cleanup: + drm_mode_config_cleanup(drm_dev); + return ret; +} + +static void jz4780_preclose(struct drm_device *drm_dev, struct drm_file *file) +{ + + struct jz4780_drm_private *priv = drm_dev->dev_private; + + jz4780_crtc_cancel_page_flip(priv->crtc, file); +} + +static void jz4780_lastclose(struct drm_device *drm_dev) +{ + + struct jz4780_drm_private *priv = drm_dev->dev_private; + + drm_fbdev_cma_restore_mode(priv->fbdev); +} + +static irqreturn_t jz4780_irq(int irq, void *arg) +{ + + struct drm_device *drm_dev = arg; + struct jz4780_drm_private *priv = drm_dev->dev_private; + + return jz4780_crtc_irq(priv->crtc); +} + +static void jz4780_enable_disable_vblank(struct drm_device *drm_dev, + bool enable) +{ + + u32 tmp; + + /* clear previous EOF flag */ + tmp = jz4780_read(drm_dev, LCDC_STATE); + jz4780_write(drm_dev, LCDC_STATE, tmp & ~LCDC_STATE_EOF); + + /* enable end of frame interrupt */ + tmp = jz4780_read(drm_dev, LCDC_CTRL); + if (enable) + jz4780_write(drm_dev, LCDC_CTRL, tmp | LCDC_CTRL_EOFM); + else + jz4780_write(drm_dev, LCDC_CTRL, tmp & ~LCDC_CTRL_EOFM); + +} + +static int jz4780_enable_vblank(struct drm_device *drm_dev, int crtc) +{ + + jz4780_enable_disable_vblank(drm_dev, true); + return 0; +} + +static void jz4780_disable_vblank(struct drm_device *drm_dev, int crtc) +{ + + jz4780_enable_disable_vblank(drm_dev, false); +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .mmap = drm_gem_cma_mmap, +}; + +static struct drm_driver jz4780_driver = { + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, + .load = jz4780_load, + .unload = jz4780_unload, + .preclose = jz4780_preclose, + .lastclose = jz4780_lastclose, + .set_busid = drm_platform_set_busid, + .irq_handler = jz4780_irq, + .get_vblank_counter = drm_vblank_count, + .enable_vblank = jz4780_enable_vblank, + .disable_vblank = jz4780_disable_vblank, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .fops = &fops, + .name = "jz4780", + .desc = "Ingenic LCD Controller DRM", + .date = "20140623", + .major = 1, + .minor = 0, +}; + +static int compare_of(struct device *dev, void *data) +{ + + struct device_node *np = data; + + return dev->of_node == np; +} + +static void jz4780_add_endpoints(struct device *dev, + struct component_match **match, + struct device_node *port) +{ + + struct device_node *ep, *remote; + + for_each_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); + continue; + } else if (!of_device_is_available(remote->parent)) { + dev_warn(dev, "parent device of %s is not available\n", + remote->full_name); + of_node_put(remote); + continue; + } + + component_match_add(dev, match, compare_of, remote); + of_node_put(remote); + } +} + +static int jz4780_drm_bind(struct device *dev) +{ + + struct drm_device *drm; + struct platform_device *pdev = dev_get_drvdata(dev); + int ret; + + drm = drm_dev_alloc(&jz4780_driver, dev); + if (!drm) + return -ENOMEM; + + ret = drm_dev_set_unique(drm, "%s", dev_name(dev)); + if (ret) + goto err_free; + + drm->platformdev = pdev; + + ret = drm_dev_register(drm, 0); + if (ret) + goto err_free; + + dev_set_drvdata(dev, drm); + + return 0; + +err_free: + drm_dev_unref(drm); + return ret; +} + +static void jz4780_drm_unbind(struct device *dev) +{ + + struct drm_device *drm = dev_get_drvdata(dev); + + drm_dev_unregister(drm); + drm_dev_unref(drm); + dev_set_drvdata(dev, NULL); +} + +static const struct component_master_ops jz4780_drm_ops = { + .bind = jz4780_drm_bind, + .unbind = jz4780_drm_unbind, +}; + +/* + * Platform driver: + */ +static int jz4780_pdev_probe(struct platform_device *pdev) +{ + + struct device *dev = &pdev->dev; + struct component_match *match = NULL; + struct device_node *np = dev->of_node; + struct device_node *port; + int i; + + if (!np) + return -ENODEV; + + /* + * Bind the crtc ports first, so that + * drm_of_find_possible_crtcs called from encoder .bind callbacks + * works as expected. + */ + for (i = 0;; i++) { + port = of_parse_phandle(np, "ports", i); + if (!port) + break; + + if (!of_device_is_available(port->parent)) { + of_node_put(port); + continue; + } + + component_match_add(dev, &match, compare_of, port->parent); + of_node_put(port); + } + + if (i == 0) { + dev_err(dev, "missing 'ports' property\n"); + return -ENODEV; + } + + if (!match) { + dev_err(dev, "No available crtc found for display-subsystem.\n"); + return -ENODEV; + } + /* + * For each bound crtc, bind the encoders attached to its + * remote endpoint. + */ + for (i = 0;; i++) { + port = of_parse_phandle(np, "ports", i); + if (!port) + break; + + if (!of_device_is_available(port->parent)) { + of_node_put(port); + continue; + } + + jz4780_add_endpoints(dev, &match, port); + of_node_put(port); + } + + dev_set_drvdata(dev, pdev); + return component_master_add_with_match(dev, &jz4780_drm_ops, match); +} + +static int jz4780_pdev_remove(struct platform_device *pdev) +{ + + component_master_del(&pdev->dev, &jz4780_drm_ops); + return 0; +} + +static const struct of_device_id jz4780_of_match[] = { + { .compatible = "ingenic,jz4780-display-subsystem", }, + { }, +}; +MODULE_DEVICE_TABLE(of, jz4780_of_match); + +static struct platform_driver jz4780_platform_driver = { + .probe = jz4780_pdev_probe, + .remove = jz4780_pdev_remove, + .driver = { + .owner = THIS_MODULE, + .name = "ingenic-jz4780-drm", + .of_match_table = jz4780_of_match, + }, +}; + +module_platform_driver(jz4780_platform_driver); + +MODULE_AUTHOR("Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>"); +MODULE_DESCRIPTION("Ingenic JZ4780 LCD/HDMI Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/jz4780/jz4780_drv.h b/drivers/gpu/drm/jz4780/jz4780_drv.h new file mode 100644 index 0000000..c63997c --- /dev/null +++ b/drivers/gpu/drm/jz4780/jz4780_drv.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 Imagination Technologies + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __jz4780_DRV_H__ +#define __jz4780_DRV_H__ + +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/list.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fb_cma_helper.h> + +/* Defaulting to maximum capability of JZ4780 */ +#define JZ4780_DEFAULT_MAX_PIXELCLOCK 200000 +#define JZ4780_DEFAULT_MAX_WIDTH 2048 +#define JZ4780_DEFAULT_MAX_BANDWIDTH (1920*1080*60) + + +struct jz4780_drm_private { + void __iomem *mmio; + + struct clk *disp_clk; /* display dpll */ + struct clk *clk; /* functional clock */ + int rev; /* IP revision */ + + /* don't attempt resolutions w/ higher W * H * Hz: */ + uint32_t max_bandwidth; + /* + * Pixel Clock will be restricted to some value as + * defined in the device datasheet measured in KHz + */ + uint32_t max_pixelclock; + /* + * Max allowable width is limited on a per device basis + * measured in pixels + */ + uint32_t max_width; + + struct workqueue_struct *wq; + + struct drm_fbdev_cma *fbdev; + + struct drm_crtc *crtc; + + unsigned int num_encoders; + struct drm_encoder *encoders[8]; + + unsigned int num_connectors; + struct drm_connector *connectors[8]; +}; + +void jz4780_crtc_cancel_page_flip(struct drm_crtc *crtc, + struct drm_file *file); +irqreturn_t jz4780_crtc_irq(struct drm_crtc *crtc); +void jz4780_crtc_update_clk(struct drm_crtc *crtc); +int jz4780_crtc_mode_valid(struct drm_crtc *crtc, + struct drm_display_mode *mode); +int jz4780_crtc_max_width(struct drm_crtc *crtc); + +#endif /* __jz4780_DRV_H__ */ diff --git a/drivers/gpu/drm/jz4780/jz4780_regs.h b/drivers/gpu/drm/jz4780/jz4780_regs.h new file mode 100644 index 0000000..2e273f9 --- /dev/null +++ b/drivers/gpu/drm/jz4780/jz4780_regs.h @@ -0,0 +1,694 @@ +/* + * Copyright (c) 2014 Imagination Technologies + * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __JZ4780_REGS_H__ +#define __JZ4780_REGS_H__ + +/* LCDC register definitions */ + +#include <linux/bitops.h> + +#include "jz4780_drv.h" + +/* Register Map Of LCDC */ +#define LCDC_CFG 0x00 +#define LCDC_CTRL 0x30 +#define LCDC_STATE 0x34 +#define LCDC_OSDC 0x100 +#define LCDC_OSDCTRL 0x104 +#define LCDC_OSDS 0x108 +#define LCDC_BGC0 0x10c +#define LCDC_BGC1 0x2c4 +#define LCDC_KEY0 0x110 +#define LCDC_KEY1 0x114 +#define LCDC_ALPHA 0x118 +#define LCDC_IPUR 0x11c +#define LCDC_RGBC 0x90 +#define LCDC_VAT 0x0c +#define LCDC_DAH 0x10 +#define LCDC_DAV 0x14 +#define LCDC_XYP0 0x120 +#define LCDC_XYP1 0x124 +#define LCDC_SIZE0 0x128 +#define LCDC_SIZE1 0x12c +#define LCDC_VSYNC 0x04 +#define LCDC_HSYNC 0x08 +#define LCDC_PS 0x18 +#define LCDC_CLS 0x1c +#define LCDC_SPL 0x20 +#define LCDC_REV 0x24 +#define LCDC_IID 0x38 +#define LCDC_DA0 0x40 +#define LCDC_SA0 0x44 +#define LCDC_FID0 0x48 +#define LCDC_CMD0 0x4c +#define LCDC_OFFS0 0x60 +#define LCDC_PW0 0x64 +#define LCDC_CNUM0 0x68 +#define LCDC_CPOS0 0x68 +#define LCDC_DESSIZE0 0x6c +#define LCDC_DA1 0x50 +#define LCDC_SA1 0x54 +#define LCDC_FID1 0x58 +#define LCDC_CMD1 0x5c +#define LCDC_OFFS1 0x70 +#define LCDC_PW1 0x74 +#define LCDC_CNUM1 0x78 +#define LCDC_CPOS1 0x78 +#define LCDC_DESSIZE1 0x7c +#define LCDC_PCFG 0x2c0 +#define LCDC_DUAL_CTRL 0x2c8 +#define LCDC_ENH_CFG 0x400 +#define LCDC_ENH_CSCCFG 0x404 +#define LCDC_ENH_LUMACFG 0x408 +#define LCDC_ENH_CHROCFG0 0x40c +#define LCDC_ENH_CHROCFG1 0x410 +#define LCDC_ENH_DITHERCFG 0x414 +#define LCDC_ENH_STATUS 0x418 +#define LCDC_ENH_GAMMA 0x800 +#define LCDC_ENH_VEE 0x1000 + +/* LCD Configure Register */ +#define LCDC_CFG_LCDPIN_BIT 31 +#define LCDC_CFG_LCDPIN_MASK (0x1 << LCDC_CFG_LCDPIN_BIT) +#define LCDC_CFG_LCDPIN_LCD (0x0 << LCDC_CFG_LCDPIN_BIT) +#define LCDC_CFG_LCDPIN_SLCD (0x1 << LCDC_CFG_LCDPIN_BIT) +#define LCDC_CFG_TVEPEH BIT(30) +#define LCDC_CFG_NEWDES BIT(28) +#define LCDC_CFG_PALBP BIT(27) +#define LCDC_CFG_TVEN BIT(26) +#define LCDC_CFG_RECOVER BIT(25) + +#define LCDC_CFG_PSM BIT(23) +#define LCDC_CFG_CLSM BIT(22) +#define LCDC_CFG_SPLM BIT(21) +#define LCDC_CFG_REVM BIT(20) +#define LCDC_CFG_HSYNM BIT(19) +#define LCDC_CFG_PCLKM BIT(18) +#define LCDC_CFG_INVDAT BIT(17) +#define LCDC_CFG_SYNDIR_IN BIT(16) +#define LCDC_CFG_PSP BIT(15) +#define LCDC_CFG_CLSP BIT(14) +#define LCDC_CFG_SPLP BIT(13) +#define LCDC_CFG_REVP BIT(12) +#define LCDC_CFG_HSP BIT(11) +#define LCDC_CFG_PCP BIT(10) +#define LCDC_CFG_DEP BIT(9) +#define LCDC_CFG_VSP BIT(8) +#define LCDC_CFG_MODE_TFT_18BIT BIT(7) +#define LCDC_CFG_MODE_TFT_16BIT (0 << 7) +#define LCDC_CFG_MODE_TFT_24BIT BIT(6) + +#define LCDC_CFG_MODE_BIT 0 +#define LCDC_CFG_MODE_MASK (0x0f << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_GENERIC_TFT (0 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_SPECIAL_TFT_1 (1 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_SPECIAL_TFT_2 (2 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_SPECIAL_TFT_3 (3 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_NONINTER_CCIR656 (4 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_INTER_CCIR656 (6 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_SERIAL_TFT (12 << LCDC_CFG_MODE_BIT) +#define LCDC_CFG_MODE_LCM (13 << LCDC_CFG_MODE_BIT) + +/* LCD Control Register */ +#define LCDC_CTRL_PINMD BIT(31) +#define LCDC_CTRL_BST_BIT 28 +#define LCDC_CTRL_BST_MASK (0x7 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_BST_4 (0 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_BST_8 (1 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_BST_16 (2 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_BST_32 (3 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_BST_64 (4 << LCDC_CTRL_BST_BIT) +#define LCDC_CTRL_RGB565 (0 << 27) +#define LCDC_CTRL_RGB555 BIT(27) +#define LCDC_CTRL_OFUP BIT(26) +#define LCDC_CTRL_PDD_BIT 16 +#define LCDC_CTRL_PDD_MASK (0xff << LCDC_CTRL_PDD_BIT) + +#define LCDC_CTRL_DACTE BIT(14) +#define LCDC_CTRL_EOFM BIT(13) +#define LCDC_CTRL_SOFM BIT(12) +#define LCDC_CTRL_OFUM BIT(11) +#define LCDC_CTRL_IFUM0 BIT(10) +#define LCDC_CTRL_IFUM1 BIT(9) +#define LCDC_CTRL_LDDM BIT(8) +#define LCDC_CTRL_QDM BIT(7) +#define LCDC_CTRL_BEDN BIT(6) +#define LCDC_CTRL_PEDN BIT(5) +#define LCDC_CTRL_DIS BIT(4) +#define LCDC_CTRL_ENA BIT(3) +#define LCDC_CTRL_BPP_BIT 0 +#define LCDC_CTRL_BPP_MASK (0x07 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_1 (0 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_2 (1 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_4 (2 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_8 (3 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_16 (4 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_18_24 (5 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_CMPS_24 (6 << LCDC_CTRL_BPP_BIT) +#define LCDC_CTRL_BPP_30 (7 << LCDC_CTRL_BPP_BIT) + +#define LCD_TYPE_GENERIC_24_BIT (0 | 1 << 6) + +/* LCD Status Register */ +#define LCDC_STATE_QD BIT(7) +#define LCDC_STATE_EOF BIT(5) +#define LCDC_STATE_SOF BIT(4) +#define LCDC_STATE_OFU BIT(3) +#define LCDC_STATE_IFU0 BIT(2) +#define LCDC_STATE_IFU1 BIT(1) +#define LCDC_STATE_LDD BIT(0) + +/* OSD Configure Register */ +#define LCDC_OSDC_PREMULTI1 BIT(23) +#define LCDC_OSDC_COEF_SLE1_BIT 21 +#define LCDC_OSDC_COEF_SLE1_MASK (0x03 << LCDC_OSDC_COEF_SLE1_BIT) +#define LCDC_OSDC_COEF_SLE1_0 (0 << LCDC_OSDC_COEF_SLE1_BIT) +#define LCDC_OSDC_COEF_SLE1_1 (1 << LCDC_OSDC_COEF_SLE1_BIT) +#define LCDC_OSDC_COEF_SLE1_2 (2 << LCDC_OSDC_COEF_SLE1_BIT) +#define LCDC_OSDC_COEF_SLE1_3 (3 << LCDC_OSDC_COEF_SLE1_BIT) + +#define LCDC_OSDC_PREMULTI0 BIT(20) +#define LCDC_OSDC_COEF_SLE0_BIT 18 +#define LCDC_OSDC_COEF_SLE0_MASK (0x03 << LCDC_OSDC_COEF_SLE0_BIT) +#define LCDC_OSDC_COEF_SLE0_0 (0 << LCDC_OSDC_COEF_SLE0_BIT) +#define LCDC_OSDC_COEF_SLE0_1 (1 << LCDC_OSDC_COEF_SLE0_BIT) +#define LCDC_OSDC_COEF_SLE0_2 (2 << LCDC_OSDC_COEF_SLE0_BIT) +#define LCDC_OSDC_COEF_SLE0_3 (3 << LCDC_OSDC_COEF_SLE0_BIT) +#define LCDC_OSDC_ALPHAMD1 BIT(17) + +#define LCDC_OSDC_SOFM1 BIT(15) +#define LCDC_OSDC_EOFM1 BIT(14) +#define LCDC_OSDC_SOFM0 BIT(11) +#define LCDC_OSDC_EOFM0 BIT(10) +#define LCDC_OSDC_DENDM BIT(9) +#define LCDC_OSDC_F1EN BIT(4) +#define LCDC_OSDC_F0EN BIT(3) +#define LCDC_OSDC_ALPHAEN BIT(2) +#define LCDC_OSDC_ALPHAMD0 BIT(1) +#define LCDC_OSDC_OSDEN BIT(0) + +/* OSD Control Register */ +#define LCDC_OSDCTRL_IPU_CLKEN BIT(15) +#define LCDC_OSDCTRL_RGB0_RGB565 (0 << 5) +#define LCDC_OSDCTRL_RGB0_RGB555 BIT(5) +#define LCDC_OSDCTRL_RGB1_RGB565 (0 << 4) +#define LCDC_OSDCTRL_RGB1_RGB555 BIT(4) + +#define LCDC_OSDCTRL_BPP_BIT 0 +#define LCDC_OSDCTRL_BPP_MASK (0x7 << LCDC_OSDCTRL_BPP_BIT) +#define LCDC_OSDCTRL_BPP_15_16 (4 << LCDC_OSDCTRL_BPP_BIT) +#define LCDC_OSDCTRL_BPP_18_24 (5 << LCDC_OSDCTRL_BPP_BIT) +#define LCDC_OSDCTRL_BPP_CMPS_24 (6 << LCDC_OSDCTRL_BPP_BIT) +#define LCDC_OSDCTRL_BPP_30 (7 << LCDC_OSDCTRL_BPP_BIT) + +/* OSD State Register */ +#define LCDC_OSDS_SOF1 BIT(15) +#define LCDC_OSDS_EOF1 BIT(14) +#define LCDC_OSDS_SOF0 BIT(11) +#define LCDC_OSDS_EOF0 BIT(10) +#define LCDC_OSDS_DEND BIT(8) + +/* Background 0 or Background 1 Color Register */ +#define LCDC_BGC_RED_OFFSET 16 +#define LCDC_BGC_RED_MASK (0xFF << LCDC_BGC_RED_OFFSET) +#define LCDC_BGC_GREEN_OFFSET 8 +#define LCDC_BGC_GREEN_MASK (0xFF << LCDC_BGC_GREEN_OFFSET) +#define LCDC_BGC_BLUE_OFFSET 0 +#define LCDC_BGC_BLUE_MASK (0xFF << LCDC_BGC_BLUE_OFFSET) + +/* Foreground 0 or Foreground 1 Color Key Register */ +#define LCDC_KEY_KEYEN BIT(31) +#define LCDC_KEY_KEYMD BIT(30) +#define LCDC_KEY_RED_OFFSET 16 +#define LCDC_KEY_RED_MASK (0xFF << LCDC_KEY_RED_OFFSET) +#define LCDC_KEY_GREEN_OFFSET 8 +#define LCDC_KEY_GREEN_MASK (0xFF << LCDC_KEY_GREEN_OFFSET) +#define LCDC_KEY_BLUE_OFFSET 0 +#define LCDC_KEY_BLUE_MASK (0xFF << LCDC_KEY_BLUE_OFFSET) +#define LCDC_KEY_MASK (LCDC_KEY_RED_MASK | \ + | LCDC_KEY_GREEN_MASK \ + | LCDC_KEY_BLUE_MASK) + +/* ALPHA Register */ +#define LCDC_ALPHA1_OFFSET 8 +#define LCDC_ALPHA1_MASK (0xFF << LCDC_ALPHA1_OFFSET) +#define LCDC_ALPHA0_OFFSET 0 +#define LCDC_ALPHA0_MASK (0xFF << LCDC_ALPHA0_OFFSET) + +/* IPU Restart Register */ +#define LCDC_IPUR_IPUREN BIT(31) +#define LCDC_IPUR_IPURMASK 0xFFFFFF + +/* RGB Control Register */ +#define LCDC_RGBC_RGBDM BIT(15) +#define LCDC_RGBC_DMM BIT(14) +#define LCDC_RGBC_422 BIT(8) +#define LCDC_RGBC_RGBFMT BIT(7) +#define LCDC_RGBC_ODDRGB_BIT 4 +#define LCDC_RGBC_ODDRGB_MASK (0x7 << LCDC_RGBC_ODDRGB_BIT) +#define LCDC_RGBC_ODD_RGB (0 << LCDC_RGBC_ODDRGB_BIT) /* RGB */ +#define LCDC_RGBC_ODD_RBG (1 << LCDC_RGBC_ODDRGB_BIT) /* RBG */ +#define LCDC_RGBC_ODD_GRB (2 << LCDC_RGBC_ODDRGB_BIT) /* GRB */ +#define LCDC_RGBC_ODD_GBR (3 << LCDC_RGBC_ODDRGB_BIT) /* GBR */ +#define LCDC_RGBC_ODD_BRG (4 << LCDC_RGBC_ODDRGB_BIT) /* BRG */ +#define LCDC_RGBC_ODD_BGR (5 << LCDC_RGBC_ODDRGB_BIT) /* BGR */ + +#define LCDC_RGBC_EVENRGB_BIT 0 +#define LCDC_RGBC_EVENRGB_MASK (0x7 << LCDC_RGBC_EVENRGB_BIT) +#define LCDC_RGBC_EVEN_RGB 0 /* RGB */ +#define LCDC_RGBC_EVEN_RBG 1 /* RBG */ +#define LCDC_RGBC_EVEN_GRB 2 /* GRB */ +#define LCDC_RGBC_EVEN_GBR 3 /* GBR */ +#define LCDC_RGBC_EVEN_BRG 4 /* BRG */ +#define LCDC_RGBC_EVEN_BGR 5 /* BGR */ + +/* Vertical Synchronize Register */ +#define LCDC_VSYNC_VPS_BIT 16 +#define LCDC_VSYNC_VPS_MASK (0xfff << LCDC_VSYNC_VPS_BIT) +#define LCDC_VSYNC_VPE_BIT 0 +#define LCDC_VSYNC_VPE_MASK (0xfff << LCDC_VSYNC_VPE_BIT) + +/* Horizontal Synchronize Register */ +#define LCDC_HSYNC_HPS_BIT 16 +#define LCDC_HSYNC_HPS_MASK (0xfff << LCDC_HSYNC_HPS_BIT) +#define LCDC_HSYNC_HPE_BIT 0 +#define LCDC_HSYNC_HPE_MASK (0xfff << LCDC_HSYNC_HPE_BIT) + +/* Virtual Area Setting Register */ +#define LCDC_VAT_HT_BIT 16 +#define LCDC_VAT_HT_MASK (0xfff << LCDC_VAT_HT_BIT) +#define LCDC_VAT_VT_BIT 0 +#define LCDC_VAT_VT_MASK (0xfff << LCDC_VAT_VT_BIT) + +/* Display Area Horizontal Start/End Point Register */ +#define LCDC_DAH_HDS_BIT 16 +#define LCDC_DAH_HDS_MASK (0xfff << LCDC_DAH_HDS_BIT) +#define LCDC_DAH_HDE_BIT 0 +#define LCDC_DAH_HDE_MASK (0xfff << LCDC_DAH_HDE_BIT) + +/* Display Area Vertical Start/End Point Register */ +#define LCDC_DAV_VDS_BIT 16 +#define LCDC_DAV_VDS_MASK (0xfff << LCDC_DAV_VDS_BIT) +#define LCDC_DAV_VDE_BIT 0 +#define LCDC_DAV_VDE_MASK (0xfff << LCDC_DAV_VDE_BIT) + +/* Foreground 0 or Foreground 1 XY Position Register */ +#define LCDC_XYP_YPOS_BIT 16 +#define LCDC_XYP_YPOS_MASK (0xfff << LCDC_XYP_YPOS_BIT) +#define LCDC_XYP_XPOS_BIT 0 +#define LCDC_XYP_XPOS_MASK (0xfff << LCDC_XYP_XPOS_BIT) + +/* Foreground 0 or Foreground 1 Size Register */ +#define LCDC_SIZE_HEIGHT_BIT 16 +#define LCDC_SIZE_HEIGHT_MASK (0xfff << LCDC_SIZE_HEIGHT_BIT) +#define LCDC_SIZE_WIDTH_BIT 0 +#define LCDC_SIZE_WIDTH_MASK (0xfff << LCDC_SIZE_WIDTH_BIT) + +/* PS Signal Setting */ +#define LCDC_PS_PSS_BIT 16 +#define LCDC_PS_PSS_MASK (0xfff << LCDC_PS_PSS_BIT) +#define LCDC_PS_PSE_BIT 0 +#define LCDC_PS_PSE_MASK (0xfff << LCDC_PS_PSE_BIT) + +/* CLS Signal Setting */ +#define LCDC_CLS_CLSS_BIT 16 +#define LCDC_CLS_CLSS_MASK (0xfff << LCDC_CLS_CLSS_BIT) +#define LCDC_CLS_CLSE_BIT 0 +#define LCDC_CLS_CLSE_MASK (0xfff << LCDC_CLS_CLSE_BIT) + +/* SPL Signal Setting */ +#define LCDC_SPL_SPLS_BIT 16 +#define LCDC_SPL_SPLS_MASK (0xfff << LCDC_SPL_SPLS_BIT) +#define LCDC_SPL_SPLE_BIT 0 +#define LCDC_SPL_SPLE_MASK (0xfff << LCDC_SPL_SPLE_BIT) + +/* REV Signal Setting */ +#define LCDC_REV_REVS_BIT 16 +#define LCDC_REV_REVS_MASK (0xfff << LCDC_REV_REVS_BIT) + +/* DMA Command 0 or 1 Register */ +#define LCDC_CMD_SOFINT BIT(31) +#define LCDC_CMD_EOFINT BIT(30) +#define LCDC_CMD_CMD BIT(29) +#define LCDC_CMD_PAL BIT(28) +#define LCDC_CMD_COMPEN BIT(27) +#define LCDC_CMD_FRM_EN BIT(26) +#define LCDC_CMD_FIELD_SEL BIT(25) +#define LCDC_CMD_16X16BLOCK BIT(24) +#define LCDC_CMD_LEN_BIT 0 +#define LCDC_CMD_LEN_MASK (0xffffff << LCDC_CMD_LEN_BIT) + +/* DMA Offsize Register 0,1 */ +#define LCDC_OFFS_BIT 0 +#define LCDC_OFFS_OFFSIZE_MASK (0xffffff << LCDC_OFFS_BIT) + +/* DMA Page Width Register 0,1 */ +#define LCDC_PW_BIT 0 +#define LCDC_PW_PAGEWIDTH_MASK (0xffffff << LCDC_PW_BIT) + +/* DMA Command Counter Register 0,1 */ +#define LCDC_CNUM_BIT 0 +#define LCDC_CNUM_CNUM_MASK (0xff << LCDC_CNUM_BIT) + +/* DMA Command Counter Register */ +#define LCDC_CPOS_ALPHAMD1 BIT(31) +#define LCDC_CPOS_RGB_RGB565 (0 << 30) +#define LCDC_CPOS_RGB_RGB555 BIT(30) + +#define LCDC_CPOS_BPP_BIT 27 +#define LCDC_CPOS_BPP_MASK (0x07 << LCDC_CPOS_BPP_BIT) +#define LCDC_CPOS_BPP_16 (4 << LCDC_CPOS_BPP_BIT) +#define LCDC_CPOS_BPP_18_24 (5 << LCDC_CPOS_BPP_BIT) +#define LCDC_CPOS_BPP_CMPS_24 (6 << LCDC_CPOS_BPP_BIT) +#define LCDC_CPOS_BPP_30 (7 << LCDC_CPOS_BPP_BIT) + +#define LCDC_CPOS_PREMULTI BIT(26) +#define LCDC_CPOS_COEF_SLE_BIT 24 +#define LCDC_CPOS_COEF_SLE_MASK (0x3 << LCDC_CPOS_COEF_SLE_BIT) +#define LCDC_CPOS_COEF_SLE_0 (0 << LCDC_CPOS_COEF_SLE_BIT) +#define LCDC_CPOS_COEF_SLE_1 (1 << LCDC_CPOS_COEF_SLE_BIT) +#define LCDC_CPOS_COEF_SLE_2 (2 << LCDC_CPOS_COEF_SLE_BIT) +#define LCDC_CPOS_COEF_SLE_3 (3 << LCDC_CPOS_COEF_SLE_BIT) + +#define LCDC_CPOS_YPOS_BIT 12 +#define LCDC_CPOS_YPOS_MASK (0xfff << LCDC_CPOS_YPOS_BIT) +#define LCDC_CPOS_XPOS_BIT 0 +#define LCDC_CPOS_XPOS_MASK (0xfff << LCDC_CPOS_XPOS_BIT) + +/* Foreground 0,1 Size Register */ +#define LCDC_DESSIZE_ALPHA_BIT 24 +#define LCDC_DESSIZE_ALPHA_MASK (0xff << LCDC_DESSIZE_ALPHA_BIT) +#define LCDC_DESSIZE_HEIGHT_BIT 12 +#define LCDC_DESSIZE_HEIGHT_MASK (0xfff << LCDC_DESSIZE_HEIGHT_BIT) +#define LCDC_DESSIZE_WIDTH_BIT 0 +#define LCDC_DESSIZE_WIDTH_MASK (0xfff << LCDC_DESSIZE_WIDTH_BIT) + +/* Priority level threshold configure Register */ +#define LCDC_PCFG_LCDC_PRI_MD BIT(31) + +#define LCDC_PCFG_HP_BST_BIT 28 +#define LCDC_PCFG_HP_BST_MASK (0x7 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_4 (0 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_8 (1 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_16 (2 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_32 (3 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_C16 (5 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_64 (4 << LCDC_PCFG_HP_BST_BIT) +#define LCDC_PCFG_HP_BST_DIS (7 << LCDC_PCFG_HP_BST_BIT) + +#define LCDC_PCFG_PCFG2_BIT 18 +#define LCDC_PCFG_PCFG2_MASK (0x1ff << LCDC_PCFG_PCFG2_BIT) +#define LCDC_PCFG_PCFG1_BIT 9 +#define LCDC_PCFG_PCFG1_MASK (0x1ff << LCDC_PCFG_PCFG1_BIT) +#define LCDC_PCFG_PCFG0_BIT 0 +#define LCDC_PCFG_PCFG0_MASK (0x1ff << LCDC_PCFG_PCFG0_BIT) + +/* Dual LCDC Channel Control register */ +/* + * Select which IPU is able to write back, this field is just + * available in lcdc1. 0:ipu1; 1:ipu0 + */ +#define LCDC_DUAL_CTRL_IPU_WR_SEL BIT(8) +/* + * Select which controller output to the tft/slcd panel, this field is just + * available in lcdc1. 0:lcdc1; 1:lcdc0 + */ +#define LCDC_DUAL_CTRL_TFT_SEL BIT(6) +/* + * 1: fix the priority of ipu0/1 in lcd internal arbiter; + * 0: use priority of ipu0/1 generated by lcd in lcd internal arbiter + */ +#define LCDC_DUAL_CTRL_PRI_IPU_EN BIT(5) +#define LCDC_DUAL_CTRL_PRI_IPU_BIT 3 +#define LCDC_DUAL_CTRL_PRI_IPU_MASK (0x3 << LCDC_DUAL_CTRL_PRI_IPU_BIT) +/* + * 1: fix the priority of lcd0/1 in lcd internal arbiter; + * 0: use priority of lcd0/1 generated by lcd in lcd internal arbiter + */ +#define LCDC_DUAL_CTRL_PRI_LCD_EN BIT(2) +#define LCDC_DUAL_CTRL_PRI_LCD_BIT 0 +#define LCDC_DUAL_CTRL_PRI_LCD_MASK (0x3 << LCDC_DUAL_CTRL_PRI_LCD_BIT) + +/* Image Enhancement CFG Register */ +#define LCDC_ENH_CFG_DITHER_EN BIT(9) +#define LCDC_ENH_CFG_YCC2RGB_EN BIT(8) +#define LCDC_ENH_CFG_SATURATION_EN BIT(7) +#define LCDC_ENH_CFG_VEE_EN BIT(6) +#define LCDC_ENH_CFG_HUE_EN BIT(5) +#define LCDC_ENH_CFG_BRIGHTNESS_EN BIT(4) +#define LCDC_ENH_CFG_CONTRAST_EN BIT(3) +#define LCDC_ENH_CFG_RGB2YCC_EN BIT(2) +#define LCDC_ENH_CFG_GAMMA_EN BIT(1) +#define LCDC_ENH_CFG_ENH_EN BIT(0) + +/* Color Space Conversion CFG Register */ +#define LCDC_ENH_CSCCFG_YCC2RGBMD_BIT 2 /* YCbCr to RGB */ +#define LCDC_ENH_CSCCFG_YCC2RGBMD_MASK (0x03 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) +#define LCDC_ENH_CSCCFG_YCC2RGBMD_0 (0 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) +#define LCDC_ENH_CSCCFG_YCC2RGBMD_1 (1 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) +#define LCDC_ENH_CSCCFG_YCC2RGBMD_2 (2 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) +#define LCDC_ENH_CSCCFG_YCC2RGBMD_3 (3 << LCDC_ENH_CSCCFG_YCC2RGBMD_BIT) +/* + * 00:601WIDE; 01:601NARROW + * 10:709WIDE; 11:709NARROW + * WIDE:RGB range 16-235 + * NARROW:RGB range 0-255 +*/ +#define LCDC_ENH_CSCCFG_RGB2YCCMD_BIT 0 /* RGB to YCbCr*/ +#define LCDC_ENH_CSCCFG_RGB2YCCMD_MASK (0x03 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) +#define LCDC_ENH_CSCCFG_RGB2YCCMD_0 (0 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) +#define LCDC_ENH_CSCCFG_RGB2YCCMD_1 (1 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) +#define LCDC_ENH_CSCCFG_RGB2YCCMD_2 (2 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) +#define LCDC_ENH_CSCCFG_RGB2YCCMD_3 (3 << LCDC_ENH_CSCCFG_RGB2YCCMD_BIT) + +/* LUMA CFG Register */ +#define LCDC_ENH_LUMACFG_BRIGHT_BIT 16 /* + * Brightness value :0x0-0x7ff + * means 0.9999~-0.9999 + */ +#define LCDC_ENH_LUMACFG_BRIGHT_MASK (0x7ff << LCDC_ENH_LUMACFG_BRIGHT_BIT) + +#define LCDC_ENH_LUMACFG_CONTRAST_BIT 0 /* + * Contrast value :0x0-0x7ff + * means 0~1.9999 + */ +#define LCDC_ENH_LUMACFG_CONTRAST_MASK (0x7ff << LCDC_ENH_LUMACFG_CONTRAST_BIT) + +/* CHROMA0 CFG Register */ +#define LCDC_ENH_CHROCFG0_HUE_SIN_BIT 16 +#define LCDC_ENH_CHROCFG0_HUE_SIN_MASK (0xfff << LCDC_ENH_CHROCFG0_HUE_SIN_BIT) +#define LCDC_ENH_CHROCFG0_HUE_COS_BIT 0 +#define LCDC_ENH_CHROCFG0_HUE_COS_MASK (0xfff << LCDC_ENH_CHROCFG0_HUE_COS_BIT) + +/* CHROMA1 CFG Register */ +#define LCDC_ENH_CHROCFG1_SATUR_BIT 0 +#define LCDC_ENH_CHROCFG1_SATUR_MASK (0x7ff << LCDC_ENH_CHROCFG1_SATUR_BIT) + +/* DITHER CFG Register */ +/* + * 00:8bit dither + * 01:6bit dither + * 10:5bit dither + * 11:4bit dither +*/ +#define LCDC_ENH_DITHERCFG_RED_BIT 4 +#define LCDC_ENH_DITHERCFG_RED_MASK (0x03 << LCDC_ENH_DITHERCFG_RED_BIT) +#define LCDC_ENH_DITHERCFG_GREEN_BIT 2 +#define LCDC_ENH_DITHERCFG_GREEN_MASK (0x03 << LCDC_ENH_DITHERCFG_GREEN_BIT) +#define LCDC_ENH_DITHERCFG_BLUE_BIT 0 +#define LCDC_ENH_DITHERCFG_BLUE_MASK (0x03 << LCDC_ENH_DITHERCFG_BLUE_BIT) + +/* Enhance Status Register */ +#define LCDC_ENH_STATUS_DITHER_DIS BIT(9) +#define LCDC_ENH_STATUS_YCC2RGB_DIS BIT(8) +#define LCDC_ENH_STATUS_SATURATION_DIS BIT(7) +#define LCDC_ENH_STATUS_VEE_DIS BIT(6) +#define LCDC_ENH_STATUS_HUE_DIS BIT(5) +#define LCDC_ENH_STATUS_BRIGHTNESS_DIS BIT(4) +#define LCDC_ENH_STATUS_CONTRAST_DIS BIT(3) +#define LCDC_ENH_STATUS_RGB2YCC_DIS BIT(2) +#define LCDC_ENH_STATUS_GAMMA_DIS BIT(1) + +/* GAMMA CFG Register */ +#define LCDC_ENH_GAMMA_DATA1_BIT 16 +#define LCDC_ENH_GAMMA_DATA1_MASK (0x3ff << LCDC_ENH_GAMMA_DATA1_BIT) +#define LCDC_ENH_GAMMA_DATA0_BIT 0 +#define LCDC_ENH_GAMMA_DATA0_MASK (0x3ff << LCDC_ENH_GAMMA_DATA0_BIT) +#define LCDC_ENH_GAMMA_LEN 0x800 + +/* VEE CFG Register */ +#define LCDC_ENH_VEE_VEE_DATA1_BIT 16 +#define LCDC_ENH_VEE_VEE_DATA1_MASK (0x3ff << LCDC_ENH_VEE_VEE_DATA1_BIT) +#define LCDC_ENH_VEE_VEE_DATA0_BIT 0 +#define LCDC_ENH_VEE_VEE_DATA0_MASK (0x3ff << LCDC_ENH_VEE_VEE_DATA0_BIT) +#define LCDC_ENH_VEE_LEN 0x800 + +/* Register Map Of SLCD (Smart LCD Controller) */ +#define SLCDC_CFG 0xA0 +#define SLCDC_CTRL 0xA4 +#define SLCDC_STATE 0xA8 +#define SLCDC_DATA 0xAc + +/* SLCD Configure Register */ +#define SLCDC_CFG_DWIDTH_BIT 10 +#define SLCDC_CFG_DWIDTH_MASK (0x7 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_18BIT (0 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_16BIT (1 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_8BIT_x3 (2 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_8BIT_x2 (3 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_8BIT_x1 (4 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_24BIT (5 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_DWIDTH_9BIT_x2 (7 << SLCDC_CFG_DWIDTH_BIT) +#define SLCDC_CFG_CWIDTH_BIT 8 +#define SLCDC_CFG_CWIDTH_MASK (0x3 << SLCDC_CFG_CWIDTH_BIT) +#define SLCDC_CFG_CWIDTH_16BIT (0 << SLCDC_CFG_CWIDTH_BIT) +#define SLCDC_CFG_CWIDTH_8BIT (1 << SLCDC_CFG_CWIDTH_BIT) +#define SLCDC_CFG_CWIDTH_18BIT (2 << SLCDC_CFG_CWIDTH_BIT) +#define SLCDC_CFG_CWIDTH_24BIT (3 << SLCDC_CFG_CWIDTH_BIT) +#define SLCDC_CFG_CS_ACTIVE_LOW (0 << 4) +#define SLCDC_CFG_CS_ACTIVE_HIGH BIT(4) +#define SLCDC_CFG_RS_CMD_LOW (0 << 3) +#define SLCDC_CFG_RS_CMD_HIGH BIT(3) +#define SLCDC_CFG_CLK_ACTIVE_FALLING (0 << 1) +#define SLCDC_CFG_CLK_ACTIVE_RISING BIT(1) +#define SLCDC_CFG_TYPE_PARALLEL (0 << 0) +#define SLCDC_CFG_TYPE_SERIAL BIT(0) + +/* SLCD Control Register */ +#define SLCDC_CTRL_DMA_MODE BIT(2) +#define SLCDC_CTRL_DMA_START BIT(1) +#define SLCDC_CTRL_DMA_EN BIT(0) + +/* SLCD Status Register */ +#define SLCDC_STATE_BUSY BIT(0) + +/* SLCD Data Register */ +#define SLCDC_DATA_RS_DATA (0 << 31) +#define SLCDC_DATA_RS_COMMAND BIT(31) + +/* Register Map Of LVDSC (LVDS Controller) */ +#define LVDS_TXCTRL 0x3c0 +#define LVDS_TXPLL0 0x3c4 +#define LVDS_TXPLL1 0x3c8 +#define LVDS_TXECTRL 0x3cc + +/* TXCTRL (LVDS Transmitter Control Register) */ +#define LVDS_MODEL_SEL BIT(31) +#define LVDS_TX_PDB BIT(30) +#define LVDS_TX_PDB_CK BIT(29) +#define LVDS_RESERVE(n) (1 << 20 + (n)) +#define LVDS_TX_RSTB BIT(18) +#define LVDS_TX_CKBIT_PHA_SEL BIT(17) +#define LVDS_TX_CKBYTE_PHA_SEL BIT(16) + +#define LVDS_TX_CKOUT_PHA_S_BIT 13 +#define LVDS_TX_CKOUT_PHA_S_MASK (0x07 << LVDS_TX_CKOUT_PHA_S_BIT) + +#define LVDS_TX_CKOUT_SET BIT(12) +#define LVDS_TX_OUT_SEL BIT(11) +#define LVDS_TX_DLY_SEL_BIT 8 +#define LVDS_TX_DLY_SEL_MASK (0x07 << LVDS_TX_DLY_SEL_BIT) +#define LVDS_TX_AMP_ADJ BIT(7) +#define LVDS_TX_LVDS BIT(6) +#define LVDS_TX_CR_BIT 3 +#define LVDS_TX_CR_MASK (0x07 << LVDS_TX_CR_BIT) +#define LVDS_TX_CR_CK BIT(2) +#define LVDS_TX_OD_S BIT(1) +#define LVDS_TX_OD_EN BIT(0) + +/* TXPLL0 (LVDS Transmitter's PLL Control Register 0 */ + +#define LVDS_PLL_LOCK BIT(31) +#define LVDS_PLL_EN BIT(30) +#define LVDS_BG_PWD BIT(29) +#define LVDS_PLL_SSC_EN BIT(27) +#define LVDS_PLL_SSC_MODE BIT(26) +#define LVDS_PLL_TEST BIT(25) +#define LVDS_PLL_POST_DIVA_BIT 21 +#define LVDS_PLL_POST_DIVA_MASK (0x03 << LVDS_PLL_POST_DIVA_BIT) +#define LVDS_PLL_POST_DIVB_BIT 16 +#define LVDS_PLL_POST_DIVB_MASK (0x1f << LVDS_PLL_POST_DIVB_BIT) +#define LVDS_PLL_PLLN_BIT 8 +#define LVDS_PLL_PLLN_MASK (0x7f << LVDS_PLL_PLLN_BIT) +#define LVDS_PLL_TEST_DIV_BIT 6 +#define LVDS_PLL_TEST_DIV_MASK (0x03 << LVDS_PLL_TEST_DIV_BIT) +#define LVDS_PLL_TEST_DIV_2 (0 << LVDS_PLL_TEST_DIV_BIT) +#define LVDS_PLL_TEST_DIV_4 (1 << LVDS_PLL_TEST_DIV_BIT) +#define LVDS_PLL_TEST_DIV_8 (2 << LVDS_PLL_TEST_DIV_BIT) +#define LVDS_PLL_TEST_DIV_16 (3 << LVDS_PLL_TEST_DIV_BIT) +#define LVDS_PLL_IN_BYPASS (1 << 5) +#define LVDS_PLL_INDIV_BIT 0 +#define LVDS_PLL_INDIV_MASK (0x1f << LVDS_PLL_INDIV_BIT) + +/* TXPLL1 (LVDS Transmitter's PLL Control Register 1 */ + +#define LVDS_PLL_ICP_SEL_BIT 29 +#define LVDS_PLL_ICP_SEL_MASK (0x07 << LVDS_PLL_ICP_SEL_BIT) +#define LVDS_PLL_KVCO_BIT 26 +#define LVDS_PLL_KVCO_MASK (0x03 << LVDS_PLL_KVCO_BIT) +#define LVDS_PLL_IVCO_SEL_BIT 24 +#define LVDS_PLL_IVCO_SEL_MASK (0x03 << LVDS_PLL_IVCO_SEL_BIT) +#define LVDS_PLL_SSCN_BIT 17 +#define LVDS_PLL_SSCN_MASK (0x7f << LVDS_PLL_SSCN_BIT) +#define LVDS_PLL_COUNT_BIT 4 +#define LVDS_PLL_COUNT_MASK (0x1fff << LVDS_PLL_COUNT_BIT) +#define LVDS_PLL_GAIN_BIT 0 +#define LVDS_PLL_GAIN_MASK (0x0f << LVDS_PLL_GAIN_BIT) + +/* TXECTRL (LVDS Transmitter's Enhance Control */ + +#define LVDS_TX_EM_S_BIT 9 +#define LVDS_TX_EM_S_MASK (0x03 << LVDS_TX_EM_S_BIT) +#define LVDS_TX_EM_EN BIT(8) +#define LVDS_TX_LDO_VO_S_BIT 5 +#define LVDS_TX_LDO_VO_S_MASK (0x03 << LVDS_TX_LDO_VO_S_BIT) +#define LVDS_TX_LDO_VO_S_0 (0x00 << LVDS_TX_LDO_VO_S_BIT) +#define LVDS_TX_LDO_VO_S_1 (0x01 << LVDS_TX_LDO_VO_S_BIT) +#define LVDS_TX_LDO_VO_S_2 (0x02 << LVDS_TX_LDO_VO_S_BIT) +#define LVDS_TX_LDO_VO_S_3 (0x03 << LVDS_TX_LDO_VO_S_BIT) +#define LVDS_PLL_PL_BP BIT(4) + +/* + * Internal 7x clock phase fine tuning for data + * setup/hold time optimization + */ +#define LVDS_TX_CK_PHA_FINE_BIT 2 +#define LVDS_TX_CK_PHA_FINE_MASK (0x03 << LVDS_TX_CK_PHA_FINE_BIT) +/* + * Internal 7x clock phase coarse tuning for data + * setup/hold time optimization + */ +#define LVDS_TX_CK_PHA_COAR_BIT 0 +#define LVDS_TX_CK_PHA_COAR_MASK (0x03 << LVDS_TX_CK_PHA_COAR_BIT) + +/* + * Helpers: + */ + +static inline unsigned long jz4780_read(struct drm_device *dev, u32 reg) +{ + struct jz4780_drm_private *priv = dev->dev_private; + + return ioread32(priv->mmio + reg); +} + +static inline void jz4780_write(struct drm_device *dev, u32 reg, u32 data) +{ + struct jz4780_drm_private *priv = dev->dev_private; + + iowrite32(data, priv->mmio + reg); +} +#endif /* __JZ4780_REGS_H__ */
Add drm driver for the Ingenic JZ4780 SoC. Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> --- V1 -> V2 Fixed Module_License macro Fix in makefile and a #include drm_flip_work Rebased to 4.0-rc3 Removed you should have received a copy of license etc. --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/jz4780/Kconfig | 12 + drivers/gpu/drm/jz4780/Makefile | 3 + drivers/gpu/drm/jz4780/jz4780_crtc.c | 719 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/jz4780/jz4780_drv.c | 388 +++++++++++++++++++ drivers/gpu/drm/jz4780/jz4780_drv.h | 82 ++++ drivers/gpu/drm/jz4780/jz4780_regs.h | 694 +++++++++++++++++++++++++++++++++ 8 files changed, 1901 insertions(+) create mode 100644 drivers/gpu/drm/jz4780/Kconfig create mode 100644 drivers/gpu/drm/jz4780/Makefile create mode 100644 drivers/gpu/drm/jz4780/jz4780_crtc.c create mode 100644 drivers/gpu/drm/jz4780/jz4780_drv.c create mode 100644 drivers/gpu/drm/jz4780/jz4780_drv.h create mode 100644 drivers/gpu/drm/jz4780/jz4780_regs.h