From: Zheng Yang Date: Mon, 7 Jul 2014 05:08:04 +0000 (+0800) Subject: rk3036 lcdc: commit driver code, just pass compiling. X-Git-Tag: firefly_0821_release~4916^2~292 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=commitdiff_plain;h=b8d4b5f2ec8efc0850c39df7bb76bea969caa996 rk3036 lcdc: commit driver code, just pass compiling. --- diff --git a/arch/arm/boot/dts/lcd-box.dtsi b/arch/arm/boot/dts/lcd-box.dtsi new file mode 100755 index 000000000000..8d7710b6cb47 --- /dev/null +++ b/arch/arm/boot/dts/lcd-box.dtsi @@ -0,0 +1,97 @@ +/* + * RockChip. LCD_BOX + * + */ + +/ { + disp_power_ctr: power_ctr { + /* rockchip,debug = <0>; + lcd_en:lcd_en { + rockchip,power_type = ; + gpios = <&gpio0 GPIO_B0 GPIO_ACTIVE_HIGH>; + rockchip,delay = <10>; + }; + + bl_en:bl_en { + rockchip,power_type = ; + gpios = <&gpio0 GPIO_A2 GPIO_ACTIVE_HIGH>; + rockchip,delay = <10>; + }; + + bl_ctr:bl_ctr { + rockchip,power_type = ; + gpios = <&gpio3 GPIO_D6 GPIO_ACTIVE_HIGH>; + rockchip,delay = <10>; + }; + + lcd_rst:lcd_rst { + rockchip,power_type = ; + rockchip,delay = <5>; + };*/ + + }; + + disp_timings: display-timings { + native-mode = <&timing0>; + timing0: timing0 { + screen-type = ; + out-face = ; + clock-frequency = <74250000>; + hactive = <1280>; + vactive = <720>; + hback-porch = <220>; + hfront-porch = <110>; + vback-porch = <20>; + vfront-porch = <5>; + hsync-len = <40>; + vsync-len = <5>; + hsync-active = <1>; + vsync-active = <1>; + de-active = <0>; + pixelclk-active = <0>; + swap-rb = <0>; + swap-rg = <0>; + swap-gb = <0>; + }; + timing1: timing1 { + screen-type = ; + out-face = ; + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hback-porch = <148>; + hfront-porch = <88>; + vback-porch = <36>; + vfront-porch = <4>; + hsync-len = <44>; + vsync-len = <5>; + hsync-active = <1>; + vsync-active = <1>; + de-active = <0>; + pixelclk-active = <0>; + swap-rb = <0>; + swap-rg = <0>; + swap-gb = <0>; + }; + timing2: timing2 { + screen-type = ; + out-face = ; + clock-frequency = <297000000>; + hactive = <3840>; + vactive = <2160>; + hback-porch = <296>; + hfront-porch = <176>; + vback-porch = <72>; + vfront-porch = <8>; + hsync-len = <88>; + vsync-len = <10>; + hsync-active = <1>; + vsync-active = <1>; + de-active = <0>; + pixelclk-active = <0>; + swap-rb = <0>; + swap-rg = <0>; + swap-gb = <0>; + }; + }; +}; diff --git a/arch/arm/boot/dts/rk3036-fpga.dts b/arch/arm/boot/dts/rk3036-fpga.dts index b78f28059888..c8ae65af314e 100644 --- a/arch/arm/boot/dts/rk3036-fpga.dts +++ b/arch/arm/boot/dts/rk3036-fpga.dts @@ -1,6 +1,7 @@ /dts-v1/; - +#include #include "rk3036.dtsi" +#include "lcd-box.dtsi" / { compatible = "rockchip,rk3036"; diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi index 591da87ea3c6..fcc04c0584a1 100755 --- a/arch/arm/boot/dts/rk3036.dtsi +++ b/arch/arm/boot/dts/rk3036.dtsi @@ -400,7 +400,17 @@ clocks = <&clk_gates1 6>, <&clk_gates7 3>; clock-names = "clk_usbphy1", "hclk_usb1"; }; - + + lcdc: lcdc@10118000 { + compatible = "rockchip,rk3036-lcdc"; + reg = <0x10118000 0x4000>; + interrupts = ; + status = "disabled"; + clocks = <&clk_gates9 6>, <&dclk_lcdc1>, <&clk_gates9 5>; + clock-names = "aclk_lcdc", "dclk_lcdc", "hclk_lcdc"; + rockchip,iommu-enabled = <1>; + }; + hdmi: hdmi@20034000 { compatible = "rockchip,rk3036-hdmi"; reg = <0x20034000 0x4000>; @@ -413,7 +423,7 @@ clock-names = "pclk_hdmi"; status = "disabled"; }; - +/* vpu: vpu_service@10108000 { compatible = "vpu_service"; reg = <0x10108000 0x800>; @@ -434,7 +444,7 @@ clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core", "clk_cabac"; name = "hevc_service"; status = "disabled"; - +*/ vop_mmu { dbgname = "vop"; compatible = "iommu,vop_mmu"; diff --git a/drivers/video/rockchip/lcdc/Kconfig b/drivers/video/rockchip/lcdc/Kconfig index 04bff9588cb4..6c0d314028a6 100755 --- a/drivers/video/rockchip/lcdc/Kconfig +++ b/drivers/video/rockchip/lcdc/Kconfig @@ -31,3 +31,9 @@ config LCDC_RK3288 depends on DRM_ROCKCHIP || FB_ROCKCHIP help Driver for rk3288 lcdc.There are two lcd controllers on rk3288 + +config LCDC_RK3036 + bool "rk3036 lcdc support" + depends on DRM_ROCKCHIP || FB_ROCKCHIP + help + Driver for rk3036 lcdc. \ No newline at end of file diff --git a/drivers/video/rockchip/lcdc/Makefile b/drivers/video/rockchip/lcdc/Makefile index c51409284826..4c96d38d0328 100644 --- a/drivers/video/rockchip/lcdc/Makefile +++ b/drivers/video/rockchip/lcdc/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_LCDC_RK2928) += rk2928_lcdc.o obj-$(CONFIG_LCDC_RK3066B) += rk3066b_lcdc.o obj-$(CONFIG_LCDC_RK3188) += rk3188_lcdc.o obj-$(CONFIG_LCDC_RK3288) += rk3288_lcdc.o +obj-$(CONFIG_LCDC_RK3036) += rk3036_lcdc.o diff --git a/drivers/video/rockchip/lcdc/rk3036_lcdc.c b/drivers/video/rockchip/lcdc/rk3036_lcdc.c new file mode 100644 index 000000000000..e78ce2ea8c08 --- /dev/null +++ b/drivers/video/rockchip/lcdc/rk3036_lcdc.c @@ -0,0 +1,1247 @@ +/* + * drivers/video/rockchip/lcdc/rk3036_lcdc.c + * + * Copyright (C) 2014 ROCKCHIP, Inc. + * Author:zhengyang + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rk3036_lcdc.h" + +static int dbg_thresd; +module_param(dbg_thresd, int, S_IRUGO | S_IWUSR); + +#define DBG(level, x...) do { \ + if (unlikely(dbg_thresd >= level)) \ + printk(KERN_INFO x); } while (0) + +static struct rk_lcdc_win lcdc_win[] = { + [0] = { + .name = "win0", + .id = 0, + .support_3d = false, + }, + [1] = { + .name = "win1", + .id = 1, + .support_3d = false, + }, + [2] = { + .name = "hwc", + .id = 2, + .support_3d = false, + }, +}; + +static void layer_enable(struct lcdc_device *lcdc_dev, unsigned int win_id, bool open); + +static irqreturn_t rk3036_lcdc_isr(int irq, void *dev_id) +{ + struct lcdc_device *lcdc_dev = + (struct lcdc_device *)dev_id; + ktime_t timestamp = ktime_get(); + u32 int_reg = lcdc_readl(lcdc_dev, INT_STATUS); + + if (int_reg & m_FS_INT_STA) { + timestamp = ktime_get(); + lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, + v_FS_INT_CLEAR(1)); + //if (lcdc_dev->driver.wait_fs) { + if (0) { + spin_lock(&(lcdc_dev->driver.cpl_lock)); + complete(&(lcdc_dev->driver.frame_done)); + spin_unlock(&(lcdc_dev->driver.cpl_lock)); + } + lcdc_dev->driver.vsync_info.timestamp = timestamp; + wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait); + + } else if (int_reg & m_LF_INT_STA) { + lcdc_msk_reg(lcdc_dev, INT_STATUS, m_LF_INT_CLEAR, + v_LF_INT_CLEAR(1)); + } + return IRQ_HANDLED; +} + +static int rk3036_lcdc_clk_enable(struct lcdc_device *lcdc_dev) +{ +#ifdef CONFIG_RK_FPGA + lcdc_dev->clk_on = 1; + return 0; +#endif + if (!lcdc_dev->clk_on) { + clk_prepare_enable(lcdc_dev->hclk); + clk_prepare_enable(lcdc_dev->dclk); + clk_prepare_enable(lcdc_dev->aclk); +// clk_prepare_enable(lcdc_dev->pd); + spin_lock(&lcdc_dev->reg_lock); + lcdc_dev->clk_on = 1; + spin_unlock(&lcdc_dev->reg_lock); + } + + return 0; +} + +static int rk3036_lcdc_clk_disable(struct lcdc_device *lcdc_dev) +{ +#ifdef CONFIG_RK_FPGA + lcdc_dev->clk_on = 0; + return 0; +#endif + if (lcdc_dev->clk_on) { + spin_lock(&lcdc_dev->reg_lock); + lcdc_dev->clk_on = 0; + spin_unlock(&lcdc_dev->reg_lock); + mdelay(25); + clk_disable_unprepare(lcdc_dev->dclk); + clk_disable_unprepare(lcdc_dev->hclk); + clk_disable_unprepare(lcdc_dev->aclk); +// clk_disable_unprepare(lcdc_dev->pd); + } + + return 0; +} + +static int rk3036_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv) +{ + u32 mask, val; + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + mask = m_FS_INT_CLEAR |m_FS_INT_EN; + val = v_FS_INT_CLEAR(1) | v_FS_INT_EN(1); + lcdc_msk_reg(lcdc_dev, INT_STATUS, mask, val); + return 0; +} + +static int rk3036_lcdc_disable_irq(struct lcdc_device *lcdc_dev) +{ + u32 mask, val; + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + mask = m_FS_INT_CLEAR |m_FS_INT_EN; + val = v_FS_INT_CLEAR(0) | v_FS_INT_EN(0); + lcdc_msk_reg(lcdc_dev, INT_STATUS, mask, val); + spin_unlock(&lcdc_dev->reg_lock); + } else { + spin_unlock(&lcdc_dev->reg_lock); + } + mdelay(1); + return 0; +} + +static void rk_lcdc_read_reg_defalut_cfg(struct lcdc_device + *lcdc_dev) +{ + int reg = 0; + u32 value = 0; + + spin_lock(&lcdc_dev->reg_lock); + for (reg = 0; reg < 0xdc; reg += 4) { + value = lcdc_readl(lcdc_dev, reg); + } + spin_unlock(&lcdc_dev->reg_lock); +} + +/********do basic init*********/ +static int rk3036_lcdc_pre_init(struct rk_lcdc_driver *dev_drv) +{ + u32 mask,val; + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct + lcdc_device, + driver); + if (lcdc_dev->pre_init) + return 0; + + lcdc_dev->hclk = devm_clk_get(lcdc_dev->dev, "hclk_lcdc"); + lcdc_dev->aclk = devm_clk_get(lcdc_dev->dev, "aclk_lcdc"); + lcdc_dev->dclk = devm_clk_get(lcdc_dev->dev, "dclk_lcdc"); +// lcdc_dev->pd = devm_clk_get(lcdc_dev->dev, "pd_lcdc"); + + if (/*IS_ERR(lcdc_dev->pd) ||*/ (IS_ERR(lcdc_dev->aclk)) || + (IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) { + dev_err(lcdc_dev->dev, "failed to get lcdc%d clk source\n", + lcdc_dev->id); + } + + rk_disp_pwr_enable(dev_drv); + rk3036_lcdc_clk_enable(lcdc_dev); + + /*backup reg config at uboot*/ + rk_lcdc_read_reg_defalut_cfg(lcdc_dev); + + mask = m_AUTO_GATING_EN; + val = v_AUTO_GATING_EN(0); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask,val); + lcdc_cfg_done(lcdc_dev); + if (dev_drv->iommu_enabled) /*disable win0 to workaround iommu pagefault*/ + layer_enable(lcdc_dev, 0, 0); + lcdc_dev->pre_init = true; + + return 0; +} + +static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev) +{ + return 0; +} + +static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + struct rk_lcdc_win *win0 = lcdc_dev->driver.win[0]; + struct rk_lcdc_win *win1 = lcdc_dev->driver.win[1]; + int timeout; + unsigned long flags; + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY, + v_LCDC_STANDBY(lcdc_dev->standby)); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, + m_WIN0_EN | m_WIN1_EN | m_WIN0_RB_SWAP | + m_WIN1_RB_SWAP, + v_WIN0_EN(win0->state) | v_WIN1_EN(win1->state) | + v_WIN0_RB_SWAP(win0->swap_rb) | + v_WIN1_RB_SWAP(win1->swap_rb)); + lcdc_writel(lcdc_dev, WIN0_SCL_FACTOR_YRGB, + v_X_SCL_FACTOR(win0->scale_yrgb_x) | + v_Y_SCL_FACTOR(win0->scale_yrgb_y)); + lcdc_writel(lcdc_dev, WIN0_SCL_FACTOR_CBR, + v_X_SCL_FACTOR(win0->scale_cbcr_x) | + v_Y_SCL_FACTOR(win0->scale_cbcr_y)); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN0_FORMAT, v_WIN0_FORMAT(win0->fmt_cfg)); + lcdc_writel(lcdc_dev, WIN0_ACT_INFO, v_ACT_WIDTH(win0->area[0].xact) | + v_ACT_HEIGHT(win0->area[0].yact)); + lcdc_writel(lcdc_dev, WIN0_DSP_ST, v_DSP_STX(win0->area[0].dsp_stx) | + v_DSP_STY(win0->area[0].dsp_sty)); + lcdc_writel(lcdc_dev, WIN0_DSP_INFO, v_DSP_WIDTH(win0->area[0].xsize) | + v_DSP_HEIGHT(win0->area[0].ysize)); + lcdc_msk_reg(lcdc_dev, WIN0_VIR, m_YRGB_VIR | m_CBBR_VIR, + v_YRGB_VIR(win0->area[0].y_vir_stride) | v_YRGB_VIR(win0->area[0].uv_vir_stride)); + lcdc_writel(lcdc_dev, WIN0_YRGB_MST, win0->area[0].y_addr); + lcdc_writel(lcdc_dev, WIN0_CBR_MST, win0->area[0].uv_addr); + lcdc_writel(lcdc_dev, WIN1_DSP_INFO, v_DSP_WIDTH(win1->area[0].xsize) | + v_DSP_HEIGHT(win1->area[0].ysize)); + lcdc_writel(lcdc_dev, WIN1_DSP_ST, v_DSP_STX(win1->area[0].dsp_stx) | + v_DSP_STY(win1->area[0].dsp_sty)); + lcdc_msk_reg(lcdc_dev, WIN1_VIR, m_YRGB_VIR, v_YRGB_VIR(win1->area[0].y_vir_stride)); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN1_FORMAT, + v_WIN1_FORMAT(win1->fmt_cfg)); + lcdc_writel(lcdc_dev, WIN1_MST, win1->area[0].y_addr); + rk3036_lcdc_alpha_cfg(lcdc_dev); + lcdc_cfg_done(lcdc_dev); + + } + spin_unlock(&lcdc_dev->reg_lock); + //if (dev_drv->wait_fs) { + if (0) { + spin_lock_irqsave(&dev_drv->cpl_lock, flags); + init_completion(&dev_drv->frame_done); + spin_unlock_irqrestore(&dev_drv->cpl_lock, flags); + timeout = wait_for_completion_timeout(&dev_drv->frame_done, + msecs_to_jiffies + (dev_drv->cur_screen->ft + + 5)); + if (!timeout && (!dev_drv->frame_done.done)) { + dev_warn(lcdc_dev->dev, "wait for new frame start time out!\n"); + return -ETIMEDOUT; + } + } + DBG(2, "%s for lcdc%d\n", __func__, lcdc_dev->id); + return 0; + +} + +static void rk3036_lcdc_reg_restore(struct lcdc_device *lcdc_dev) +{ + memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0xdc); +} + +static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv) +{ + u32 mask,val; + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + mask = m_MMU_EN | m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;; + val = v_MMU_EN(1) | v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1); + lcdc_msk_reg(lcdc_dev, AXI_BUS_CTRL, mask, val); + } + spin_unlock(&lcdc_dev->reg_lock); +} + +static int rk3036_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv) +{ +#ifdef CONFIG_RK_FPGA + return 0; +#endif + int ret,fps; + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + struct rk_screen *screen = dev_drv->cur_screen; + + ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock); + if (ret) + dev_err(dev_drv->dev, "set lcdc%d dclk failed\n", lcdc_dev->id); + lcdc_dev->pixclock = + div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + lcdc_dev->driver.pixclock = lcdc_dev->pixclock; + + fps = rk_fb_calc_fps(screen, lcdc_dev->pixclock); + screen->ft = 1000 / fps; + dev_info(lcdc_dev->dev, "%s: dclk:%lu>>fps:%d ", + lcdc_dev->driver.name, clk_get_rate(lcdc_dev->dclk), fps); + return 0; + +} + +static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) +{ + int ret = -EINVAL; + int fps; + u16 face = 0; + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + struct rk_screen *screen = dev_drv->cur_screen; + u16 right_margin = screen->mode.right_margin; + u16 left_margin = screen->mode.left_margin; + u16 lower_margin = screen->mode.lower_margin; + u16 upper_margin = screen->mode.upper_margin; + u16 x_res = screen->mode.xres; + u16 y_res = screen->mode.yres; + u32 mask, val; + + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + switch (screen->type) { + case SCREEN_HDMI: + mask = m_HDMI_DCLK_EN; + val = v_HDMI_DCLK_EN(1); + if(screen->pixelrepeat) { + mask |= m_CORE_CLK_DIV_EN; + val |= v_CORE_CLK_DIV_EN(1); + } + lcdc_msk_reg(lcdc_dev, AXI_BUS_CTRL, mask, val); + break; + case SCREEN_TVOUT: + mask = m_TVE_DAC_DCLK_EN; + val = v_TVE_DAC_DCLK_EN(1); + if(screen->pixelrepeat) { + mask |= m_CORE_CLK_DIV_EN; + val |= v_CORE_CLK_DIV_EN(1); + } + lcdc_msk_reg(lcdc_dev, AXI_BUS_CTRL, mask, val); + break; + default: + dev_err(lcdc_dev->dev, "un supported interface!\n"); + break; + } + + mask = m_DSP_OUT_FORMAT | m_HSYNC_POL | m_VSYNC_POL | + m_DEN_POL | m_DCLK_POL; + val = v_DSP_OUT_FORMAT(face) | v_HSYNC_POL(screen->pin_hsync) | + v_VSYNC_POL(screen->pin_vsync) | v_DEN_POL(screen->pin_den) | + v_DCLK_POL(screen->pin_dclk); + lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val); + + mask = m_BG_COLOR | m_DSP_BG_SWAP | m_DSP_RB_SWAP | + m_DSP_RG_SWAP | m_DSP_DELTA_SWAP | + m_DSP_DUMMY_SWAP | m_BLANK_EN; + + val = v_BG_COLOR(0x000000) | v_DSP_BG_SWAP(screen->swap_gb) | + v_DSP_RB_SWAP(screen->swap_rb) | v_DSP_RG_SWAP(screen-> + swap_rg) | + v_DSP_DELTA_SWAP(screen-> + swap_delta) | v_DSP_DUMMY_SWAP(screen-> + swap_dumy) | + v_BLANK_EN(0) | v_BLACK_EN(0); + lcdc_msk_reg(lcdc_dev, DSP_CTRL1, mask, val); + val = + v_HSYNC(screen->mode.hsync_len) | v_HORPRD(screen->mode. + hsync_len + + left_margin + + x_res + + right_margin); + lcdc_writel(lcdc_dev, DSP_HTOTAL_HS_END, val); + val = v_HAEP(screen->mode.hsync_len + left_margin + x_res) | + v_HASP(screen->mode.hsync_len + left_margin); + lcdc_writel(lcdc_dev, DSP_HACT_ST_END, val); + + val = + v_VSYNC(screen->mode.vsync_len) | v_VERPRD(screen->mode. + vsync_len + + upper_margin + + y_res + + lower_margin); + lcdc_writel(lcdc_dev, DSP_VTOTAL_VS_END, val); + + val = v_VAEP(screen->mode.vsync_len + upper_margin + y_res) | + v_VASP(screen->mode.vsync_len + screen->mode.upper_margin); + lcdc_writel(lcdc_dev, DSP_VACT_ST_END, val); + } + spin_unlock(&lcdc_dev->reg_lock); + + ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock); + if (ret) + dev_err(dev_drv->dev, "set lcdc%d dclk failed\n", lcdc_dev->id); + lcdc_dev->pixclock = + div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + lcdc_dev->driver.pixclock = lcdc_dev->pixclock; + + fps = rk_fb_calc_fps(screen, lcdc_dev->pixclock); + screen->ft = 1000 / fps; + dev_info(lcdc_dev->dev, "%s: dclk:%lu>>fps:%d ", + lcdc_dev->driver.name, clk_get_rate(lcdc_dev->dclk), fps); + if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) + dev_drv->trsm_ops->enable(); + if (screen->init) + screen->init(); + + return 0; +} + +static void layer_enable(struct lcdc_device *lcdc_dev, unsigned int win_id, bool open) +{ + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + if (open) { + if (!lcdc_dev->atv_layer_cnt) { + dev_info(lcdc_dev->dev, "wakeup from standby!\n"); + lcdc_dev->standby = 0; + } + lcdc_dev->atv_layer_cnt++; + } else if ((lcdc_dev->atv_layer_cnt > 0) && (!open)) { + lcdc_dev->atv_layer_cnt--; + } + lcdc_dev->driver.win[win_id]->state = open; + if(win_id == 0) + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN0_EN, v_WIN0_EN(open)); + else if(win_id == 1) + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN1_EN, v_WIN1_EN(open)); + else + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_HWC_EN, v_HWC_EN(open)); + /*if no layer used,disable lcdc*/ + if (!lcdc_dev->atv_layer_cnt) { + dev_info(lcdc_dev->dev, "no layer is used,go to standby!\n"); + lcdc_dev->standby = 1; + } + } + spin_unlock(&lcdc_dev->reg_lock); +} + +static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id, + bool open) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + + /*enable clk,when first layer open */ + if ((open) && (!lcdc_dev->atv_layer_cnt)) { + rk3036_lcdc_pre_init(dev_drv); + rk3036_lcdc_clk_enable(lcdc_dev); + rk3036_lcdc_reg_restore(lcdc_dev); + if (dev_drv->iommu_enabled) + rk3036_lcdc_mmu_en(dev_drv); + if ((support_uboot_display()&&(lcdc_dev->prop == PRMRY))) { + rk3036_lcdc_set_dclk(dev_drv); + rk3036_lcdc_enable_irq(dev_drv); + } else { + rk3036_load_screen(dev_drv, 1); + } + } + if(win_id < ARRAY_SIZE(lcdc_win)) { + layer_enable(lcdc_dev, win_id, open); + } + else + dev_err(lcdc_dev->dev, "invalid win id:%d\n", win_id); + + /*when all layer closed,disable clk */ + if ((!open) && (!lcdc_dev->atv_layer_cnt)) { + rk3036_lcdc_disable_irq(lcdc_dev); + rk3036_lcdc_reg_update(dev_drv); + rk3036_lcdc_clk_disable(lcdc_dev); + } + + return 0; +} + +static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv,int win_id) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + struct rk_screen *screen = dev_drv->cur_screen; + struct rk_lcdc_win *win = NULL; + char fmt[9] = "NULL"; + + if (!screen) { + dev_err(dev_drv->dev, "screen is null!\n"); + return -ENOENT; + } + + if (win_id == 0) { + win = dev_drv->win[0]; + } else if (win_id == 1) { + win = dev_drv->win[1]; + } else { + dev_err(dev_drv->dev, "un supported win number:%d\n", win_id); + return -EINVAL; + } + + spin_lock(&lcdc_dev->reg_lock); + + win->area[0].dsp_stx = win->area[0].xpos + screen->mode.left_margin + screen->mode.hsync_len; + win->area[0].dsp_sty = win->area[0].ypos + screen->mode.upper_margin + screen->mode.vsync_len; + win->scale_yrgb_x = CalScale(win->area[0].xact, win->area[0].xsize); + win->scale_yrgb_y = CalScale(win->area[0].yact, win->area[0].ysize); + switch (win->format) { + case ARGB888: + win->fmt_cfg = VOP_FORMAT_ARGB888; + win->swap_rb = 0; + break; + case XBGR888: + win->fmt_cfg = VOP_FORMAT_ARGB888; + win->swap_rb = 1; + break; + case ABGR888: + win->fmt_cfg = VOP_FORMAT_ARGB888; + win->swap_rb = 1; + break; + case RGB888: + win->fmt_cfg = VOP_FORMAT_RGB888; + win->swap_rb = 0; + break; + case RGB565: + win->fmt_cfg = VOP_FORMAT_RGB565; + win->swap_rb = 0; + break; + case YUV444: + if(win_id == 0) { + win->fmt_cfg = VOP_FORMAT_YCBCR444; + win->scale_cbcr_x = CalScale(win->area[0].xact, win->area[0].xsize); + win->scale_cbcr_y = CalScale(win->area[0].yact, win->area[0].ysize); + win->swap_rb = 0; + } else { + dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", + __func__); + } + break; + case YUV422: + if(win_id == 0) { + win->fmt_cfg = VOP_FORMAT_YCBCR422; + win->scale_cbcr_x = CalScale((win->area[0].xact / 2), win->area[0].xsize); + win->scale_cbcr_y = CalScale(win->area[0].yact, win->area[0].ysize); + win->swap_rb = 0; + } else { + dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", + __func__); + } + break; + case YUV420: + if(win_id == 0) { + win->fmt_cfg = VOP_FORMAT_YCBCR420; + win->scale_cbcr_x = CalScale(win->area[0].xact / 2, win->area[0].xsize); + win->scale_cbcr_y = CalScale(win->area[0].yact / 2, win->area[0].ysize); + win->swap_rb = 0; + } + else { + dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", + __func__); + } + break; + default: + dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", + __func__); + break; + } + spin_unlock(&lcdc_dev->reg_lock); + + if (lcdc_dev->clk_on) { + rk3036_lcdc_alpha_cfg(lcdc_dev); + } + DBG(1, "lcdc%d>>%s\n>>format:%s>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d\n" + ">>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id, + __func__, get_format_string(win->format, fmt), win->area[0].xact, + win->area[0].yact, win->area[0].xsize, win->area[0].ysize, win->area[0].xvir, + win->area[0].yvir, win->area[0].xpos, win->area[0].ypos); + return 0; +} + +static int rk3036_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + struct rk_lcdc_win *win = NULL; + struct rk_screen *screen = dev_drv->cur_screen; + + if (!screen) { + dev_err(dev_drv->dev,"screen is null!\n"); + return -ENOENT; + } + + if (win_id == 0) { + win = dev_drv->win[0]; + } else if(win_id==1) { + win = dev_drv->win[1]; + } else { + dev_err(dev_drv->dev,"invalid win number:%d!\n", win_id); + return -EINVAL; + } + + + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + win->area[0].y_addr = win->area[0].smem_start+win->area[0].y_offset; + win->area[0].uv_addr = win->area[0].cbr_start + win->area[0].c_offset; + if(win_id == 0) { + lcdc_writel(lcdc_dev, WIN0_YRGB_MST, win->area[0].y_addr); + lcdc_writel(lcdc_dev, WIN0_CBR_MST, win->area[0].uv_addr); + } else + lcdc_writel(lcdc_dev, WIN1_MST, win->area[0].y_addr); + /*lcdc_cfg_done(lcdc_dev);*/ + } + spin_unlock(&lcdc_dev->reg_lock); + + DBG(2, "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x>>offset:%d\n", + lcdc_dev->id, __func__, win->area[0].y_addr, win->area[0].uv_addr,win->area[0].y_offset); + /*this is the first frame of the system ,enable frame start interrupt*/ + if ((dev_drv->first_frame)) { + dev_drv->first_frame = 0; + rk3036_lcdc_enable_irq(dev_drv); + + } + + return 0; +} + +static int rk3036_lcdc_ioctl(struct rk_lcdc_driver *dev_drv, unsigned int cmd, + unsigned long arg, int win_id) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + u32 panel_size[2]; + void __user *argp = (void __user *)arg; + struct color_key_cfg clr_key_cfg; + + switch (cmd) { + case RK_FBIOGET_PANEL_SIZE: + panel_size[0] = lcdc_dev->screen->mode.xres; + panel_size[1] = lcdc_dev->screen->mode.yres; + if (copy_to_user(argp, panel_size, 8)) + return -EFAULT; + break; + case RK_FBIOPUT_COLOR_KEY_CFG: + if (copy_from_user(&clr_key_cfg, argp, + sizeof(struct color_key_cfg))) + return -EFAULT; + lcdc_writel(lcdc_dev, WIN0_COLOR_KEY, + clr_key_cfg.win0_color_key_cfg); + lcdc_writel(lcdc_dev, WIN1_COLOR_KEY, + clr_key_cfg.win1_color_key_cfg); + break; + + default: + break; + } + return 0; +} + +static int rk3036_lcdc_get_win_id(struct rk_lcdc_driver *dev_drv, + const char *id) +{ + int win_id = 0; + mutex_lock(&dev_drv->fb_win_id_mutex); + if (!strcmp(id, "fb0")) + win_id = dev_drv->fb0_win_id; + else if (!strcmp(id, "fb1")) + win_id = dev_drv->fb1_win_id; + else if (!strcmp(id, "fb2")) + win_id = dev_drv->fb2_win_id; + mutex_unlock(&dev_drv->fb_win_id_mutex); + + return win_id; +} + +static int rk3036_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv, int win_id) +{ + return 0; +} + +static int rk3036_lcdc_ovl_mgr(struct rk_lcdc_driver *dev_drv, int swap, + bool set) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + int ovl; + spin_lock(&lcdc_dev->reg_lock); + if (lcdc_dev->clk_on) { + if (set) { + lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_WIN0_TOP, + v_WIN0_TOP(swap)); + ovl = swap; + } else { + ovl = lcdc_read_bit(lcdc_dev, DSP_CTRL0, m_WIN0_TOP); + } + } else { + ovl = -EPERM; + } + spin_unlock(&lcdc_dev->reg_lock); + + return ovl; +} + +static int rk3036_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv) +{ + + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + if (dev_drv->suspend_flag) + return 0; + dev_drv->suspend_flag = 1; + flush_kthread_worker(&dev_drv->update_regs_worker); + + if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable) + dev_drv->trsm_ops->disable(); + spin_lock(&lcdc_dev->reg_lock); + if (likely(lcdc_dev->clk_on)) { + lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BLANK_EN, + v_BLANK_EN(1)); + lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, + v_FS_INT_CLEAR(1)); + lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_OUT_ZERO, + v_DSP_OUT_ZERO(1)); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY, + v_LCDC_STANDBY(1)); + lcdc_cfg_done(lcdc_dev); + spin_unlock(&lcdc_dev->reg_lock); + } else { + spin_unlock(&lcdc_dev->reg_lock); + return 0; + } + rk3036_lcdc_clk_disable(lcdc_dev); + rk_disp_pwr_disable(dev_drv); + return 0; +} + +static int rk3036_lcdc_early_resume(struct rk_lcdc_driver *dev_drv) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + + if (!dev_drv->suspend_flag) + return 0; + rk_disp_pwr_enable(dev_drv); + dev_drv->suspend_flag = 0; + + if (lcdc_dev->atv_layer_cnt) { + rk3036_lcdc_clk_enable(lcdc_dev); + rk3036_lcdc_reg_restore(lcdc_dev); + + spin_lock(&lcdc_dev->reg_lock); + + lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_OUT_ZERO, + v_DSP_OUT_ZERO(0)); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY, + v_LCDC_STANDBY(0)); + lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BLANK_EN, + v_BLANK_EN(0)); + lcdc_cfg_done(lcdc_dev); + + spin_unlock(&lcdc_dev->reg_lock); + } + + if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) + dev_drv->trsm_ops->enable(); + return 0; +} + + +static int rk3036_lcdc_blank(struct rk_lcdc_driver *dev_drv, + int win_id, int blank_mode) +{ + switch (blank_mode) { + case FB_BLANK_UNBLANK: + rk3036_lcdc_early_resume(dev_drv); + break; + case FB_BLANK_NORMAL: + rk3036_lcdc_early_suspend(dev_drv); + break; + default: + rk3036_lcdc_early_suspend(dev_drv); + break; + } + + dev_info(dev_drv->dev, "blank mode:%d\n", blank_mode); + + return 0; +} + +static int rk3036_lcdc_cfg_done(struct rk_lcdc_driver *dev_drv) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, driver); + spin_lock(&lcdc_dev->reg_lock); + if (lcdc_dev->clk_on) + lcdc_cfg_done(lcdc_dev); + spin_unlock(&lcdc_dev->reg_lock); + return 0; +} + +/* + a:[-30~0]: + sin_hue = sin(a)*256 +0x100; + cos_hue = cos(a)*256; + a:[0~30] + sin_hue = sin(a)*256; + cos_hue = cos(a)*256; +*/ +static int rk3036_lcdc_get_bcsh_hue(struct rk_lcdc_driver *dev_drv,bcsh_hue_mode mode) +{ + + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 val; + + spin_lock(&lcdc_dev->reg_lock); + if (lcdc_dev->clk_on) { + val = lcdc_readl(lcdc_dev, BCSH_H); + switch(mode){ + case H_SIN: + val &= m_BCSH_SIN_HUE; + break; + case H_COS: + val &= m_BCSH_COS_HUE; + val >>= 16; + break; + default: + break; + } + } + spin_unlock(&lcdc_dev->reg_lock); + + return val; +} + + +static int rk3036_lcdc_set_bcsh_hue(struct rk_lcdc_driver *dev_drv,int sin_hue, int cos_hue) +{ + + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 mask, val; + + spin_lock(&lcdc_dev->reg_lock); + if (lcdc_dev->clk_on) { + mask = m_BCSH_SIN_HUE | m_BCSH_COS_HUE; + val = v_BCSH_SIN_HUE(sin_hue) | v_BCSH_COS_HUE(cos_hue); + lcdc_msk_reg(lcdc_dev, BCSH_H, mask, val); + lcdc_cfg_done(lcdc_dev); + } + spin_unlock(&lcdc_dev->reg_lock); + + return 0; +} + +static int rk3036_lcdc_set_bcsh_bcs(struct rk_lcdc_driver *dev_drv,bcsh_bcs_mode mode,int value) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 mask, val; + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) { + switch (mode) { + case BRIGHTNESS: + /*from 0 to 255,typical is 128*/ + if (value < 0x80) + value += 0x80; + else if (value >= 0x80) + value = value - 0x80; + mask = m_BCSH_BRIGHTNESS; + val = v_BCSH_BRIGHTNESS(value); + break; + case CONTRAST: + /*from 0 to 510,typical is 256*/ + mask = m_BCSH_CONTRAST; + val = v_BCSH_CONTRAST(value); + break; + case SAT_CON: + /*from 0 to 1015,typical is 256*/ + mask = m_BCSH_SAT_CON; + val = v_BCSH_SAT_CON(value); + break; + default: + break; + } + lcdc_msk_reg(lcdc_dev, BCSH_BCS, mask, val); + lcdc_cfg_done(lcdc_dev); + } + spin_unlock(&lcdc_dev->reg_lock); + return val; +} + +static int rk3036_lcdc_get_bcsh_bcs(struct rk_lcdc_driver *dev_drv,bcsh_bcs_mode mode) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 val; + + spin_lock(&lcdc_dev->reg_lock); + if(lcdc_dev->clk_on) { + val = lcdc_readl(lcdc_dev, BCSH_BCS); + switch (mode) { + case BRIGHTNESS: + val &= m_BCSH_BRIGHTNESS; + if(val > 0x80) + val -= 0x80; + else + val += 0x80; + break; + case CONTRAST: + val &= m_BCSH_CONTRAST; + val >>= 8; + break; + case SAT_CON: + val &= m_BCSH_SAT_CON; + val >>= 20; + break; + default: + break; + } + } + spin_unlock(&lcdc_dev->reg_lock); + return val; +} + + +static int rk3036_lcdc_open_bcsh(struct rk_lcdc_driver *dev_drv, bool open) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 mask, val; + + spin_lock(&lcdc_dev->reg_lock); + if (lcdc_dev->clk_on) { + if (open) { + lcdc_writel(lcdc_dev,BCSH_COLOR_BAR,0x1); + lcdc_writel(lcdc_dev,BCSH_BCS,0xd0010000); + lcdc_writel(lcdc_dev,BCSH_H,0x01000000); + } else { + mask = m_BCSH_EN; + val = v_BCSH_EN(0); + lcdc_msk_reg(lcdc_dev, BCSH_COLOR_BAR, mask, val); + } + lcdc_cfg_done(lcdc_dev); + } + spin_unlock(&lcdc_dev->reg_lock); + return 0; +} + +static int rk3036_fb_win_remap(struct rk_lcdc_driver *dev_drv, + enum fb_win_map_order order) +{ + mutex_lock(&dev_drv->fb_win_id_mutex); + if (order == FB_DEFAULT_ORDER) + order = FB0_WIN0_FB1_WIN1_FB2_WIN2; + dev_drv->fb2_win_id = order / 100; + dev_drv->fb1_win_id = (order / 10) % 10; + dev_drv->fb0_win_id = order % 10; + mutex_unlock(&dev_drv->fb_win_id_mutex); + + return 0; +} + +static int rk3036_lcdc_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps, + bool set) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + struct rk_screen *screen = dev_drv->cur_screen; + u64 ft = 0; + u32 dotclk; + int ret; + u32 pixclock; + u32 x_total, y_total; + if (set) { + ft = div_u64(1000000000000llu, fps); + x_total = + screen->mode.upper_margin + screen->mode.lower_margin + + screen->mode.yres + screen->mode.vsync_len; + y_total = + screen->mode.left_margin + screen->mode.right_margin + + screen->mode.xres + screen->mode.hsync_len; + dev_drv->pixclock = div_u64(ft, x_total * y_total); + dotclk = div_u64(1000000000000llu, dev_drv->pixclock); + ret = clk_set_rate(lcdc_dev->dclk, dotclk); + } + + pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk)); + dev_drv->pixclock = lcdc_dev->pixclock = pixclock; + fps = rk_fb_calc_fps(lcdc_dev->screen, pixclock); + screen->ft = 1000 / fps; /*one frame time in ms */ + + if (set) + dev_info(dev_drv->dev, "%s:dclk:%lu,fps:%d\n", __func__, + clk_get_rate(lcdc_dev->dclk), fps); + + return fps; +} + +static int rk3036_lcdc_poll_vblank(struct rk_lcdc_driver *dev_drv) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + u32 int_reg; + int ret; + + if (lcdc_dev->clk_on) { + int_reg = lcdc_readl(lcdc_dev, INT_STATUS); + if (int_reg & m_LF_INT_STA) { + lcdc_msk_reg(lcdc_dev, INT_STATUS, m_LF_INT_CLEAR, + v_LF_INT_CLEAR(1)); + ret = RK_LF_STATUS_FC; + } else + ret = RK_LF_STATUS_FR; + } else { + ret = RK_LF_STATUS_NC; + } + + return ret; +} + +static int rk3036_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,unsigned int *dsp_addr) +{ + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + + if(lcdc_dev->clk_on){ + dsp_addr[0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST); + dsp_addr[1] = lcdc_readl(lcdc_dev, WIN1_MST); + } + return 0; +} + +static ssize_t rk3036_lcdc_get_disp_info(struct rk_lcdc_driver *dev_drv, + char *buf, int win_id) +{ +// struct lcdc_device *lcdc_dev = container_of(dev_drv, +// struct lcdc_device, driver); +// struct rk_screen *screen = dev_drv->cur_screen; + struct rk_lcdc_win *win = NULL; + char fmt[9] = "NULL"; + u32 size; + + if (win_id < ARRAY_SIZE(lcdc_win)) { + win = dev_drv->win[win_id]; + } else { + dev_err(dev_drv->dev,"invalid win number:%d!\n", win_id); + return 0; + } + + size = snprintf(buf, PAGE_SIZE, "win%d: %s\n", win_id, get_format_string(win->format, fmt)); + size += snprintf(buf + size, PAGE_SIZE - size, " xact %d yact %d xvir %d yvir %d\n", + win->area[0].xact, win->area[0].yact, win->area[0].xvir, win->area[0].yvir); + size += snprintf(buf + size, PAGE_SIZE - size, " xpos %d ypos %d xsize %d ysize %d\n", + win->area[0].xpos, win->area[0].ypos, win->area[0].xsize, win->area[0].ysize); + size += snprintf(buf + size, PAGE_SIZE - size, " yaddr 0x%x uvaddr 0x%x\n", + win->area[0].y_addr, win->area[0].uv_addr); + return size; +} + +static int rk3036_lcdc_reg_dump(struct rk_lcdc_driver *dev_drv) +{ + struct lcdc_device *lcdc_dev = container_of(dev_drv, + struct lcdc_device, + driver); + int *cbase = (int *)lcdc_dev->regs; + int *regsbak = (int *)lcdc_dev->regsbak; + int i, j; + + printk("back up reg:\n"); + for (i = 0; i <= (0x90 >> 4); i++) { + for (j = 0; j < 4; j++) + printk("%08x ", *(regsbak + i * 4 + j)); + printk("\n"); + } + + printk("lcdc reg:\n"); + for (i = 0; i <= (0x90 >> 4); i++) { + for (j = 0; j < 4; j++) + printk("%08x ", readl_relaxed(cbase + i * 4 + j)); + printk("\n"); + } + return 0; +} + +static struct rk_lcdc_drv_ops lcdc_drv_ops = { + .open = rk3036_lcdc_open, + .load_screen = rk3036_load_screen, + .set_par = rk3036_lcdc_set_par, + .pan_display = rk3036_lcdc_pan_display, + .blank = rk3036_lcdc_blank, + .ioctl = rk3036_lcdc_ioctl, + .get_win_state = rk3036_lcdc_get_win_state, + .ovl_mgr = rk3036_lcdc_ovl_mgr, + .get_disp_info = rk3036_lcdc_get_disp_info, + .fps_mgr = rk3036_lcdc_fps_mgr, + .fb_get_win_id = rk3036_lcdc_get_win_id, + .fb_win_remap = rk3036_fb_win_remap, + .poll_vblank = rk3036_lcdc_poll_vblank, + .get_dsp_addr = rk3036_lcdc_get_dsp_addr, + .cfg_done = rk3036_lcdc_cfg_done, + .dump_reg = rk3036_lcdc_reg_dump, + .set_dsp_bcsh_hue = rk3036_lcdc_set_bcsh_hue, + .set_dsp_bcsh_bcs = rk3036_lcdc_set_bcsh_bcs, + .get_dsp_bcsh_hue = rk3036_lcdc_get_bcsh_hue, + .get_dsp_bcsh_bcs = rk3036_lcdc_get_bcsh_bcs, + .open_bcsh = rk3036_lcdc_open_bcsh, +}; + +static int rk3036_lcdc_probe(struct platform_device *pdev) +{ + struct lcdc_device *lcdc_dev = NULL; + struct rk_lcdc_driver *dev_drv; + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + + lcdc_dev = devm_kzalloc(dev, + sizeof(struct lcdc_device), GFP_KERNEL); + if (!lcdc_dev) { + dev_err(&pdev->dev, "rk3036 lcdc device kmalloc fail!"); + return -ENOMEM; + } + platform_set_drvdata(pdev, lcdc_dev); + lcdc_dev->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lcdc_dev->reg_phy_base = res->start; + lcdc_dev->len = resource_size(res); + lcdc_dev->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(lcdc_dev->regs)) + return PTR_ERR(lcdc_dev->regs); + + lcdc_dev->regsbak = devm_kzalloc(dev, lcdc_dev->len, GFP_KERNEL); + if (IS_ERR(lcdc_dev->regsbak)) + return PTR_ERR(lcdc_dev->regsbak); + + dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id); + dev_drv = &lcdc_dev->driver; + dev_drv->dev = dev; + dev_drv->prop = 0; + dev_drv->id = lcdc_dev->id; + dev_drv->ops = &lcdc_drv_ops; + dev_drv->lcdc_win_num = ARRAY_SIZE(lcdc_win); + spin_lock_init(&lcdc_dev->reg_lock); + + lcdc_dev->irq = platform_get_irq(pdev, 0); + if (lcdc_dev->irq < 0) { + dev_err(&pdev->dev, "cannot find IRQ for lcdc%d\n", + lcdc_dev->id); + return -ENXIO; + } + + ret = devm_request_irq(dev, lcdc_dev->irq, rk3036_lcdc_isr, + IRQF_DISABLED, dev_name(dev), lcdc_dev); + if (ret) { + dev_err(&pdev->dev, "cannot requeset irq %d - err %d\n", + lcdc_dev->irq, ret); + return ret; + } + + ret = rk_fb_register(dev_drv, lcdc_win, lcdc_dev->id); + if (ret < 0) { + dev_err(dev, "register fb for lcdc%d failed!\n", lcdc_dev->id); + return ret; + } + lcdc_dev->screen = dev_drv->screen0; + + dev_info(dev, "lcdc%d probe ok\n", lcdc_dev->id); + return 0; +} + +#if defined(CONFIG_PM) +static int rk3036_lcdc_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int rk3036_lcdc_resume(struct platform_device *pdev) +{ + return 0; +} +#else +#define rk3036_lcdc_suspend NULL +#define rk3036_lcdc_resume NULL +#endif + +static int rk3036_lcdc_remove(struct platform_device *pdev) +{ + return 0; +} + +static void rk3036_lcdc_shutdown(struct platform_device *pdev) +{ + +} + +#if defined(CONFIG_OF) +static const struct of_device_id rk3036_lcdc_dt_ids[] = { + {.compatible = "rockchip,rk3036-lcdc",}, + {} +}; +#endif + +static struct platform_driver rk3036_lcdc_driver = { + .probe = rk3036_lcdc_probe, + .remove = rk3036_lcdc_remove, + .driver = { + .name = "rk3036-lcdc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rk3036_lcdc_dt_ids), + }, + .suspend = rk3036_lcdc_suspend, + .resume = rk3036_lcdc_resume, + .shutdown = rk3036_lcdc_shutdown, +}; + +static int __init rk3036_lcdc_module_init(void) +{ + return platform_driver_register(&rk3036_lcdc_driver); +} + +static void __exit rk3036_lcdc_module_exit(void) +{ + platform_driver_unregister(&rk3036_lcdc_driver); +} + +fs_initcall(rk3036_lcdc_module_init); +module_exit(rk3036_lcdc_module_exit); \ No newline at end of file diff --git a/drivers/video/rockchip/lcdc/rk3036_lcdc.h b/drivers/video/rockchip/lcdc/rk3036_lcdc.h new file mode 100644 index 000000000000..bb0861ac8e01 --- /dev/null +++ b/drivers/video/rockchip/lcdc/rk3036_lcdc.h @@ -0,0 +1,546 @@ +#ifndef _RK3036_LCDC_H_ +#define _RK3036_LCDC_H_ + +#include +#include +#include + +/*******************register definition**********************/ + +#define SYS_CTRL (0x00) + #define m_WIN0_EN (1<<0) + #define m_WIN1_EN (1<<1) + #define m_HWC_EN (1<<2) + #define m_WIN0_FORMAT (7<<3) + #define m_WIN1_FORMAT (7<<6) + #define m_HWC_LUT_EN (1<<9) + #define m_HWC_SIZE (1<<10) + #define m_WIN0_RB_SWAP (1<<15) + #define m_WIN0_ALPHA_SWAP (1<<16) + #define m_WIN0_Y8_SWAP (1<<17) + #define m_WIN0_UV_SWAP (1<<18) + #define m_WIN1_RB_SWAP (1<<19) + #define m_WIN1_ALPHA_SWAP (1<<20) + #define m_WIN0_OTSD_DISABLE (1<<22) + #define m_WIN1_OTSD_DISABLE (1<<23) + #define m_DMA_BURST_LENGTH (3<<24) + #define m_HWC_LODAD_EN (1<<26) + #define m_DMA_STOP (1<<29) + #define m_LCDC_STANDBY (1<<30) + #define m_AUTO_GATING_EN (1<<31) + + #define v_WIN0_EN(x) (((x)&1)<<0) + #define v_WIN1_EN(x) (((x)&1)<<1) + #define v_HWC_EN(x) (((x)&1)<<2) + #define v_WIN0_FORMAT(x) (((x)&7)<<3) + #define v_WIN1_FORMAT(x) (((x)&7)<<6) + #define v_HWC_LUT_EN(x) (((x)&1)<<9) + #define v_HWC_SIZE(x) (((x)&1)<<10) + #define v_WIN0_RB_SWAP(x) (((x)&1)<<15) + #define v_WIN0_ALPHA_SWAP(x) (((x)&1)<<16) + #define v_WIN0_Y8_SWAP(x) (((x)&1)<<17) + #define v_WIN0_UV_SWAP(x) (((x)&1)<<18) + #define v_WIN1_RB_SWAP(x) (((x)&1)<<19) + #define v_WIN1_ALPHA_SWAP(x) (((x)&1)<<20) + #define v_WIN0_OTSD_DISABLE(x) (((x)&1)<<22) + #define v_WIN1_OTSD_DISABLE(x) (((x)&1)<<23) + #define v_DMA_BURST_LENGTH(x) (((x)&3)<<24) + #define v_HWC_LODAD_EN(x) (((x)&1)<<26) + #define v_WIN1_LUT_EN(x) (((x)&1)<<27) + #define v_DMA_STOP(x) (((x)&1)<<29) + #define v_LCDC_STANDBY(x) (((x)&1)<<30) + #define v_AUTO_GATING_EN(x) (((x)&1)<<31) + +#define DSP_CTRL0 (0x04) + #define m_DSP_OUT_FORMAT (0x0f<<0) + #define m_HSYNC_POL (1<<4) + #define m_VSYNC_POL (1<<5) + #define m_DEN_POL (1<<6) + #define m_DCLK_POL (1<<7) + #define m_WIN0_TOP (1<<8) + #define m_DITHER_UP_EN (1<<9) + #define m_INTERLACE_DSP_EN (1<<12) + #define m_WIN1_INTERLACE_EN (1<<15) + #define m_WIN0_YRGB_DEFLICK_EN (1<<16) + #define m_WIN0_CBR_DEFLICK_EN (1<<17) + #define m_WIN0_ALPHA_MODE (1<<18) + #define m_WIN1_ALPHA_MODE (1<<19) + #define m_WIN0_CSC_MODE (3<<20) + #define m_WIN0_YUV_CLIP (1<<23) + #define m_TVE_MODE (1<<25) + #define m_HWC_ALPHA_MODE (1<<28) + #define m_PREMUL_ALPHA_ENABLE (1<<29) + #define m_ALPHA_MODE_SEL1 (1<<30) + #define m_WIN1_DIFF_DCLK_EN (1<<31) + + #define v_DSP_OUT_FORMAT(x) (((x)&0x0f)<<0) + #define v_HSYNC_POL(x) (((x)&1)<<4) + #define v_VSYNC_POL(x) (((x)&1)<<5) + #define v_DEN_POL(x) (((x)&1)<<6) + #define v_DCLK_POL(x) (((x)&1)<<7) + #define v_WIN0_TOP(x) (((x)&1)<<8) + #define v_DITHER_UP_EN(x) (((x)&1)<<9) + #define v_INTERLACE_DSP_EN(x) (((x)&1)<<12) + #define v_WIN1_INTERLACE_EN(x) (((x)&1)<<15) + #define v_WIN0_YRGB_DEFLICK_EN(x) (((x)&1)<<16) + #define v_WIN0_CBR_DEFLICK_EN(x) (((x)&1)<<17) + #define v_WIN0_ALPHA_MODE(x) (((x)&1)<<18) + #define v_WIN1_ALPHA_MODE(x) (((x)&1)<<19) + #define v_WIN0_CSC_MODE(x) (((x)&3)<<20) + #define v_WIN0_YUV_CLIP(x) (((x)&1)<<23) + #define v_TVE_MODE(x) (((x)&1)<<25) + #define v_HWC_ALPHA_MODE(x) (((x)&1)<<28) + #define v_PREMUL_ALPHA_ENABLE(x) (((x)&1)<<29) + #define v_ALPHA_MODE_SEL1(x) (((x)&1)<<30) + #define v_WIN1_DIFF_DCLK_EN(x) (((x)&1)<<31) + +#define DSP_CTRL1 (0x08) + #define m_BG_COLOR (0xffffff<<0) + #define m_BG_B (0xff<<0) + #define m_BG_G (0xff<<8) + #define m_BG_R (0xff<<16) + #define m_BLANK_EN (1<<24) + #define m_BLACK_EN (1<<25) + #define m_DSP_BG_SWAP (1<<26) + #define m_DSP_RB_SWAP (1<<27) + #define m_DSP_RG_SWAP (1<<28) + #define m_DSP_DELTA_SWAP (1<<29) + #define m_DSP_DUMMY_SWAP (1<<30) + #define m_DSP_OUT_ZERO (1<<31) + + #define v_BG_COLOR(x) (((x)&0xffffff)<<0) + #define v_BG_B(x) (((x)&0xff)<<0) + #define v_BG_G(x) (((x)&0xff)<<8) + #define v_BG_R(x) (((x)&0xff)<<16) + #define v_BLANK_EN(x) (((x)&1)<<24) + #define v_BLACK_EN(x) (((x)&1)<<25) + #define v_DSP_BG_SWAP(x) (((x)&1)<<26) + #define v_DSP_RB_SWAP(x) (((x)&1)<<27) + #define v_DSP_RG_SWAP(x) (((x)&1)<<28) + #define v_DSP_DELTA_SWAP(x) (((x)&1)<<29) + #define v_DSP_DUMMY_SWAP(x) (((x)&1)<<30) + #define v_DSP_OUT_ZERO(x) (((x)&1)<<31) + +#define INT_STATUS (0x10) + #define m_HS_INT_STA (1<<0) //status + #define m_FS_INT_STA (1<<1) + #define m_LF_INT_STA (1<<2) + #define m_BUS_ERR_INT_STA (1<<3) + #define m_HS_INT_EN (1<<4) //enable + #define m_FS_INT_EN (1<<5) + #define m_LF_INT_EN (1<<6) + #define m_BUS_ERR_INT_EN (1<<7) + #define m_HS_INT_CLEAR (1<<8) //auto clear + #define m_FS_INT_CLEAR (1<<9) + #define m_LF_INT_CLEAR (1<<10) + #define m_BUS_ERR_INT_CLEAR (1<<11) + #define m_LF_INT_NUM (0xfff<<12) + #define m_WIN0_EMPTY_INT_EN (1<<24) + #define m_WIN1_EMPTY_INT_EN (1<<25) + #define m_WIN0_EMPTY_INT_CLEAR (1<<26) + #define m_WIN1_EMPTY_INT_CLEAR (1<<27) + #define m_WIN0_EMPTY_INT_STA (1<<28) + #define m_WIN1_EMPTY_INT_STA (1<<29) + #define m_FS_RAW_STA (1<<30) + #define m_LF_RAW_STA (1<<31) + + #define v_HS_INT_EN(x) (((x)&1)<<4) + #define v_FS_INT_EN(x) (((x)&1)<<5) + #define v_LF_INT_EN(x) (((x)&1)<<6) + #define v_BUS_ERR_INT_EN(x) (((x)&1)<<7) + #define v_HS_INT_CLEAR(x) (((x)&1)<<8) + #define v_FS_INT_CLEAR(x) (((x)&1)<<9) + #define v_LF_INT_CLEAR(x) (((x)&1)<<10) + #define v_BUS_ERR_INT_CLEAR(x) (((x)&1)<<11) + #define v_LF_INT_NUM(x) (((x)&0xfff)<<12) + #define v_WIN0_EMPTY_INT_EN(x) (((x)&1)<<24) + #define v_WIN1_EMPTY_INT_EN(x) (((x)&1)<<25) + #define v_WIN0_EMPTY_INT_CLEAR(x) (((x)&1)<<26) + #define v_WIN1_EMPTY_INT_CLEAR(x) (((x)&1)<<27) + + +#define ALPHA_CTRL (0x14) + #define m_WIN0_ALPHA_EN (1<<0) + #define m_WIN1_ALPHA_EN (1<<1) + #define m_HWC_ALPAH_EN (1<<2) + #define m_WIN1_PREMUL_SCALE (1<<3) + #define m_WIN0_ALPHA_VAL (0xff<<4) + #define m_WIN1_ALPHA_VAL (0xff<<12) + #define m_HWC_ALPAH_VAL (0x0f<<20) + + #define v_WIN0_ALPHA_EN(x) (((x)&1)<<0) + #define v_WIN1_ALPHA_EN(x) (((x)&1)<<1) + #define v_HWC_ALPAH_EN(x) (((x)&1)<<2) + #define v_WIN1_PREMUL_SCALE(x) (((x)&1)<<3) + #define v_WIN0_ALPHA_VAL(x) (((x)&0xff)<<4) + #define v_WIN1_ALPHA_VAL(x) (((x)&0xff)<<12) + #define v_HWC_ALPAH_VAL(x) (((x)&0x0f)<<20) + +#define WIN0_COLOR_KEY (0x18) +#define WIN1_COLOR_KEY (0x1C) + #define m_COLOR_KEY_VAL (0xffffff<<0) + #define m_COLOR_KEY_EN (1<<24) + #define v_COLOR_KEY_VAL(x) (((x)&0xffffff)<<0) + #define v_COLOR_KEY_EN(x) (((x)&1)<<24) + +/* Layer Registers */ +#define WIN0_YRGB_MST (0x20) +#define WIN0_CBR_MST (0x24) +#define WIN1_MST (0xa0) +#define HWC_MST (0x58) + +#define WIN1_VIR (0x28) +#define WIN0_VIR (0x30) + #define m_YRGB_VIR (0x1fff << 0) + #define m_CBBR_VIR (0x1fff << 16) + + #define v_YRGB_VIR(x) ((x & 0x1fff) << 0) + #define v_CBBR_VIR(x) ((x & 0x1fff) << 16) + + #define v_ARGB888_VIRWIDTH(x) (((x)&0x1fff)<<0) + #define v_RGB888_VIRWIDTH(x) (((((x*3)>>2)+((x)%3))&0x1fff)<<0) + #define v_RGB565_VIRWIDTH(x) ((DIV_ROUND_UP(x,2)&0x1fff)<<0) + #define v_YUV_VIRWIDTH(x) ((DIV_ROUND_UP(x,4)&0x1fff)<<0) + #define v_CBCR_VIR(x) ((x & 0x1fff) << 16) + +#define WIN0_ACT_INFO (0x34) +#define WIN1_ACT_INFO (0xB4) + #define m_ACT_WIDTH (0x1fff<<0) + #define m_ACT_HEIGHT (0x1fff<<16) + #define v_ACT_WIDTH(x) (((x-1)&0x1fff)<<0) + #define v_ACT_HEIGHT(x) (((x-1)&0x1fff)<<16) + +#define WIN0_DSP_INFO (0x38) +#define WIN1_DSP_INFO (0xB8) + #define v_DSP_WIDTH(x) (((x-1)&0x7ff)<<0) + #define v_DSP_HEIGHT(x) (((x-1)&0x7ff)<<16) + +#define WIN0_DSP_ST (0x3C) +#define WIN1_DSP_ST (0xBC) +#define HWC_DSP_ST (0x5C) + #define v_DSP_STX(x) (((x)&0xfff)<<0) + #define v_DSP_STY(x) (((x)&0xfff)<<16) + +#define WIN0_SCL_FACTOR_YRGB (0x40) +#define WIN0_SCL_FACTOR_CBR (0x44) +#define WIN1_SCL_FACTOR_YRGB (0xC0) + #define v_X_SCL_FACTOR(x) (((x)&0xffff)<<0) + #define v_Y_SCL_FACTOR(x) (((x)&0xffff)<<16) + +#define WIN0_SCL_OFFSET (0x48) +#define WIN1_SCL_OFFSET (0xC8) + +/* LUT Registers */ +#define WIN1_LUT_ADDR (0x0400) +#define HWC_LUT_ADDR (0x0800) + +/* Display Infomation Registers */ +#define DSP_HTOTAL_HS_END (0x6C) + #define v_HSYNC(x) (((x)&0xfff)<<0) //hsync pulse width + #define v_HORPRD(x) (((x)&0xfff)<<16) //horizontal period + +#define DSP_HACT_ST_END (0x70) + #define v_HAEP(x) (((x)&0xfff)<<0) //horizontal active end point + #define v_HASP(x) (((x)&0xfff)<<16) //horizontal active start point + +#define DSP_VTOTAL_VS_END (0x74) + #define v_VSYNC(x) (((x)&0xfff)<<0) + #define v_VERPRD(x) (((x)&0xfff)<<16) + +#define DSP_VACT_ST_END (0x78) + #define v_VAEP(x) (((x)&0xfff)<<0) + #define v_VASP(x) (((x)&0xfff)<<16) + +#define DSP_VS_ST_END_F1 (0x7C) +#define DSP_VACT_ST_END_F1 (0x80) + +/*BCSH Registers*/ +#define BCSH_COLOR_BAR (0xD0) + #define v_BCSH_EN(x) (((x)&1)<<0) + #define v_BCSH_COLOR_BAR_Y(x) (((x)&0x3ff)<<2) + #define v_BCSH_COLOR_BAR_U(x) (((x)&0x3ff)<<12) + #define v_BCSH_COLOR_BAR_V(x) (((x)&0x3ff)<<22) + + #define m_BCSH_EN (1<<0) + #define m_BCSH_COLOR_BAR_Y (0x3ff<<2) + #define m_BCSH_COLOR_BAR_U (0x3ff<<12) + #define m_BCSH_COLOR_BAR_V ((u32)0x3ff<<22) + +#define BCSH_BCS (0xD4) + #define v_BCSH_BRIGHTNESS(x) (((x)&0xff)<<0) + #define v_BCSH_CONTRAST(x) (((x)&0x1ff)<<8) + #define v_BCSH_SAT_CON(x) (((x)&0x3ff)<<20) + #define v_BCSH_OUT_MODE(x) (((x)&0x3)<<30) + + #define m_BCSH_BRIGHTNESS (0xff<<0) + #define m_BCSH_CONTRAST (0x1ff<<8) + #define m_BCSH_SAT_CON (0x3ff<<20) + #define m_BCSH_OUT_MODE ((u32)0x3<<30) + + +#define BCSH_H (0xD8) + #define v_BCSH_SIN_HUE(x) (((x)&0x1ff)<<0) + #define v_BCSH_COS_HUE(x) (((x)&0x1ff)<<16) + + #define m_BCSH_SIN_HUE (0x1ff<<0) + #define m_BCSH_COS_HUE (0x1ff<<16) + +/* Bus Register */ +#define AXI_BUS_CTRL (0x2C) + #define m_IO_PAD_CLK (1 << 31) + #define m_CORE_CLK_DIV_EN (1 << 30) + #define m_HDMI_DCLK_INVERT (1 << 23) + #define m_HDMI_DCLK_EN (1 << 22) + #define m_TVE_DAC_DCLK_INVERT (1 << 21) + #define m_TVE_DAC_DCLK_EN (1 << 20) + #define m_HDMI_DCLK_DIV_EN (1 << 19) + #define m_AXI_OUTSTANDING_MAX_NUM (0x1f << 12) + #define m_AXI_MAX_OUTSTANDING_EN (1 << 11) + #define m_MMU_EN (1 << 10) + #define m_NOC_HURRY_THRESHOLD (0xf << 6) + #define m_NOC_HURRY_VALUE (3 << 4) + #define m_NOC_HURRY_EN (1 << 3) + #define m_NOC_QOS_VALUE (3 << 1) + #define m_NOC_QOS_EN (1 << 0) + + #define v_IO_PAD_CLK(x) ((x&1) << 31) + #define v_CORE_CLK_DIV_EN(x) ((x&1) << 30) + #define v_HDMI_DCLK_INVERT(x) ((x&1) << 23) + #define v_HDMI_DCLK_EN(x) ((x&1) << 22) + #define v_TVE_DAC_DCLK_INVERT(x) ((x&1) << 21) + #define v_TVE_DAC_DCLK_EN(x) ((x&1) << 20) + #define v_HDMI_DCLK_DIV_EN(x) ((x&1) << 19) + #define v_AXI_OUTSTANDING_MAX_NUM(x) ((x&0x1f) << 12) + #define v_AXI_MAX_OUTSTANDING_EN(x) ((x&1) << 11) + #define v_MMU_EN(x) ((x&1) << 10) + #define v_NOC_HURRY_THRESHOLD(x) ((x&0xf) << 6) + #define v_NOC_HURRY_VALUE(x) ((x&3) << 4) + #define v_NOC_HURRY_EN(x) ((x&1) << 3) + #define v_NOC_QOS_VALUE(x) ((x&3) << 1) + #define v_NOC_QOS_EN(x) ((x&1) << 0) + +#define GATHER_TRANSFER (0x84) + #define m_WIN1_AXI_GATHER_NUM (0xf << 12) + #define m_WIN0_CBCR_AXI_GATHER_NUM (0x7 << 8) + #define m_WIN0_YRGB_AXI_GATHER_NUM (0xf << 4) + #define m_WIN1_AXI_GAHTER_EN (1 << 2) + #define m_WIN0_CBCR_AXI_GATHER_EN (1 << 1) + #define m_WIN0_YRGB_AXI_GATHER_EN (1 << 0) + + #define v_WIN1_AXI_GATHER_NUM(x) ((x & 0xf) << 12) + #define v_WIN0_CBCR_AXI_GATHER_NUM(x) ((x & 0x7) << 8) + #define v_WIN0_YRGB_AXI_GATHER_NUM(x) ((x & 0xf) << 4) + #define v_WIN1_AXI_GAHTER_EN(x) ((x & 1) << 2) + #define v_WIN0_CBCR_AXI_GATHER_EN(x) ((x & 1) << 1) + #define v_WIN0_YRGB_AXI_GATHER_EN(x) ((x & 1) << 0) + +#define VERSION_INFO (0x94) + #define m_MAJOR (0xff << 24) + #define m_MINOR (0xff << 16) + #define m_BUILD (0xffff) + +#define REG_CFG_DONE (0x90) + +/* TV Control Registers */ +#define TV_CTRL (0x200) +#define TV_SYNC_TIMING (0x204) +#define TV_ACT_TIMING (0x208) +#define TV_ADJ_TIMING (0x20c) +#define TV_FREQ_SC (0x210) +#define TV_FILTER0 (0x214) +#define TV_FILTER1 (0x218) +#define TV_FILTER2 (0x21C) +#define TV_ACT_ST (0x234) +#define TV_ROUTING (0x238) +#define TV_SYNC_ADJUST (0x250) +#define TV_STATUS (0x254) +#define TV_RESET (0x268) +#define TV_SATURATION (0x278) +#define TV_BW_CTRL (0x28C) +#define TV_BRIGHTNESS_CONTRAST (0x290) + + +/* MMU registers */ +#define MMU_DTE_ADDR (0x0300) + #define v_MMU_DTE_ADDR(x) (((x)&0xffffffff)<<0) + #define m_MMU_DTE_ADDR (0xffffffff<<0) + +#define MMU_STATUS (0x0304) + #define v_PAGING_ENABLED(x) (((x)&1)<<0) + #define v_PAGE_FAULT_ACTIVE(x) (((x)&1)<<1) + #define v_STAIL_ACTIVE(x) (((x)&1)<<2) + #define v_MMU_IDLE(x) (((x)&1)<<3) + #define v_REPLAY_BUFFER_EMPTY(x) (((x)&1)<<4) + #define v_PAGE_FAULT_IS_WRITE(x) (((x)&1)<<5) + #define v_PAGE_FAULT_BUS_ID(x) (((x)&0x1f)<<6) + #define m_PAGING_ENABLED (1<<0) + #define m_PAGE_FAULT_ACTIVE (1<<1) + #define m_STAIL_ACTIVE (1<<2) + #define m_MMU_IDLE (1<<3) + #define m_REPLAY_BUFFER_EMPTY (1<<4) + #define m_PAGE_FAULT_IS_WRITE (1<<5) + #define m_PAGE_FAULT_BUS_ID (0x1f<<6) + +#define MMU_COMMAND (0x0308) + #define v_MMU_CMD(x) (((x)&0x3)<<0) + #define m_MMU_CMD (0x3<<0) + +#define MMU_PAGE_FAULT_ADDR (0x030c) + #define v_PAGE_FAULT_ADDR(x) (((x)&0xffffffff)<<0) + #define m_PAGE_FAULT_ADDR (0xffffffff<<0) + +#define MMU_ZAP_ONE_LINE (0x0310) + #define v_MMU_ZAP_ONE_LINE(x) (((x)&0xffffffff)<<0) + #define m_MMU_ZAP_ONE_LINE (0xffffffff<<0) + +#define MMU_INT_RAWSTAT (0x0314) + #define v_PAGE_FAULT_RAWSTAT(x) (((x)&1)<<0) + #define v_READ_BUS_ERROR_RAWSTAT(x) (((x)&1)<<1) + #define m_PAGE_FAULT_RAWSTAT (1<<0) + #define m_READ_BUS_ERROR_RAWSTAT (1<<1) + +#define MMU_INT_CLEAR (0x0318) + #define v_PAGE_FAULT_CLEAR(x) (((x)&1)<<0) + #define v_READ_BUS_ERROR_CLEAR(x) (((x)&1)<<1) + #define m_PAGE_FAULT_CLEAR (1<<0) + #define m_READ_BUS_ERROR_CLEAR (1<<1) + +#define MMU_INT_MASK (0x031c) + #define v_PAGE_FAULT_MASK(x) (((x)&1)<<0) + #define v_READ_BUS_ERROR_MASK(x) (((x)&1)<<1) + #define m_PAGE_FAULT_MASK (1<<0) + #define m_READ_BUS_ERROR_MASK (1<<1) + +#define MMU_INT_STATUS (0x0320) + #define v_PAGE_FAULT_STATUS(x) (((x)&1)<<0) + #define v_READ_BUS_ERROR_STATUS(x) (((x)&1)<<1) + #define m_PAGE_FAULT_STATUS (1<<0) + #define m_READ_BUS_ERROR_STATUS (1<<1) + +#define MMU_AUTO_GATING (0x0324) + #define v_MMU_AUTO_GATING(x) (((x)&1)<<0) + #define m_MMU_AUTO_GATING (1<<0) + +enum _vop_dma_burst { + DMA_BURST_16 = 0, + DMA_BURST_8, + DMA_BURST_4 +}; + +enum _vop_format_e { + VOP_FORMAT_ARGB888 = 0, + VOP_FORMAT_RGB888, + VOP_FORMAT_RGB565, + VOP_FORMAT_YCBCR420, + VOP_FORMAT_YCBCR422, + VOP_FORMAT_YCBCR444 +}; + +enum _vop_tv_mode { + TV_NTSC, + TV_PAL, +}; + +enum _vop_csc_mode { + VOP_CSC_BT601 = 0, + VOP_CSC_JPEG, + VOP_CSC_BT709 +}; + +enum _vop_hwc_size { + VOP_HWC_SIZE_32, + VOP_HWC_SIZE_64 +}; + +#define CalScale(x, y) ((((u32)(x-1))*0x1000)/(y-1)) + +struct lcdc_device{ + int id; + struct rk_lcdc_driver driver; + struct device *dev; + struct rk_screen *screen; + + void __iomem *regs; + void *regsbak; /*back up reg*/ + u32 reg_phy_base; /* physical basic address of lcdc register*/ + u32 len; /* physical map length of lcdc register*/ + spinlock_t reg_lock; /*one time only one process allowed to config the register*/ + + int __iomem *dsp_lut_addr_base; + + + int prop; /*used for primary or extended display device*/ + bool pre_init; + bool pwr18; /*if lcdc use 1.8v power supply*/ + bool clk_on; /*if aclk or hclk is closed ,acess to register is not allowed*/ + u8 atv_layer_cnt; /*active layer counter,when atv_layer_cnt = 0,disable lcdc*/ + + + unsigned int irq; + + struct clk *pd; /*lcdc power domain*/ + struct clk *hclk; /*lcdc AHP clk*/ + struct clk *dclk; /*lcdc dclk*/ + struct clk *aclk; /*lcdc share memory frequency*/ + u32 pixclock; + + u32 standby; /*1:standby,0:wrok*/ +}; + +static inline void lcdc_writel(struct lcdc_device *lcdc_dev,u32 offset,u32 v) +{ + u32 *_pv = (u32*)lcdc_dev->regsbak; + _pv += (offset >> 2); + *_pv = v; + writel_relaxed(v,lcdc_dev->regs+offset); +} + +static inline u32 lcdc_readl(struct lcdc_device *lcdc_dev,u32 offset) +{ + u32 v; + u32 *_pv = (u32*)lcdc_dev->regsbak; + _pv += (offset >> 2); + v = readl_relaxed(lcdc_dev->regs+offset); + *_pv = v; + return v; +} + +static inline u32 lcdc_read_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk) +{ + u32 _v = readl_relaxed(lcdc_dev->regs+offset); + _v &= msk; + return (_v?1:0); +} + +static inline void lcdc_set_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk) +{ + u32* _pv = (u32*)lcdc_dev->regsbak; + _pv += (offset >> 2); + (*_pv) |= msk; + writel_relaxed(*_pv,lcdc_dev->regs + offset); +} + +static inline void lcdc_clr_bit(struct lcdc_device *lcdc_dev,u32 offset,u32 msk) +{ + u32* _pv = (u32*)lcdc_dev->regsbak; + _pv += (offset >> 2); + (*_pv) &= (~msk); + writel_relaxed(*_pv,lcdc_dev->regs + offset); +} + +static inline void lcdc_msk_reg(struct lcdc_device *lcdc_dev,u32 offset,u32 msk,u32 v) +{ + u32 *_pv = (u32*)lcdc_dev->regsbak; + _pv += (offset >> 2); + (*_pv) &= (~msk); + (*_pv) |= v; + writel_relaxed(*_pv,lcdc_dev->regs+offset); +} + +static inline void lcdc_cfg_done(struct lcdc_device *lcdc_dev) +{ + writel_relaxed(0x01,lcdc_dev->regs+REG_CFG_DONE); + dsb(); +} + +#endif /* _RK3036_LCDC_H_ */ \ No newline at end of file diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 3c1b6c917ca9..57d6a8631ac0 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -2832,7 +2832,8 @@ int rk_fb_dpi_open(bool open) { struct rk_lcdc_driver *dev_drv = NULL; dev_drv = rk_get_prmry_lcdc_drv(); - dev_drv->ops->dpi_open(dev_drv, open); + if(dev_drv->ops->dpi_open) + dev_drv->ops->dpi_open(dev_drv, open); return 0; } @@ -2841,18 +2842,20 @@ int rk_fb_dpi_win_sel(int win_id) { struct rk_lcdc_driver *dev_drv = NULL; dev_drv = rk_get_prmry_lcdc_drv(); - dev_drv->ops->dpi_win_sel(dev_drv, win_id); + if(dev_drv->ops->dpi_win_sel) + dev_drv->ops->dpi_win_sel(dev_drv, win_id); return 0; } int rk_fb_dpi_status(void) { - int ret; + int ret = 0; struct rk_lcdc_driver *dev_drv = NULL; dev_drv = rk_get_prmry_lcdc_drv(); - ret = dev_drv->ops->dpi_status(dev_drv); - + if(dev_drv->ops->dpi_status) + ret = dev_drv->ops->dpi_status(dev_drv); + return ret; } diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index af48af11bef0..fc8b10706e8f 100755 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -330,13 +330,15 @@ static ssize_t show_dsp_bcsh(struct device *dev, struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; int brightness, contrast, sat_con, sin_hue, cos_hue; - - brightness = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, BRIGHTNESS); - contrast = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, CONTRAST); - sat_con = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, SAT_CON); - sin_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv,H_SIN); - cos_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv,H_COS); - + if(dev_drv->ops->get_dsp_bcsh_bcs) { + brightness = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, BRIGHTNESS); + contrast = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, CONTRAST); + sat_con = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, SAT_CON); + } + if(dev_drv->ops->get_dsp_bcsh_hue) { + sin_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv,H_SIN); + cos_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv,H_COS); + } snprintf(buf, PAGE_SIZE, "brightness:%4d,contrast:%4d,sat_con:%4d," "sin_hue:%4d,cos_hue:%4d\n", brightness, contrast,sat_con,sin_hue,cos_hue); @@ -350,37 +352,56 @@ static ssize_t set_dsp_bcsh(struct device *dev, struct device_attribute *attr, struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; int brightness, contrast, sat_con, ret, sin_hue, cos_hue; + if (!strncmp(buf, "open", 4)) { - ret = dev_drv->ops->open_bcsh(dev_drv, 1); + if(dev_drv->ops->open_bcsh) + ret = dev_drv->ops->open_bcsh(dev_drv, 1); + else + ret = -1; } else if (!strncmp(buf, "close", 5)) { - ret = dev_drv->ops->open_bcsh(dev_drv, 0); + if(dev_drv->ops->open_bcsh) + ret = dev_drv->ops->open_bcsh(dev_drv, 0); + else + ret = -1; } else if (!strncmp(buf, "brightness", 10)) { sscanf(buf, "brightness %d", &brightness); if (unlikely(brightness > 255)) { dev_err(fbi->dev,"brightness should be [0:255],now=%d\n\n",brightness); brightness = 255; } - ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, BRIGHTNESS,brightness); + if(dev_drv->ops->set_dsp_bcsh_bcs) + ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, BRIGHTNESS,brightness); + else + ret = -1; } else if (!strncmp(buf, "contrast", 8)) { sscanf(buf, "contrast %d", &contrast); if (unlikely(contrast > 510)) { dev_err(fbi->dev,"contrast should be [0:510],now=%d\n",contrast); contrast = 510; } - ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, CONTRAST,contrast); + if(dev_drv->ops->set_dsp_bcsh_bcs) + ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, CONTRAST,contrast); + else + ret = -1; } else if (!strncmp(buf, "sat_con", 7)) { sscanf(buf, "sat_con %d", &sat_con); if (unlikely(sat_con > 1015)) { dev_err(fbi->dev,"sat_con should be [0:1015],now=%d\n",sat_con); sat_con = 1015; } - ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, SAT_CON,sat_con); + if(dev_drv->ops->set_dsp_bcsh_bcs) + ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv, SAT_CON,sat_con); + else + ret = -1; } else if (!strncmp(buf, "hue", 3)) { sscanf(buf, "hue %d %d", &sin_hue,&cos_hue); if (unlikely(sin_hue > 511 || cos_hue > 511)) { dev_err(fbi->dev,"sin_hue=%d,cos_hue=%d\n",sin_hue,cos_hue); } - ret = dev_drv->ops->set_dsp_bcsh_hue(dev_drv,sin_hue,cos_hue); + if(dev_drv->ops->set_dsp_bcsh_hue) + ret = dev_drv->ops->set_dsp_bcsh_hue(dev_drv,sin_hue,cos_hue); + else + ret = -1; } else { printk("format error\n"); } diff --git a/include/linux/rk_screen.h b/include/linux/rk_screen.h index 4ee4960d49d5..e7f33c1d32a7 100755 --- a/include/linux/rk_screen.h +++ b/include/linux/rk_screen.h @@ -74,6 +74,7 @@ struct rk_screen { u16 x_mirror; u16 y_mirror; int interlace; + int pixelrepeat; //For 480i/576i format, pixel is repeated twice. u16 width; u16 height; u8 ft;