#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/devfreq-event.h>
#include <linux/rockchip-iovmm.h>
#include <asm/div64.h>
#include <linux/uaccess.h>
#include <linux/rockchip/grf.h>
#include <linux/rockchip/common.h>
#include <dt-bindings/clock/rk_system_status.h>
+#include <soc/rockchip/rkfb_dmc.h>
+#include <linux/of_gpio.h>
#include "rk322x_lcdc.h"
} while (0)
static struct rk_lcdc_win rk322x_vop_win[] = {
- { .name = "win0", .id = VOP_WIN0},
- { .name = "win1", .id = VOP_WIN1},
- { .name = "hwc", .id = VOP_HWC}
+ { .name = "win0",
+ .id = VOP_WIN0,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_SCALE | SUPPORT_YUV |
+ SUPPORT_YUV10BIT,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ { .name = "win1",
+ .id = VOP_WIN1,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_SCALE | SUPPORT_YUV |
+ SUPPORT_YUV10BIT,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ {
+ .name = "hwc",
+ .id = VOP_HWC,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_HWC_LAYER,
+ .property.max_input_x = 128,
+ .property.max_input_y = 128
+ }
};
static struct rk_lcdc_win rk3399_vop_win[] = {
- { .name = "win0", .id = VOP_WIN0},
- { .name = "win1", .id = VOP_WIN1},
- { .name = "win2", .id = VOP_WIN2},
- { .name = "win3", .id = VOP_WIN3},
- { .name = "hwc", .id = VOP_HWC}
+ { .name = "win0",
+ .id = VOP_WIN0,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_SCALE | SUPPORT_YUV |
+ SUPPORT_YUV10BIT,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ { .name = "win1",
+ .id = VOP_WIN1,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_SCALE | SUPPORT_YUV |
+ SUPPORT_YUV10BIT,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ { .name = "win2",
+ .id = VOP_WIN2,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_MULTI_AREA,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ { .name = "win3",
+ .id = VOP_WIN3,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_MULTI_AREA,
+ .property.max_input_x = 4096,
+ .property.max_input_y = 2304},
+ {
+ .name = "hwc",
+ .id = VOP_HWC,
+ .property.feature = SUPPORT_WIN_IDENTIFY | SUPPORT_HW_EXIST |
+ SUPPORT_HWC_LAYER,
+ .property.max_input_x = 128,
+ .property.max_input_y = 128
+ }
};
static const struct vop_data rk322x_data = {
int __iomem *c;
v = dsp_lut[i];
- c = vop_dev->dsp_lut_addr_base + (i << 2);
- b = (v & 0xff) << 2;
- g = (v & 0xff00) << 4;
- r = (v & 0xff0000) << 6;
- v = r + g + b;
- for (j = 0; j < 4; j++) {
+ if (dev_drv->id == 0) {
+ c = vop_dev->dsp_lut_addr_base + (i << 2);
+ b = (v & 0xff) << 2;
+ g = (v & 0xff00) << 4;
+ r = (v & 0xff0000) << 6;
+ v = r + g + b;
+ for (j = 0; j < 4; j++) {
+ writel_relaxed(v, c);
+ v += (1 + (1 << 10) + (1 << 20));
+ c++;
+ }
+ } else {
+ c = vop_dev->dsp_lut_addr_base + i;
writel_relaxed(v, c);
- v += (1 + (1 << 10) + (1 << 20));
- c++;
}
}
vop_msk_reg(vop_dev, DSP_CTRL1, V_DSP_LUT_EN(1));
clk_prepare_enable(vop_dev->hclk_noc);
if (vop_dev->aclk_noc)
clk_prepare_enable(vop_dev->aclk_noc);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ pm_runtime_get_sync(vop_dev->dev);
+#endif
spin_lock(&vop_dev->reg_lock);
vop_dev->clk_on = 1;
spin_unlock(&vop_dev->reg_lock);
vop_dev->clk_on = 0;
spin_unlock(&vop_dev->reg_lock);
mdelay(25);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ pm_runtime_put_sync(vop_dev->dev);
+#endif
clk_disable_unprepare(vop_dev->dclk);
clk_disable_unprepare(vop_dev->hclk);
clk_disable_unprepare(vop_dev->aclk);
{
struct vop_device *vop_dev =
container_of(drv, struct vop_device, driver);
+
+ drv->win[win_id]->state = en;
if (win_id == 0)
win0_enable(vop_dev, en);
else if (win_id == 1)
vop_writel(vop_dev, FRC_LOWER11_0, 0xdeb77deb);
vop_writel(vop_dev, FRC_LOWER11_1, 0xed7bb7de);
- vop_msk_reg(vop_dev, SYS_CTRL, V_AUTO_GATING_EN(0));
+ if (!dev_drv->cabc_mode)
+ vop_msk_reg(vop_dev, SYS_CTRL, V_AUTO_GATING_EN(0));
vop_msk_reg(vop_dev, DSP_CTRL1, V_DITHER_UP_EN(1));
vop_cfg_done(vop_dev);
+ if ((dev_drv->cur_screen->refresh_mode == SCREEN_CMD_MODE) &&
+ (support_uboot_display() == 0))
+ vop_msk_reg(vop_dev, SYS_CTRL, V_EDPI_WMS_MODE(1));
vop_dev->pre_init = true;
return 0;
int output_color = dev_drv->output_color;
int i;
- for (i = 0; i < dev_drv->lcdc_win_num && i <= 4; i++) {
+ for (i = 0; i < dev_drv->lcdc_win_num && i < 4; i++) {
struct rk_lcdc_win *win = dev_drv->win[i];
int shift = i * 8;
u64 val = V_WIN0_YUV2YUV_EN(0) | V_WIN0_YUV2YUV_R2Y_EN(0) |
} else if (win->colorspace == CSC_BT2020) {
val |= V_WIN0_YUV2YUV_EN(1);
LOAD_CSC(vop_dev, Y2R, csc_y2r_bt2020, i);
- LOAD_CSC(vop_dev, 3x3, csc_r2r_bt2020to709, i);
+ LOAD_CSC(vop_dev, R2R, csc_r2r_bt2020to709, i);
}
} else if (output_color == COLOR_YCBCR ||
output_color == COLOR_YCBCR_BT709) {
if (!(IS_YUV(win->area[0].fmt_cfg) ||
win->area[0].yuyv_fmt)) {
val |= V_WIN0_YUV2YUV_R2Y_EN(1);
- LOAD_CSC(vop_dev, R2Y, csc_r2y_bt709_full, i);
+ if ((win->id == 0) || (win->id == 1))
+ LOAD_CSC(vop_dev, R2Y, csc_r2y_bt709_full_10, i);
+ else
+ val |= V_WIN0_YUV2YUV_R2Y_MODE(VOP_R2Y_CSC_BT709);
+
} else if (win->colorspace == CSC_BT2020) {
val |= V_WIN0_YUV2YUV_EN(1) |
V_WIN0_YUV2YUV_Y2R_EN(1) |
V_WIN0_YUV2YUV_R2Y_EN(1);
- LOAD_CSC(vop_dev, R2Y, csc_y2r_bt2020, i);
- LOAD_CSC(vop_dev, R2Y, csc_r2r_bt2020to709, i);
- LOAD_CSC(vop_dev, R2Y, csc_r2y_bt709_full, i);
+ LOAD_CSC(vop_dev, Y2R, csc_y2r_bt2020, i);
+ LOAD_CSC(vop_dev, R2R, csc_r2r_bt2020to709, i);
+ LOAD_CSC(vop_dev, R2Y, csc_r2y_bt709_full_10, i);
}
} else if (output_color == COLOR_YCBCR_BT2020) {
if (!(IS_YUV(win->area[0].fmt_cfg) ||
win->area[0].yuyv_fmt)) {
val |= V_WIN0_YUV2YUV_R2Y_EN(1) |
V_WIN0_YUV2YUV_EN(1);
- LOAD_CSC(vop_dev, R2Y, csc_r2r_bt709to2020, i);
- LOAD_CSC(vop_dev, R2Y, csc_r2y_bt2020, i);
+ if ((win->id == 0) || (win->id == 1)) {
+ LOAD_CSC(vop_dev, R2R, csc_r2r_bt709to2020, i);
+ LOAD_CSC(vop_dev, R2Y, csc_r2y_bt2020, i);
+ } else {
+ val |= V_WIN0_YUV2YUV_R2Y_MODE(VOP_R2Y_CSC_BT2020);
+ }
} else if (win->colorspace == CSC_BT601 ||
win->colorspace == CSC_BT709) {
val |= V_WIN0_YUV2YUV_Y2R_EN(1) |
V_WIN0_YUV2YUV_R2Y_EN(1) |
V_WIN0_YUV2YUV_EN(1);
- LOAD_CSC(vop_dev, R2Y, csc_y2r_bt709_full, i);
- LOAD_CSC(vop_dev, R2Y, csc_r2r_bt709to2020, i);
+ LOAD_CSC(vop_dev, Y2R, csc_y2r_bt709_full_10, i);
+ LOAD_CSC(vop_dev, R2R, csc_r2r_bt709to2020, i);
LOAD_CSC(vop_dev, R2Y, csc_r2y_bt2020, i);
}
}
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
int output_color = dev_drv->output_color;
- int win_csc, overlay_mode;
+ int win_csc = 0, overlay_mode = 0;
u64 val;
if (VOP_CHIP(vop_dev) == VOP_RK322X) {
struct alpha_config alpha_config;
u64 val;
int ppixel_alpha = 0, global_alpha = 0, i;
- u32 src_alpha_ctl, dst_alpha_ctl;
+ u32 src_alpha_ctl = 0, dst_alpha_ctl = 0;
int alpha_en = 1;
+ memset(&alpha_config, 0, sizeof(struct alpha_config));
for (i = 0; i < win->area_num; i++) {
ppixel_alpha |= ((win->area[i].format == ARGB888) ||
(win->area[i].format == FBDC_ARGB_888) ||
static int vop_fbdc_reg_update(struct vop_device *vop_dev, int win_id)
{
struct rk_lcdc_win *win = vop_dev->driver.win[win_id];
- u32 val;
+ u64 val;
val = V_VOP_FBDC_WIN_SEL(win_id) |
V_AFBCD_HREG_PIXEL_PACKING_FMT(win->area[0].fbdc_fmt_cfg) |
return 0;
}
- win->area[0].fbdc_mb_width = win->area[0].xact;
+ win->area[0].fbdc_mb_width = win->area[0].xvir;
win->area[0].fbdc_mb_height = win->area[0].yact;
win->area[0].fbdc_cor_en = 0; /* hreg_block_split */
- win->area[0].fbdc_fmt_cfg |= 0 << 4;
+ win->area[0].fbdc_fmt_cfg |= AFBDC_YUV_COLOR_TRANSFORM << 4;
return 0;
}
u64 val;
u32 off;
int format;
+ struct rk_win_property *win_property =
+ &dev_drv->win[win_id]->property;
off = win_id * 0x40;
if (win->state == 1) {
+ if (!(win_property->feature & SUPPORT_HW_EXIST)) {
+ pr_err("vop[%d] win[%d] hardware unsupport\n",
+ vop_dev->id, win_id);
+ return 0;
+ }
vop_axi_gather_cfg(vop_dev, win);
if (win->area[0].fbdc_en)
vop_fbdc_reg_update(vop_dev, win_id);
val = V_WIN0_HS_FACTOR_CBR(win->scale_cbcr_x) |
V_WIN0_VS_FACTOR_CBR(win->scale_cbcr_y);
vop_writel(vop_dev, WIN0_SCL_FACTOR_CBR + off, val);
- if (win->alpha_en == 1) {
- vop_alpha_cfg(dev_drv, win_id);
- } else {
- val = V_WIN0_SRC_ALPHA_EN(0);
- vop_msk_reg(vop_dev, WIN0_SRC_ALPHA_CTRL + off, val);
- }
-
} else {
val = V_WIN0_EN(win->state);
vop_msk_reg(vop_dev, WIN0_CTRL0 + off, val);
struct rk_lcdc_win *win = dev_drv->win[win_id];
unsigned int off;
u64 val;
+ struct rk_win_property *win_property =
+ &dev_drv->win[win_id]->property;
off = (win_id - 2) * 0x50;
area_xst(win, win->area_num);
if (win->state == 1) {
+ if (!(win_property->feature & SUPPORT_HW_EXIST)) {
+ pr_err("vop[%d] win[%d] hardware unsupport\n",
+ vop_dev->id, win_id);
+ return 0;
+ }
vop_axi_gather_cfg(vop_dev, win);
if (win->area[0].fbdc_en)
vop_fbdc_reg_update(vop_dev, win_id);
val = V_WIN2_VIR_STRIDE0(win->area[0].y_vir_stride);
vop_msk_reg(vop_dev, WIN2_VIR0_1 + off, val);
- val = V_WIN2_DSP_WIDTH0(win->area[0].xsize) |
- V_WIN2_DSP_HEIGHT0(win->area[0].ysize);
+ val = V_WIN2_DSP_WIDTH0(win->area[0].xsize - 1) |
+ V_WIN2_DSP_HEIGHT0(win->area[0].ysize - 1);
vop_writel(vop_dev, WIN2_DSP_INFO0 + off, val);
val = V_WIN2_DSP_XST0(win->area[0].dsp_stx) |
V_WIN2_DSP_YST0(win->area[0].dsp_sty);
val = V_WIN2_VIR_STRIDE1(win->area[1].y_vir_stride);
vop_msk_reg(vop_dev, WIN2_VIR0_1 + off, val);
- val = V_WIN2_DSP_WIDTH1(win->area[1].xsize) |
- V_WIN2_DSP_HEIGHT1(win->area[1].ysize);
+ val = V_WIN2_DSP_WIDTH1(win->area[1].xsize - 1) |
+ V_WIN2_DSP_HEIGHT1(win->area[1].ysize - 1);
vop_writel(vop_dev, WIN2_DSP_INFO1 + off, val);
val = V_WIN2_DSP_XST1(win->area[1].dsp_stx) |
V_WIN2_DSP_YST1(win->area[1].dsp_sty);
val = V_WIN2_VIR_STRIDE2(win->area[2].y_vir_stride);
vop_msk_reg(vop_dev, WIN2_VIR2_3 + off, val);
- val = V_WIN2_DSP_WIDTH2(win->area[2].xsize) |
- V_WIN2_DSP_HEIGHT2(win->area[2].ysize);
+ val = V_WIN2_DSP_WIDTH2(win->area[2].xsize - 1) |
+ V_WIN2_DSP_HEIGHT2(win->area[2].ysize - 1);
vop_writel(vop_dev, WIN2_DSP_INFO2 + off, val);
val = V_WIN2_DSP_XST2(win->area[2].dsp_stx) |
V_WIN2_DSP_YST2(win->area[2].dsp_sty);
val = V_WIN2_VIR_STRIDE3(win->area[3].y_vir_stride);
vop_msk_reg(vop_dev, WIN2_VIR2_3 + off, val);
- val = V_WIN2_DSP_WIDTH3(win->area[3].xsize) |
- V_WIN2_DSP_HEIGHT3(win->area[3].ysize);
+ val = V_WIN2_DSP_WIDTH3(win->area[3].xsize - 1) |
+ V_WIN2_DSP_HEIGHT3(win->area[3].ysize - 1);
vop_writel(vop_dev, WIN2_DSP_INFO3 + off, val);
val = V_WIN2_DSP_XST3(win->area[3].dsp_stx) |
V_WIN2_DSP_YST3(win->area[3].dsp_sty);
val = V_WIN2_MST3_EN(0);
vop_msk_reg(vop_dev, WIN2_CTRL0 + off, val);
}
-
- if (win->alpha_en == 1) {
- vop_alpha_cfg(dev_drv, win_id);
- } else {
- val = V_WIN2_SRC_ALPHA_EN(0);
- vop_msk_reg(vop_dev, WIN2_SRC_ALPHA_CTRL + off, val);
- }
} else {
val = V_WIN2_EN(win->state) | V_WIN2_MST0_EN(0) |
V_WIN2_MST1_EN(0) | V_WIN2_MST2_EN(0) | V_WIN2_MST3_EN(0);
unsigned int hwc_size = 0;
u64 val;
+ if ((win->area[0].xsize == 32) && (win->area[0].ysize == 32)) {
+ hwc_size = 0;
+ } else if ((win->area[0].xsize == 64) && (win->area[0].ysize == 64)) {
+ hwc_size = 1;
+ } else if ((win->area[0].xsize == 96) && (win->area[0].ysize == 96)) {
+ hwc_size = 2;
+ } else if ((win->area[0].xsize == 128) &&
+ (win->area[0].ysize == 128)) {
+ hwc_size = 3;
+ } else {
+ dev_err(vop_dev->dev, "un supported hwc size[%dx%d]!\n",
+ win->area[0].xsize, win->area[0].ysize);
+ return -EINVAL;
+ }
+
if (win->state == 1) {
vop_axi_gather_cfg(vop_dev, win);
val = V_HWC_EN(1) | V_HWC_DATA_FMT(win->area[0].fmt_cfg) |
V_HWC_RB_SWAP(win->area[0].swap_rb);
vop_msk_reg(vop_dev, HWC_CTRL0, val);
- if ((win->area[0].xsize == 32) && (win->area[0].ysize == 32))
- hwc_size = 0;
- else if ((win->area[0].xsize == 64) &&
- (win->area[0].ysize == 64))
- hwc_size = 1;
- else if ((win->area[0].xsize == 96) &&
- (win->area[0].ysize == 96))
- hwc_size = 2;
- else if ((win->area[0].xsize == 128) &&
- (win->area[0].ysize == 128))
- hwc_size = 3;
- else
- dev_err(vop_dev->dev, "un supported hwc size[%dx%d]!\n",
- win->area[0].xsize, win->area[0].ysize);
-
val = V_HWC_SIZE(hwc_size);
vop_msk_reg(vop_dev, HWC_CTRL0, val);
val = V_HWC_DSP_XST(win->area[0].dsp_stx) |
V_HWC_DSP_YST(win->area[0].dsp_sty);
vop_msk_reg(vop_dev, HWC_DSP_ST, val);
-
- if (win->alpha_en == 1) {
- vop_alpha_cfg(dev_drv, win_id);
- } else {
- val = V_WIN2_SRC_ALPHA_EN(0);
- vop_msk_reg(vop_dev, HWC_SRC_ALPHA_CTRL, val);
- }
} else {
val = V_HWC_EN(win->state);
vop_msk_reg(vop_dev, HWC_CTRL0, val);
vop_msk_reg(vop_dev, LINE_FLAG, val);
}
vop_post_cfg(dev_drv);
+ if ((x_res <= VOP_INPUT_MAX_WIDTH / 2) && (vop_dev->id == 0))
+ vop_msk_reg(vop_dev, SYS_CTRL, V_POST_LB_MODE(1));
+ else
+ vop_msk_reg(vop_dev, SYS_CTRL, V_POST_LB_MODE(0));
return 0;
}
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
struct rk_screen *screen = dev_drv->cur_screen;
- u64 val;
+ u64 val = 0;
if (unlikely(!vop_dev->clk_on)) {
pr_info("%s,clk_on = %d\n", __func__, vop_dev->clk_on);
| V_PRE_DITHER_DOWN_EN(1) |
V_DITHER_DOWN_SEL(0) | V_DITHER_DOWN_MODE(0);
break;
+ case OUT_S888x:
+ face = OUT_S888x;
+ val = V_DITHER_DOWN_EN(0) | V_DITHER_UP_EN(1)
+ | V_PRE_DITHER_DOWN_EN(1) |
+ V_DITHER_DOWN_SEL(0) | V_DITHER_DOWN_MODE(0);
+ break;
+ case OUT_S888:
+ face = OUT_S888;
+ val = V_DITHER_DOWN_EN(0) | V_DITHER_UP_EN(1)
+ | V_PRE_DITHER_DOWN_EN(1) |
+ V_DITHER_DOWN_SEL(0) | V_DITHER_DOWN_MODE(0);
+ break;
case OUT_YUV_420:
face = OUT_YUV_420;
dclk_ddr = 1;
V_DITHER_DOWN_SEL(0) |
V_DITHER_DOWN_MODE(0);
break;
+ case OUT_YUV_422:
+ face = OUT_YUV_422;
+ val = V_DITHER_DOWN_EN(0) | V_DITHER_UP_EN(1) |
+ V_PRE_DITHER_DOWN_EN(1) |
+ V_DITHER_DOWN_SEL(0) |
+ V_DITHER_DOWN_MODE(0);
+ break;
+ case OUT_YUV_422_10BIT:
+ face = OUT_YUV_422;
+ val = V_DITHER_DOWN_EN(0) | V_DITHER_UP_EN(1) |
+ V_PRE_DITHER_DOWN_EN(0) |
+ V_DITHER_DOWN_SEL(0) |
+ V_DITHER_DOWN_MODE(0);
+ break;
case OUT_P101010:
face = OUT_P101010;
val = V_DITHER_DOWN_EN(0) | V_DITHER_UP_EN(1) |
vop_msk_reg(vop_dev, SYS_CTRL, val);
break;
case SCREEN_HDMI:
+ if ((VOP_CHIP(vop_dev) == VOP_RK3399) &&
+ ((screen->face == OUT_P888) ||
+ (screen->face == OUT_P101010))) {
+ if (vop_dev->id == 0)
+ face = OUT_P101010; /*RGB 10bit output*/
+ else
+ face = OUT_P888;
+ }
val = V_HDMI_OUT_EN(1) | V_SW_UV_OFFSET_EN(0);
vop_msk_reg(vop_dev, SYS_CTRL, val);
+ val = V_HDMI_HSYNC_POL(screen->pin_hsync) |
+ V_HDMI_VSYNC_POL(screen->pin_vsync) |
+ V_HDMI_DEN_POL(screen->pin_den) |
+ V_HDMI_DCLK_POL(screen->pin_dclk);
+ /*hsync vsync den dclk polo,dither */
+ vop_msk_reg(vop_dev, DSP_CTRL1, val);
break;
case SCREEN_RGB:
case SCREEN_LVDS:
val = V_RGB_OUT_EN(1);
vop_msk_reg(vop_dev, SYS_CTRL, val);
+ break;
case SCREEN_MIPI:
val = V_MIPI_OUT_EN(1);
vop_msk_reg(vop_dev, SYS_CTRL, val);
+ val = V_MIPI_HSYNC_POL(screen->pin_hsync) |
+ V_MIPI_VSYNC_POL(screen->pin_vsync) |
+ V_MIPI_DEN_POL(screen->pin_den) |
+ V_MIPI_DCLK_POL(screen->pin_dclk);
+ /*hsync vsync den dclk polo,dither */
+ vop_msk_reg(vop_dev, DSP_CTRL1, val);
+ break;
+ case SCREEN_DUAL_MIPI:
+ val = V_MIPI_OUT_EN(1) | V_MIPI_DUAL_CHANNEL_EN(1);
+ vop_msk_reg(vop_dev, SYS_CTRL, val);
+ val = V_MIPI_HSYNC_POL(screen->pin_hsync) |
+ V_MIPI_VSYNC_POL(screen->pin_vsync) |
+ V_MIPI_DEN_POL(screen->pin_den) |
+ V_MIPI_DCLK_POL(screen->pin_dclk);
+ /*hsync vsync den dclk polo,dither */
+ vop_msk_reg(vop_dev, DSP_CTRL1, val);
+ break;
case SCREEN_EDP:
+ if (VOP_CHIP(vop_dev) == VOP_RK3399) {
+ if (vop_dev->id == 0)
+ face = OUT_P101010;
+ else
+ face = OUT_P888;
+ }
val = V_EDP_OUT_EN(1);
vop_msk_reg(vop_dev, SYS_CTRL, val);
+ val = V_EDP_HSYNC_POL(screen->pin_hsync) |
+ V_EDP_VSYNC_POL(screen->pin_vsync) |
+ V_EDP_DEN_POL(screen->pin_den) |
+ V_EDP_DCLK_POL(screen->pin_dclk);
+ /*hsync vsync den dclk polo,dither */
+ vop_msk_reg(vop_dev, DSP_CTRL1, val);
+ break;
+ case SCREEN_DP:
+ dclk_ddr = 0;
+ if ((VOP_CHIP(vop_dev) == VOP_RK3399) &&
+ ((screen->face == OUT_P888) ||
+ (screen->face == OUT_P101010))) {
+ if (vop_dev->id == 0)
+ face = OUT_P101010;
+ else
+ face = OUT_P888;
+ }
+ val = V_DP_OUT_EN(1);
+ vop_msk_reg(vop_dev, SYS_CTRL, val);
+ val = V_DP_HSYNC_POL(screen->pin_hsync) |
+ V_DP_VSYNC_POL(screen->pin_vsync) |
+ V_DP_DEN_POL(screen->pin_den) |
+ V_DP_DCLK_POL(screen->pin_dclk);
+ /*hsync vsync den dclk polo,dither */
+ vop_msk_reg(vop_dev, DSP_CTRL1, val);
break;
default:
dev_err(vop_dev->dev, "un supported interface[%d]!\n",
screen->type);
break;
}
- val = V_HDMI_HSYNC_POL(screen->pin_hsync) |
- V_HDMI_VSYNC_POL(screen->pin_vsync) |
- V_HDMI_DEN_POL(screen->pin_den) |
- V_HDMI_DCLK_POL(screen->pin_dclk);
- /*hsync vsync den dclk polo,dither */
- vop_msk_reg(vop_dev, DSP_CTRL1, val);
if (screen->color_mode == COLOR_RGB)
dev_drv->overlay_mode = VOP_RGB_DOMAIN;
return 0;
}
+static int vop_early_suspend(struct rk_lcdc_driver *dev_drv);
+static int vop_early_resume(struct rk_lcdc_driver *dev_drv);
/*enable layer,open:1,enable;0 disable*/
static void vop_layer_enable(struct vop_device *vop_dev,
unsigned int win_id, bool open)
vop_dev->driver.win[win_id]);
vop_cfg_done(vop_dev);
}
- /* if no layer used,disable lcdc */
- if (!vop_dev->atv_layer_cnt) {
+ }
+ spin_unlock(&vop_dev->reg_lock);
+ /* if no layer used,disable lcdc */
+ if (vop_dev->prop == EXTEND) {
+ if (!vop_dev->atv_layer_cnt && !open) {
+ if (!wait_event_timeout(vop_dev->wait_dmc_queue,
+ !vop_dev->dmc_in_process, HZ / 5))
+ dev_warn(vop_dev->dev,
+ "Timeout waiting for dmc when vop disable\n");
+
+ vop_dev->vop_switch_status = 1;
+ vop_early_suspend(&vop_dev->driver);
dev_info(vop_dev->dev,
"no layer is used,go to standby!\n");
vop_dev->standby = 1;
+
+ vop_dev->vop_switch_status = 0;
+ wake_up(&vop_dev->wait_vop_switch_queue);
+ /*
+ * if clsoe enxtend vop need to enable dmc again.
+ */
+ if (vop_dev->devfreq) {
+ if (vop_dev->devfreq_event_dev)
+ devfreq_event_enable_edev(vop_dev->devfreq_event_dev);
+ devfreq_resume_device(vop_dev->devfreq);
+ }
+ } else if (open) {
+ vop_early_resume(&vop_dev->driver);
+ vop_dev->vop_switch_status = 0;
+ wake_up(&vop_dev->wait_vop_switch_queue);
+ /* if enable two vop, need to disable dmc */
+ if (vop_dev->devfreq) {
+ if (vop_dev->devfreq_event_dev)
+ devfreq_event_disable_edev(vop_dev->devfreq_event_dev);
+ devfreq_suspend_device(vop_dev->devfreq);
+ }
+ dev_info(vop_dev->dev, "wake up from standby!\n");
+ }
+ } else if (vop_dev->prop == PRMRY) {
+ if ((open) && (!vop_dev->atv_layer_cnt)) {
+ vop_dev->vop_switch_status = 0;
+ wake_up(&vop_dev->wait_vop_switch_queue);
}
}
- spin_unlock(&vop_dev->reg_lock);
}
static int vop_enable_irq(struct rk_lcdc_driver *dev_drv)
val = INTR_FS | INTR_LINE_FLAG0 | INTR_BUS_ERROR | INTR_LINE_FLAG1 |
INTR_WIN0_EMPTY | INTR_WIN1_EMPTY | INTR_HWC_EMPTY |
INTR_POST_BUF_EMPTY;
+ val |= val << 16;
- vop_mask_writel(vop_dev, INTR_EN0, INTR_MASK, val);
+ vop_msk_reg(vop_dev, INTR_EN0, val);
return 0;
}
+static int dmc_notify(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct vop_device *vop = container_of(nb, struct vop_device, dmc_nb);
+
+ if (event == DEVFREQ_PRECHANGE) {
+
+ /*
+ * check if vop in enable or disable process,
+ * if yes, wait until it finish, use 200ms as
+ * timeout.
+ */
+ if (!wait_event_timeout(vop->wait_vop_switch_queue,
+ !vop->vop_switch_status, HZ / 5))
+ dev_warn(vop->dev,
+ "Timeout waiting for vop swtich status\n");
+ vop->dmc_in_process = 1;
+ } else if (event == DEVFREQ_POSTCHANGE) {
+ vop->dmc_in_process = 0;
+ wake_up(&vop->wait_dmc_queue);
+ }
+
+ return NOTIFY_OK;
+}
+
static int vop_open(struct rk_lcdc_driver *dev_drv, int win_id,
bool open)
{
/* enable clk,when first layer open */
if ((open) && (!vop_dev->atv_layer_cnt)) {
/* rockchip_set_system_status(sys_status); */
+ if (!wait_event_timeout(vop_dev->wait_dmc_queue,
+ !vop_dev->dmc_in_process, HZ / 5))
+ dev_warn(vop_dev->dev,
+ "Timeout waiting for dmc when vop enable\n");
+ vop_dev->vop_switch_status = 1;
vop_pre_init(dev_drv);
vop_clk_enable(vop_dev);
vop_enable_irq(dev_drv);
static int vop_cal_scl_fac(struct rk_lcdc_win *win, struct rk_screen *screen)
{
- u16 srcW;
- u16 srcH;
- u16 dstW;
- u16 dstH;
- u16 yrgb_srcW;
- u16 yrgb_srcH;
- u16 yrgb_dstW;
- u16 yrgb_dstH;
- u32 yrgb_vscalednmult;
- u32 yrgb_xscl_factor;
- u32 yrgb_yscl_factor;
+ u16 srcW = 0;
+ u16 srcH = 0;
+ u16 dstW = 0;
+ u16 dstH = 0;
+ u16 yrgb_srcW = 0;
+ u16 yrgb_srcH = 0;
+ u16 yrgb_dstW = 0;
+ u16 yrgb_dstH = 0;
+ u32 yrgb_vscalednmult = 0;
+ u32 yrgb_xscl_factor = 0;
+ u32 yrgb_yscl_factor = 0;
u8 yrgb_vsd_bil_gt2 = 0;
u8 yrgb_vsd_bil_gt4 = 0;
- u16 cbcr_srcW;
- u16 cbcr_srcH;
- u16 cbcr_dstW;
- u16 cbcr_dstH;
- u32 cbcr_vscalednmult;
- u32 cbcr_xscl_factor;
- u32 cbcr_yscl_factor;
+ u16 cbcr_srcW = 0;
+ u16 cbcr_srcH = 0;
+ u16 cbcr_dstW = 0;
+ u16 cbcr_dstH = 0;
+ u32 cbcr_vscalednmult = 0;
+ u32 cbcr_xscl_factor = 0;
+ u32 cbcr_yscl_factor = 0;
u8 cbcr_vsd_bil_gt2 = 0;
u8 cbcr_vsd_bil_gt4 = 0;
u8 yuv_fmt = 0;
static int win_0_1_set_par(struct vop_device *vop_dev,
struct rk_screen *screen, struct rk_lcdc_win *win)
{
- u32 xact, yact, xvir, yvir, xpos, ypos;
- u8 fmt_cfg = 0, swap_rb, swap_uv = 0;
+ u32 xact = 0, yact = 0, xvir = 0, yvir = 0, xpos = 0, ypos = 0;
+ u8 fmt_cfg = 0, swap_rb = 0, swap_uv = 0;
char fmt[9] = "NULL";
xpos = dsp_x_pos(win->xmirror, screen, &win->area[0]);
struct rk_screen *screen, struct rk_lcdc_win *win)
{
int i;
- u8 fmt_cfg, swap_rb;
+ u8 fmt_cfg = 0, swap_rb = 0;
char fmt[9] = "NULL";
if (VOP_CHIP(vop_dev) == VOP_RK322X) {
fmt_cfg = 2;
swap_rb = 0;
win->fmt_10 = 0;
- win->area[0].fbdc_fmt_cfg = 0x05;
+ win->area[0].fbdc_fmt_cfg = AFBDC_FMT_RGB565;
break;
case FBDC_ARGB_888:
+ fmt_cfg = 0;
+ swap_rb = 1;
+ win->fmt_10 = 0;
+ win->area[0].fbdc_fmt_cfg = AFBDC_FMT_U8U8U8U8;
+ break;
+ case FBDC_ABGR_888:
fmt_cfg = 0;
swap_rb = 0;
win->fmt_10 = 0;
- win->area[0].fbdc_fmt_cfg = 0x0c;
+ win->area[0].fbdc_fmt_cfg = AFBDC_FMT_U8U8U8U8;
break;
case FBDC_RGBX_888:
fmt_cfg = 0;
swap_rb = 0;
win->fmt_10 = 0;
- win->area[0].fbdc_fmt_cfg = 0x3a;
+ win->area[0].fbdc_fmt_cfg = AFBDC_FMT_U8U8U8U8;
break;
case ARGB888:
fmt_cfg = 0;
static int hwc_set_par(struct vop_device *vop_dev,
struct rk_screen *screen, struct rk_lcdc_win *win)
{
- u32 xact, yact, xvir, yvir, xpos, ypos;
- u8 fmt_cfg = 0, swap_rb;
+ u32 xact = 0, yact = 0, xvir = 0, yvir = 0, xpos = 0, ypos = 0;
+ u8 fmt_cfg = 0, swap_rb = 0;
char fmt[9] = "NULL";
xpos = win->area[0].xpos + screen->mode.left_margin +
return 0;
}
wb_data = &dev_drv->wb_data;
+ if ((wb_data->xsize == 0) || (wb_data->ysize == 0))
+ return 0;
xsize = wb_data->xsize;
ysize = wb_data->ysize;
switch (wb_data->data_format) {
case ARGB888:
+ case ABGR888:
+ case XRGB888:
+ case XBGR888:
fmt_cfg = 0;
break;
case RGB888:
+ case BGR888:
fmt_cfg = 1;
break;
case RGB565:
+ case BGR565:
fmt_cfg = 2;
break;
case YUV420:
vop_mask_writel(vop_dev, INTR_CLEAR0, INTR_MASK, INTR_MASK);
vop_msk_reg(vop_dev, DSP_CTRL0, V_DSP_OUT_ZERO(1));
vop_msk_reg(vop_dev, SYS_CTRL, V_VOP_STANDBY_EN(1));
+ if (VOP_CHIP(vop_dev) == VOP_RK3399) {
+ vop_msk_reg(vop_dev, WIN0_CTRL0, V_WIN0_EN(0));
+ vop_msk_reg(vop_dev, WIN1_CTRL0, V_WIN1_EN(0));
+ vop_msk_reg(vop_dev, WIN2_CTRL0, V_WIN2_EN(0));
+ vop_msk_reg(vop_dev, WIN3_CTRL0, V_WIN3_EN(0));
+ vop_msk_reg(vop_dev, AFBCD0_CTRL, V_VOP_FBDC_EN(0));
+ }
vop_cfg_done(vop_dev);
if (dev_drv->iommu_enabled && dev_drv->mmu_dev) {
spin_lock(&vop_dev->reg_lock);
vop_msk_reg(vop_dev, DSP_CTRL0, V_DSP_OUT_ZERO(0));
- vop_msk_reg(vop_dev, SYS_CTRL, V_VOP_STANDBY_EN(0));
vop_msk_reg(vop_dev, DSP_CTRL0, V_DSP_BLANK_EN(0));
vop_cfg_done(vop_dev);
spin_unlock(&vop_dev->reg_lock);
rockchip_iovmm_activate(dev_drv->dev);
}
+ spin_lock(&vop_dev->reg_lock);
+ vop_msk_reg(vop_dev, SYS_CTRL, V_VOP_STANDBY_EN(0));
+ vop_cfg_done(vop_dev);
+ spin_unlock(&vop_dev->reg_lock);
+
dev_drv->suspend_flag = 0;
if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
struct rk_lcdc_win *win = NULL;
- int i, ovl;
+ int i, ovl = 0;
u64 val;
int z_order_num = 0;
- int layer0_sel, layer1_sel, layer2_sel, layer3_sel;
+ int layer0_sel = 0, layer1_sel = 1, layer2_sel = 2, layer3_sel = 3;
if (swap == 0) {
for (i = 0; i < dev_drv->lcdc_win_num; i++) {
spin_unlock(&vop_dev->reg_lock);
size += snprintf(dsp_buf, 80,
"z-order:\n win[%d]\n win[%d]\n win[%d]\n win[%d]\n",
- layer1_sel, layer0_sel, layer2_sel, layer3_sel);
+ layer3_sel, layer2_sel, layer1_sel, layer0_sel);
strcat(buf, dsp_buf);
memset(dsp_buf, 0, sizeof(dsp_buf));
/* win0 */
static int vop_fps_mgr(struct rk_lcdc_driver *dev_drv, int fps, bool set)
{
struct vop_device *vop_dev =
- container_of(dev_drv, struct vop_device, driver);
- struct rk_screen *screen = dev_drv->cur_screen;
- u64 ft = 0;
- u32 dotclk;
+ container_of(dev_drv, struct vop_device, driver);
+ struct rk_fb_vsync *vsync = &dev_drv->vsync_info;
+ int step_fps, old_fps;
+ u32 h_total, v_total;
+ unsigned long dclk;
+ u64 val;
int ret;
- u32 pixclock;
- u32 x_total, y_total;
- if (set) {
- if (fps == 0) {
- dev_info(dev_drv->dev, "unsupport set fps=0\n");
- return 0;
+ dclk = clk_get_rate(vop_dev->dclk);
+
+ spin_lock(&vop_dev->reg_lock);
+
+ if (!vop_dev->clk_on) {
+ spin_unlock(&vop_dev->reg_lock);
+ return 0;
+ }
+
+ val = vop_readl(vop_dev, DSP_HTOTAL_HS_END);
+ h_total = (val & MASK(DSP_HTOTAL)) >> 16;
+
+ val = vop_readl(vop_dev, DSP_VTOTAL_VS_END);
+ v_total = (val & MASK(DSP_VTOTAL)) >> 16;
+
+ spin_unlock(&vop_dev->reg_lock);
+
+ old_fps = div_u64(dclk, v_total * h_total);
+
+ if (!set)
+ return old_fps;
+
+ /*
+ * Direct change fps to dest fps would may screen flash,
+ * Every frame change one step fps is safe, screen flash
+ * disappear.
+ */
+ step_fps = old_fps;
+ while (step_fps != fps) {
+ ktime_t timestamp = vsync->timestamp;
+
+ if (step_fps > fps)
+ step_fps--;
+ else
+ step_fps++;
+ spin_lock(&vop_dev->reg_lock);
+ if (!vop_dev->clk_on) {
+ spin_unlock(&vop_dev->reg_lock);
+ break;
}
- 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(vop_dev->dclk, dotclk);
- }
-
- pixclock = div_u64(1000000000000llu, clk_get_rate(vop_dev->dclk));
- vop_dev->pixclock = pixclock;
- dev_drv->pixclock = vop_dev->pixclock;
- fps = rk_fb_calc_fps(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(vop_dev->dclk), fps);
+ h_total = div_u64(dclk, step_fps * v_total);
+ val = V_DSP_HTOTAL(h_total);
+ vop_msk_reg(vop_dev, DSP_HTOTAL_HS_END, val);
+ vop_cfg_done(vop_dev);
+ spin_unlock(&vop_dev->reg_lock);
+
+ ret = wait_event_interruptible_timeout(vsync->wait,
+ !ktime_equal(timestamp, vsync->timestamp) &&
+ (vsync->active > 0 || vsync->irq_stop),
+ msecs_to_jiffies(50));
+ }
+
+ dev_info(dev_drv->dev, "%s:dclk:%lu, htotal=%d, vtatol=%d, fps:%d\n",
+ __func__, dclk, h_total, v_total, fps);
return fps;
}
vop_msk_reg(vop_dev, SYS_CTRL, V_VOP_STANDBY_EN(vop_dev->standby));
for (i = 0; i < dev_drv->lcdc_win_num; i++) {
win = dev_drv->win[i];
+ vop_alpha_cfg(dev_drv, i);
fbdc_en |= win->area[0].fbdc_en;
+ vop_dev->atv_layer_cnt &= ~(1 << win->id);
+ vop_dev->atv_layer_cnt |= (win->state << win->id);
if ((win->state == 0) && (win->last_state == 1)) {
switch (win->id) {
case 0:
if (enable)
enable_irq(vop_dev->irq);
else
- disable_irq(vop_dev->irq);
+ disable_irq_nosync(vop_dev->irq);
return 0;
}
{
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
- u32 val;
+ u32 val = 0;
spin_lock(&vop_dev->reg_lock);
if (vop_dev->clk_on) {
struct rk_screen *screen = dev_drv->cur_screen;
u32 total_pixel, calc_pixel, stage_up, stage_down;
u32 pixel_num, global_dn;
+ u64 val = 0;
+ ktime_t timestamp;
+ int ret = 0;
if (!vop_dev->cabc_lut_addr_base) {
pr_err("vop chip[%d] not supoort cabc\n", VOP_CHIP(vop_dev));
return 0;
}
- dev_drv->cabc_mode = mode;
- if (!dev_drv->cabc_mode) {
- spin_lock(&vop_dev->reg_lock);
- if (vop_dev->clk_on) {
- vop_msk_reg(vop_dev, CABC_CTRL0,
- V_CABC_EN(0) | V_CABC_HANDLE_EN(0));
- vop_cfg_done(vop_dev);
+ if (!mode) {
+ if (VOP_CHIP(vop_dev) == VOP_RK3399) {
+ calc = 0;
+ up = 256;
+ down = 255;
+ global = 0;
+ } else {
+ spin_lock(&vop_dev->reg_lock);
+ if (vop_dev->clk_on) {
+ vop_msk_reg(vop_dev, CABC_CTRL0,
+ V_CABC_EN(0) | V_CABC_HANDLE_EN(0));
+ vop_cfg_done(vop_dev);
+ }
+ pr_info("mode = 0, close cabc\n");
+ spin_unlock(&vop_dev->reg_lock);
+ return 0;
}
- pr_info("mode = 0, close cabc\n");
- spin_unlock(&vop_dev->reg_lock);
- return 0;
}
total_pixel = screen->mode.xres * screen->mode.yres;
spin_lock(&vop_dev->reg_lock);
if (vop_dev->clk_on) {
- u64 val = 0;
-
- val = V_CABC_EN(1) | V_CABC_HANDLE_EN(1) |
- V_PWM_CONFIG_MODE(STAGE_BY_STAGE) |
+ val = V_PWM_CONFIG_MODE(STAGE_BY_STAGE) |
V_CABC_CALC_PIXEL_NUM(calc_pixel);
vop_msk_reg(vop_dev, CABC_CTRL0, val);
}
spin_unlock(&vop_dev->reg_lock);
+ timestamp = dev_drv->vsync_info.timestamp;
+ ret = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
+ !ktime_equal(timestamp, dev_drv->vsync_info.timestamp),
+ msecs_to_jiffies(50));
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
+ pr_err("%s wait vsync time out\n", __func__);
+
+ spin_lock(&vop_dev->reg_lock);
+ if (vop_dev->clk_on) {
+ val = V_CABC_EN(1) | V_CABC_HANDLE_EN(1);
+ vop_msk_reg(vop_dev, CABC_CTRL0, val);
+ vop_cfg_done(vop_dev);
+ }
+ spin_unlock(&vop_dev->reg_lock);
+
return 0;
}
{
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
- u64 val;
+ u64 val = 0;
spin_lock(&vop_dev->reg_lock);
if (vop_dev->clk_on) {
{
struct vop_device *vop_dev =
container_of(dev_drv, struct vop_device, driver);
- u64 val;
+ u64 val = 0;
spin_lock(&vop_dev->reg_lock);
if (vop_dev->clk_on) {
return 0;
}
+static int vop_extern_func(struct rk_lcdc_driver *dev_drv, int cmd)
+{
+ struct vop_device *vop_dev =
+ container_of(dev_drv, struct vop_device, driver);
+
+ if (unlikely(!vop_dev->clk_on)) {
+ pr_info("%s,clk_on = %d\n", __func__, vop_dev->clk_on);
+ return 0;
+ }
+
+ switch (cmd) {
+ case UPDATE_CABC_PWM:
+ vop_cfg_done(vop_dev);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static struct rk_lcdc_drv_ops lcdc_drv_ops = {
.open = vop_open,
.win_direct_en = vop_win_direct_en,
.backlight_close = vop_backlight_close,
.mmu_en = vop_mmu_en,
.set_overscan = vop_set_overscan,
+ .extern_func = vop_extern_func,
};
static irqreturn_t vop_isr(int irq, void *dev_id)
if (intr_status & INTR_FS) {
timestamp = ktime_get();
- if (vop_dev->wb_on) {
+ if (vop_dev->driver.wb_data.state) {
u32 wb_status;
spin_lock_irqsave(&vop_dev->irq_lock, flags);
wb_status = vop_read_bit(vop_dev, WB_CTRL0, V_WB_EN(0));
+
if (wb_status)
- vop_set_bit(vop_dev, WB_CTRL0, V_WB_EN(0));
+ vop_clr_bit(vop_dev, WB_CTRL0, V_WB_EN(0));
vop_cfg_done(vop_dev);
vop_dev->driver.wb_data.state = 0;
else
dev_drv->rotate_mode = val;
+ if (of_property_read_u32(np, "rockchip,cabc_mode", &val))
+ dev_drv->cabc_mode = 0; /* default set close cabc */
+ else
+ dev_drv->cabc_mode = val;
+
if (of_property_read_u32(np, "rockchip,pwr18", &val))
/*default set it as 3.xv power supply */
vop_dev->pwr18 = false;
dev_drv->iommu_enabled = 0;
else
dev_drv->iommu_enabled = val;
+
+ if (of_property_read_u32(np, "rockchip,dsp_mode", &val))
+ dev_drv->dsp_mode = DEFAULT_MODE;
+ else
+ dev_drv->dsp_mode = val;
+
+ return 0;
+}
+
+static struct platform_device *rk322x_pdev;
+
+int vop_register_dmc(void)
+{
+ struct platform_device *pdev = rk322x_pdev;
+ struct vop_device *vop_dev;
+ struct device *dev = &pdev->dev;
+ struct devfreq *devfreq;
+ struct devfreq_event_dev *event_dev;
+
+ if (!pdev)
+ return -ENODEV;
+
+ vop_dev = platform_get_drvdata(pdev);;
+ if (!vop_dev)
+ return -ENODEV;
+
+ dev = &pdev->dev;
+ devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
+ if (IS_ERR(devfreq)) {
+ dev_err(vop_dev->dev, "fail to get devfreq for dmc\n");
+ return -ENODEV;
+ }
+
+ vop_dev->devfreq = devfreq;
+ vop_dev->dmc_nb.notifier_call = dmc_notify;
+ devfreq_register_notifier(vop_dev->devfreq, &vop_dev->dmc_nb,
+ DEVFREQ_TRANSITION_NOTIFIER);
+
+ event_dev = devfreq_event_get_edev_by_phandle(vop_dev->devfreq->dev.parent,
+ 0);
+ if (IS_ERR(event_dev)) {
+ dev_err(vop_dev->dev, "fail to get edev for dmc\n");
+ return -ENODEV;
+ }
+
+ vop_dev->devfreq_event_dev = event_dev;
+ return 0;
+}
+
+static int vop_wms_refresh(struct rk_lcdc_driver *dev_drv)
+{
+ struct vop_device *vop_dev =
+ container_of(dev_drv, struct vop_device, driver);
+
+ if (unlikely(!vop_dev->clk_on)) {
+ dev_info_ratelimited(vop_dev->dev, "%s,clk_on = %d\n",
+ __func__, vop_dev->clk_on);
+ return 0;
+ }
+ vop_msk_reg_nobak(vop_dev, SYS_CTRL, V_EDPI_WMS_FS(1));
+ vop_msk_reg(vop_dev, SYS_CTRL, V_EDPI_WMS_MODE(0));
+ vop_msk_reg(vop_dev, SYS_CTRL, V_EDPI_WMS_MODE(1));
+
+ if (dev_drv->trsm_ops && dev_drv->trsm_ops->refresh)
+ dev_drv->trsm_ops->refresh(0, 0, dev_drv->cur_screen->mode.xres,
+ dev_drv->cur_screen->mode.yres);
+
return 0;
}
+static irqreturn_t te_irq_handle(int irq, void *dev_id)
+{
+ struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)dev_id;
+
+ vop_wms_refresh(dev_drv);
+
+ return IRQ_HANDLED;
+}
+
static int vop_probe(struct platform_device *pdev)
{
struct vop_device *vop_dev = NULL;
struct device_node *np = pdev->dev.of_node;
int prop;
int ret = 0;
+ int te_pin;
/* if the primary lcdc has not registered ,the extend
* lcdc register later
platform_set_drvdata(pdev, vop_dev);
vop_dev->dev = dev;
vop_parse_dt(vop_dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ /* enable power domain */
+ pm_runtime_enable(dev);
+#endif
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vop_dev->reg_phy_base = res->start;
vop_dev->len = resource_size(res);
- vop_dev->regs = devm_ioremap_resource(dev, res);
+ vop_dev->regs = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
if (IS_ERR(vop_dev->regs))
return PTR_ERR(vop_dev->regs);
vop_dev->irq, ret);
return ret;
}
- if (dev_drv->iommu_enabled)
- strcpy(dev_drv->mmu_dts_name, VOP_IOMMU_COMPATIBLE_NAME);
+ if (dev_drv->iommu_enabled) {
+ if (VOP_CHIP(vop_dev) == VOP_RK322X) {
+ strcpy(dev_drv->mmu_dts_name,
+ VOP_IOMMU_COMPATIBLE_NAME);
+ } else {
+ if (vop_dev->id == 0)
+ strcpy(dev_drv->mmu_dts_name,
+ VOPB_IOMMU_COMPATIBLE_NAME);
+ else
+ strcpy(dev_drv->mmu_dts_name,
+ VOPL_IOMMU_COMPATIBLE_NAME);
+ }
+ }
+ if (VOP_CHIP(vop_dev) == VOP_RK3399)
+ dev_drv->property.feature |= SUPPORT_WRITE_BACK | SUPPORT_AFBDC;
+ dev_drv->property.feature |= SUPPORT_VOP_IDENTIFY |
+ SUPPORT_YUV420_OUTPUT;
+ dev_drv->property.max_output_x = 4096;
+ dev_drv->property.max_output_y = 2160;
+
+ init_waitqueue_head(&vop_dev->wait_vop_switch_queue);
+ vop_dev->vop_switch_status = 0;
+ init_waitqueue_head(&vop_dev->wait_dmc_queue);
+ vop_dev->dmc_in_process = 0;
+
ret = rk_fb_register(dev_drv, vop_dev->data->win, vop_dev->id);
if (ret < 0) {
dev_err(dev, "register fb for lcdc%d failed!\n", vop_dev->id);
return ret;
}
+
+ if ((VOP_CHIP(vop_dev) == VOP_RK3399) && (vop_dev->id == 1)) {
+ dev_drv->win[1]->property.feature &= ~SUPPORT_HW_EXIST;
+ dev_drv->win[3]->property.feature &= ~SUPPORT_HW_EXIST;
+ }
+
vop_dev->screen = dev_drv->screen0;
dev_info(dev, "lcdc%d probe ok, iommu %s\n",
vop_dev->id, dev_drv->iommu_enabled ? "enabled" : "disabled");
+ rk322x_pdev = pdev;
+
+ if (dev_drv->cur_screen->refresh_mode == SCREEN_CMD_MODE) {
+ te_pin = of_get_named_gpio_flags(np, "te-gpio", 0, NULL);
+ if (IS_ERR_VALUE(te_pin)) {
+ dev_err(dev, "define te pin for cmd mode!\n");
+ return 0;
+ }
+ ret = devm_gpio_request(dev, te_pin, "vop-te-gpio");
+ if (ret) {
+ dev_err(dev, "request gpio %d failed\n", te_pin);
+ return 0;
+ }
+ gpio_direction_input(te_pin);
+ dev_drv->te_irq = gpio_to_irq(te_pin);
+ ret = devm_request_threaded_irq(dev,
+ dev_drv->te_irq,
+ NULL, te_irq_handle,
+ IRQ_TYPE_EDGE_FALLING | IRQF_ONESHOT,
+ "te_irq", dev_drv);
+ if (ret < 0)
+ dev_err(dev, "request te irq failed, ret: %d\n", ret);
+ }
return 0;
}
vop_deint(vop_dev);
vop_clk_disable(vop_dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+ pm_runtime_disable(vop_dev->dev);
+#endif
rk_disp_pwr_disable(dev_drv);
}