From patchwork Mon Mar 9 12:44:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zubair Lutfullah Kakakhel X-Patchwork-Id: 5974041 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 2D7B79F2A9 for ; Tue, 10 Mar 2015 02:12:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CB66F203C2 for ; Tue, 10 Mar 2015 02:12:05 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 94131203C1 for ; Tue, 10 Mar 2015 02:12:01 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C5D8D6E67B; Mon, 9 Mar 2015 19:11:49 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mailapp01.imgtec.com (mailapp01.imgtec.com [195.59.15.196]) by gabe.freedesktop.org (Postfix) with ESMTP id 749E46E4F4 for ; Mon, 9 Mar 2015 05:44:44 -0700 (PDT) Received: from KLMAIL01.kl.imgtec.org (unknown [192.168.5.35]) by Websense Email Security Gateway with ESMTPS id A2523E67A3C7D; Mon, 9 Mar 2015 12:44:39 +0000 (GMT) Received: from LEMAIL01.le.imgtec.org (192.168.152.62) by KLMAIL01.kl.imgtec.org (192.168.5.35) with Microsoft SMTP Server (TLS) id 14.3.195.1; Mon, 9 Mar 2015 12:44:42 +0000 Received: from zkakakhel-linux.le.imgtec.org (192.168.154.89) by LEMAIL01.le.imgtec.org (192.168.152.62) with Microsoft SMTP Server (TLS) id 14.3.210.2; Mon, 9 Mar 2015 12:44:41 +0000 From: Zubair Lutfullah Kakakhel To: Subject: [PATCH_V2 3/5] drm: jz4780: Add DRM driver for Ingenic JZ4780 Date: Mon, 9 Mar 2015 12:44:03 +0000 Message-ID: <1425905045-14007-4-git-send-email-Zubair.Kakakhel@imgtec.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1425905045-14007-1-git-send-email-Zubair.Kakakhel@imgtec.com> References: <1425905045-14007-1-git-send-email-Zubair.Kakakhel@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [192.168.154.89] X-Mailman-Approved-At: Mon, 09 Mar 2015 19:11:46 -0700 Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Zubair.Kakakhel@imgtec.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add drm driver for the Ingenic JZ4780 SoC. Signed-off-by: Zubair Lutfullah Kakakhel --- 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 + * + * 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 + +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include + +#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 "); +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* 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 + * + * 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 + +#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__ */