[U-Boot] [PATCH v2 17/37] rockchip: video: Add a video-output driver

Simon Glass sjg at chromium.org
Fri Jan 22 03:45:05 CET 2016


Some rockchip SoCs include video output (VOP). Add a driver to support this.
It can output via a display driver (UCLASS_DISPLAY) and currently HDMI and
eDP are supported.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v2: None

 arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 349 ++++++++++++++++++++++++
 drivers/video/rockchip/Makefile                 |   2 +-
 drivers/video/rockchip/rk_vop.c                 | 346 +++++++++++++++++++++++
 3 files changed, 696 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/include/asm/arch-rockchip/vop_rk3288.h
 create mode 100644 drivers/video/rockchip/rk_vop.c

diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h
new file mode 100644
index 0000000..0104ba3
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Copyright 2014 Rockchip Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_VOP_RK3288_H
+#define _ASM_ARCH_VOP_RK3288_H
+
+struct rk3288_vop {
+	u32 reg_cfg_done;
+	u32 version_info;
+	u32 sys_ctrl;
+	u32 sys_ctrl1;
+	u32 dsp_ctrl0;
+	u32 dsp_ctrl1;
+	u32 dsp_bg;
+	u32 mcu_ctrl;
+	u32 intr_ctrl0;
+	u32 intr_ctrl1;
+	u32 intr_reserved0;
+	u32 intr_reserved1;
+
+	u32 win0_ctrl0;
+	u32 win0_ctrl1;
+	u32 win0_color_key;
+	u32 win0_vir;
+	u32 win0_yrgb_mst;
+	u32 win0_cbr_mst;
+	u32 win0_act_info;
+	u32 win0_dsp_info;
+	u32 win0_dsp_st;
+	u32 win0_scl_factor_yrgb;
+	u32 win0_scl_factor_cbr;
+	u32 win0_scl_offset;
+	u32 win0_src_alpha_ctrl;
+	u32 win0_dst_alpha_ctrl;
+	u32 win0_fading_ctrl;
+	u32 win0_reserved0;
+
+	u32 win1_ctrl0;
+	u32 win1_ctrl1;
+	u32 win1_color_key;
+	u32 win1_vir;
+	u32 win1_yrgb_mst;
+	u32 win1_cbr_mst;
+	u32 win1_act_info;
+	u32 win1_dsp_info;
+	u32 win1_dsp_st;
+	u32 win1_scl_factor_yrgb;
+	u32 win1_scl_factor_cbr;
+	u32 win1_scl_offset;
+	u32 win1_src_alpha_ctrl;
+	u32 win1_dst_alpha_ctrl;
+	u32 win1_fading_ctrl;
+	u32 win1_reservd0;
+	u32 reserved2[48];
+	u32 post_dsp_hact_info;
+	u32 post_dsp_vact_info;
+	u32 post_scl_factor_yrgb;
+	u32 post_reserved;
+	u32 post_scl_ctrl;
+	u32 post_dsp_vact_info_f1;
+	u32 dsp_htotal_hs_end;
+	u32 dsp_hact_st_end;
+	u32 dsp_vtotal_vs_end;
+	u32 dsp_vact_st_end;
+	u32 dsp_vs_st_end_f1;
+	u32 dsp_vact_st_end_f1;
+};
+check_member(rk3288_vop, dsp_vact_st_end_f1, 0x19c);
+
+enum rockchip_fb_data_format_t {
+	ARGB8888 = 0,
+	RGB888 = 1,
+	RGB565 = 2,
+};
+
+enum {
+	LB_YUV_3840X5 = 0x0,
+	LB_YUV_2560X8 = 0x1,
+	LB_RGB_3840X2 = 0x2,
+	LB_RGB_2560X4 = 0x3,
+	LB_RGB_1920X5 = 0x4,
+	LB_RGB_1280X8 = 0x5
+};
+
+enum vop_modes {
+	VOP_MODE_EDP = 0,
+	VOP_MODE_HDMI,
+	VOP_MODE_NONE,
+	VOP_MODE_AUTO_DETECT,
+	VOP_MODE_UNKNOWN,
+};
+
+/* VOP_VERSION_INFO */
+#define M_FPGA_VERSION (0xffff << 16)
+#define M_RTL_VERSION  (0xffff)
+
+/* VOP_SYS_CTRL */
+#define M_AUTO_GATING_EN (1 << 23)
+#define M_STANDBY_EN     (1 << 22)
+#define M_DMA_STOP       (1 << 21)
+#define M_MMU_EN         (1 << 20)
+#define M_DAM_BURST_LENGTH (0x3 << 18)
+#define M_MIPI_OUT_EN	   (1 << 15)
+#define M_EDP_OUT_EN       (1 << 14)
+#define M_HDMI_OUT_EN      (1 << 13)
+#define M_RGB_OUT_EN       (1 << 12)
+#define M_ALL_OUT_EN		\
+		(M_MIPI_OUT_EN | M_EDP_OUT_EN | M_HDMI_OUT_EN | M_RGB_OUT_EN)
+#define M_EDPI_WMS_FS      (1 << 10)
+#define M_EDPI_WMS_MODE    (1 << 9)
+#define M_EDPI_HALT_EN     (1 << 8)
+#define M_DOUB_CH_OVERLAP_NUM (0xf << 4)
+#define M_DOUB_CHANNEL_EN     (1 << 3)
+#define M_DIRECT_PATH_LAYER_SEL (0x3 << 1)
+#define M_DIRECT_PATH_EN       (1)
+
+#define V_AUTO_GATING_EN(x) (((x) & 1) << 23)
+#define V_STANDBY_EN(x)     (((x) & 1) << 22)
+#define V_DMA_STOP(x)       (((x) & 1) << 21)
+#define V_MMU_EN(x)         (((x) & 1) << 20)
+#define V_DMA_BURST_LENGTH(x) (((x) & 3) << 18)
+#define V_MIPI_OUT_EN(x)      (((x) & 1) << 15)
+#define V_EDP_OUT_EN(x)       (((x) & 1) << 14)
+#define V_HDMI_OUT_EN(x)      (((x) & 1) << 13)
+#define V_RGB_OUT_EN(x)       (((x) & 1) << 12)
+#define V_EDPI_WMS_FS(x)      (((x) & 1) << 10)
+#define V_EDPI_WMS_MODE(x)    (((x) & 1) << 9)
+#define V_EDPI_HALT_EN(x)     (((x)&1)<<8)
+#define V_DOUB_CH_OVERLAP_NUM(x) (((x) & 0xf) << 4)
+#define V_DOUB_CHANNEL_EN(x)     (((x) & 1) << 3)
+#define V_DIRECT_PATH_LAYER_SEL(x) (((x) & 3) << 1)
+#define V_DIRECT_PATH_EN(x)       ((x) & 1)
+
+/* VOP_SYS_CTRL1 */
+#define M_AXI_OUTSTANDING_MAX_NUM (0x1f << 13)
+#define M_AXI_MAX_OUTSTANDING_EN  (1 << 12)
+#define M_NOC_WIN_QOS             (3 << 10)
+#define M_NOC_QOS_EN              (1 << 9)
+#define M_NOC_HURRY_THRESHOLD     (0x3f << 3)
+#define M_NOC_HURRY_VALUE         (0x3 << 1)
+#define M_NOC_HURRY_EN            (1)
+
+#define V_AXI_OUTSTANDING_MAX_NUM(x) (((x) & 0x1f) << 13)
+#define V_AXI_MAX_OUTSTANDING_EN(x)  (((x) & 1) << 12)
+#define V_NOC_WIN_QOS(x)             (((x) & 3) << 10)
+#define V_NOC_QOS_EN(x)              (((x) & 1) << 9)
+#define V_NOC_HURRY_THRESHOLD(x)     (((x) & 0x3f) << 3)
+#define V_NOC_HURRY_VALUE(x)         (((x) & 3) << 1)
+#define V_NOC_HURRY_EN(x)            ((x) & 1)
+
+/* VOP_DSP_CTRL0 */
+#define M_DSP_Y_MIR_EN              (1 << 23)
+#define M_DSP_X_MIR_EN              (1 << 22)
+#define M_DSP_YUV_CLIP              (1 << 21)
+#define M_DSP_CCIR656_AVG           (1 << 20)
+#define M_DSP_BLACK_EN              (1 << 19)
+#define M_DSP_BLANK_EN              (1 << 18)
+#define M_DSP_OUT_ZERO              (1 << 17)
+#define M_DSP_DUMMY_SWAP            (1 << 16)
+#define M_DSP_DELTA_SWAP            (1 << 15)
+#define M_DSP_RG_SWAP               (1 << 14)
+#define M_DSP_RB_SWAP               (1 << 13)
+#define M_DSP_BG_SWAP               (1 << 12)
+#define M_DSP_FIELD_POL             (1 << 11)
+#define M_DSP_INTERLACE             (1 << 10)
+#define M_DSP_DDR_PHASE             (1 << 9)
+#define M_DSP_DCLK_DDR              (1 << 8)
+#define M_DSP_DCLK_POL              (1 << 7)
+#define M_DSP_DEN_POL               (1 << 6)
+#define M_DSP_VSYNC_POL             (1 << 5)
+#define M_DSP_HSYNC_POL             (1 << 4)
+#define M_DSP_OUT_MODE              (0xf)
+
+#define V_DSP_Y_MIR_EN(x)              (((x) & 1) << 23)
+#define V_DSP_X_MIR_EN(x)              (((x) & 1) << 22)
+#define V_DSP_YUV_CLIP(x)              (((x) & 1) << 21)
+#define V_DSP_CCIR656_AVG(x)           (((x) & 1) << 20)
+#define V_DSP_BLACK_EN(x)              (((x) & 1) << 19)
+#define V_DSP_BLANK_EN(x)              (((x) & 1) << 18)
+#define V_DSP_OUT_ZERO(x)              (((x) & 1) << 17)
+#define V_DSP_DUMMY_SWAP(x)            (((x) & 1) << 16)
+#define V_DSP_DELTA_SWAP(x)            (((x) & 1) << 15)
+#define V_DSP_RG_SWAP(x)               (((x) & 1) << 14)
+#define V_DSP_RB_SWAP(x)               (((x) & 1) << 13)
+#define V_DSP_BG_SWAP(x)               (((x) & 1) << 12)
+#define V_DSP_FIELD_POL(x)             (((x) & 1) << 11)
+#define V_DSP_INTERLACE(x)             (((x) & 1) << 10)
+#define V_DSP_DDR_PHASE(x)             (((x) & 1) << 9)
+#define V_DSP_DCLK_DDR(x)              (((x) & 1) << 8)
+#define V_DSP_DCLK_POL(x)              (((x) & 1) << 7)
+#define V_DSP_DEN_POL(x)               (((x) & 1) << 6)
+#define V_DSP_VSYNC_POL(x)             (((x) & 1) << 5)
+#define V_DSP_HSYNC_POL(x)             (((x) & 1) << 4)
+#define V_DSP_OUT_MODE(x)              ((x) & 0xf)
+
+/* VOP_DSP_CTRL1 */
+#define M_DSP_LAYER3_SEL               (3 << 14)
+#define M_DSP_LAYER2_SEL               (3 << 12)
+#define M_DSP_LAYER1_SEL               (3 << 10)
+#define M_DSP_LAYER0_SEL               (3 << 8)
+#define M_DITHER_UP_EN                 (1 << 6)
+#define M_DITHER_DOWN_SEL              (1 << 4)
+#define M_DITHER_DOWN_MODE             (1 << 3)
+#define M_DITHER_DOWN_EN               (1 << 2)
+#define M_PRE_DITHER_DOWN_EN           (1 << 1)
+#define M_DSP_LUT_EN                   (1)
+
+#define V_DSP_LAYER3_SEL(x)                (((x) & 3) << 14)
+#define V_DSP_LAYER2_SEL(x)                (((x) & 3) << 12)
+#define V_DSP_LAYER1_SEL(x)                (((x) & 3) << 10)
+#define V_DSP_LAYER0_SEL(x)                (((x) & 3) << 8)
+#define V_DITHER_UP_EN(x)                  (((x) & 1) << 6)
+#define V_DITHER_DOWN_SEL(x)               (((x) & 1) << 4)
+#define V_DITHER_DOWN_MODE(x)              (((x) & 1) << 3)
+#define V_DITHER_DOWN_EN(x)                (((x) & 1) << 2)
+#define V_PRE_DITHER_DOWN_EN(x)            (((x) & 1) << 1)
+#define V_DSP_LUT_EN(x)                    ((x)&1)
+
+/* VOP_DSP_BG */
+#define M_DSP_BG_RED     (0x3f << 20)
+#define M_DSP_BG_GREEN   (0x3f << 10)
+#define M_DSP_BG_BLUE    (0x3f << 0)
+
+#define V_DSP_BG_RED(x)     (((x) & 0x3f) << 20)
+#define V_DSP_BG_GREEN(x)   (((x) & 0x3f) << 10)
+#define V_DSP_BG_BLUE(x)    (((x) & 0x3f) << 0)
+
+/* VOP_WIN0_CTRL0 */
+#define M_WIN0_YUV_CLIP     (1 << 20)
+#define M_WIN0_CBR_DEFLICK  (1 << 19)
+#define M_WIN0_YRGB_DEFLICK  (1 << 18)
+#define M_WIN0_PPAS_ZERO_EN  (1 << 16)
+#define M_WIN0_UV_SWAP       (1 << 15)
+#define M_WIN0_MID_SWAP      (1 << 14)
+#define M_WIN0_ALPHA_SWAP    (1 << 13)
+#define M_WIN0_RB_SWAP       (1 << 12)
+#define M_WIN0_CSC_MODE      (3 << 10)
+#define M_WIN0_NO_OUTSTANDING (1 << 9)
+#define M_WIN0_INTERLACE_READ  (1 << 8)
+#define M_WIN0_LB_MODE         (7 << 5)
+#define M_WIN0_FMT_10          (1 << 4)
+#define M_WIN0_DATA_FMT        (7 << 1)
+#define M_WIN0_EN              (1 << 0)
+
+#define V_WIN0_YUV_CLIP(x)       (((x) & 1) << 20)
+#define V_WIN0_CBR_DEFLICK(x)    (((x) & 1) << 19)
+#define V_WIN0_YRGB_DEFLICK(x)   (((x) & 1) << 18)
+#define V_WIN0_PPAS_ZERO_EN(x)   (((x) & 1) << 16)
+#define V_WIN0_UV_SWAP(x)        (((x) & 1) << 15)
+#define V_WIN0_MID_SWAP(x)       (((x) & 1) << 14)
+#define V_WIN0_ALPHA_SWAP(x)     (((x) & 1) << 13)
+#define V_WIN0_RB_SWAP(x)        (((x) & 1) << 12)
+#define V_WIN0_CSC_MODE(x)       (((x) & 3) << 10)
+#define V_WIN0_NO_OUTSTANDING(x) (((x) & 1) << 9)
+#define V_WIN0_INTERLACE_READ(x)  (((x) & 1) << 8)
+#define V_WIN0_LB_MODE(x)         (((x) & 7) << 5)
+#define V_WIN0_FMT_10(x)          (((x) & 1) << 4)
+#define V_WIN0_DATA_FMT(x)        (((x) & 7) << 1)
+#define V_WIN0_EN(x)              ((x) & 1)
+
+/* VOP_WIN0_CTRL1 */
+#define M_WIN0_CBR_VSD_MODE        (1 << 31)
+#define M_WIN0_CBR_VSU_MODE        (1 << 30)
+#define M_WIN0_CBR_HSD_MODE        (3 << 28)
+#define M_WIN0_CBR_VER_SCL_MODE    (3 << 26)
+#define M_WIN0_CBR_HOR_SCL_MODE    (3 << 24)
+#define M_WIN0_YRGB_VSD_MODE       (1 << 23)
+#define M_WIN0_YRGB_VSU_MODE       (1 << 22)
+#define M_WIN0_YRGB_HSD_MODE       (3 << 20)
+#define M_WIN0_YRGB_VER_SCL_MODE   (3 << 18)
+#define M_WIN0_YRGB_HOR_SCL_MODE   (3 << 16)
+#define M_WIN0_LINE_LOAD_MODE      (1 << 15)
+#define M_WIN0_CBR_AXI_GATHER_NUM  (7 << 12)
+#define M_WIN0_YRGB_AXI_GATHER_NUM (0xf << 8)
+#define M_WIN0_VSD_CBR_GT2         (1 << 7)
+#define M_WIN0_VSD_CBR_GT4         (1 << 6)
+#define M_WIN0_VSD_YRGB_GT2        (1 << 5)
+#define M_WIN0_VSD_YRGB_GT4        (1 << 4)
+#define M_WIN0_BIC_COE_SEL         (3 << 2)
+#define M_WIN0_CBR_AXI_GATHER_EN   (1 << 1)
+#define M_WIN0_YRGB_AXI_GATHER_EN  (1)
+
+#define V_WIN0_CBR_VSD_MODE(x)        (((x) & 1) << 31)
+#define V_WIN0_CBR_VSU_MODE(x)        (((x) & 1) << 30)
+#define V_WIN0_CBR_HSD_MODE(x)        (((x) & 3) << 28)
+#define V_WIN0_CBR_VER_SCL_MODE(x)    (((x) & 3) << 26)
+#define V_WIN0_CBR_HOR_SCL_MODE(x)    (((x) & 3) << 24)
+#define V_WIN0_YRGB_VSD_MODE(x)       (((x) & 1) << 23)
+#define V_WIN0_YRGB_VSU_MODE(x)       (((x) & 1) << 22)
+#define V_WIN0_YRGB_HSD_MODE(x)       (((x) & 3) << 20)
+#define V_WIN0_YRGB_VER_SCL_MODE(x)   (((x) & 3) << 18)
+#define V_WIN0_YRGB_HOR_SCL_MODE(x)   (((x) & 3) << 16)
+#define V_WIN0_LINE_LOAD_MODE(x)      (((x) & 1) << 15)
+#define V_WIN0_CBR_AXI_GATHER_NUM(x)  (((x) & 7) << 12)
+#define V_WIN0_YRGB_AXI_GATHER_NUM(x) (((x) & 0xf) << 8)
+#define V_WIN0_VSD_CBR_GT2(x)         (((x) & 1) << 7)
+#define V_WIN0_VSD_CBR_GT4(x)         (((x) & 1) << 6)
+#define V_WIN0_VSD_YRGB_GT2(x)        (((x) & 1) << 5)
+#define V_WIN0_VSD_YRGB_GT4(x)        (((x) & 1) << 4)
+#define V_WIN0_BIC_COE_SEL(x)         (((x) & 3) << 2)
+#define V_WIN0_CBR_AXI_GATHER_EN(x)   (((x) & 1) << 1)
+#define V_WIN0_YRGB_AXI_GATHER_EN(x)  ((x) & 1)
+
+/*VOP_WIN0_COLOR_KEY*/
+#define M_WIN0_KEY_EN                 (1 << 31)
+#define M_WIN0_KEY_COLOR              (0x3fffffff)
+
+#define V_WIN0_KEY_EN(x)              (((x) & 1) << 31)
+#define V_WIN0_KEY_COLOR(x)           ((x) & 0x3fffffff)
+
+/* VOP_WIN0_VIR */
+#define V_ARGB888_VIRWIDTH(x)	(((x) & 0x3fff) << 0)
+#define V_RGB888_VIRWIDTH(x)	(((((x * 3) >> 2)+((x) % 3)) & 0x3fff) << 0)
+#define V_RGB565_VIRWIDTH(x)	(((x / 2) & 0x3fff) << 0)
+#define YUV_VIRWIDTH(x)		(((x / 4) & 0x3fff) << 0)
+
+/* VOP_WIN0_ACT_INFO */
+#define V_ACT_HEIGHT(x)         (((x) & 0x1fff) << 16)
+#define V_ACT_WIDTH(x)          ((x) & 0x1fff)
+
+/* VOP_WIN0_DSP_INFO */
+#define V_DSP_HEIGHT(x)         (((x) & 0xfff) << 16)
+#define V_DSP_WIDTH(x)          ((x) & 0xfff)
+
+/* VOP_WIN0_DSP_ST */
+#define V_DSP_YST(x)            (((x) & 0x1fff) << 16)
+#define V_DSP_XST(x)            ((x) & 0x1fff)
+
+/* VOP_WIN0_SCL_OFFSET */
+#define V_WIN0_VS_OFFSET_CBR(x)     (((x) & 0xff) << 24)
+#define V_WIN0_VS_OFFSET_YRGB(x)    (((x) & 0xff) << 16)
+#define V_WIN0_HS_OFFSET_CBR(x)     (((x) & 0xff) << 8)
+#define V_WIN0_HS_OFFSET_YRGB(x)    ((x) & 0xff)
+
+#define V_HSYNC(x)		(((x)&0x1fff)<<0)   /* hsync pulse width */
+#define V_HORPRD(x)		(((x)&0x1fff)<<16)   /* horizontal period */
+#define V_VSYNC(x)		(((x)&0x1fff)<<0)
+#define V_VERPRD(x)		(((x)&0x1fff)<<16)
+
+#define V_HEAP(x)		(((x)&0x1fff)<<0)/* horizontal active end */
+#define V_HASP(x)		(((x)&0x1fff)<<16)/* horizontal active start */
+#define V_VAEP(x)		(((x)&0x1fff)<<0)
+#define V_VASP(x)		(((x)&0x1fff)<<16)
+
+#endif
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile
index 5566719..0e9a8ac 100644
--- a/drivers/video/rockchip/Makefile
+++ b/drivers/video/rockchip/Makefile
@@ -5,4 +5,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-y += rk_edp.o rk_hdmi.o
+obj-y += rk_edp.o rk_hdmi.o rk_vop.o
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
new file mode 100644
index 0000000..adbc68f
--- /dev/null
+++ b/drivers/video/rockchip/rk_vop.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Copyright 2014 Rockchip Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <edid.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <video.h>
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cru_rk3288.h>
+#include <asm/arch/grf_rk3288.h>
+#include <asm/arch/edp_rk3288.h>
+#include <asm/arch/hdmi_rk3288.h>
+#include <asm/arch/vop_rk3288.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <dt-bindings/clock/rk3288-cru.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct rk_vop_priv {
+	struct rk3288_vop *regs;
+	struct rk3288_grf *grf;
+};
+
+void rkvop_enable(struct rk3288_vop *regs, ulong fbbase,
+		  int fb_bits_per_pixel, const struct display_timing *edid)
+{
+	u32 lb_mode;
+	u32 rgb_mode;
+	u32 hactive = edid->hactive.typ;
+	u32 vactive = edid->vactive.typ;
+
+	writel(V_ACT_WIDTH(hactive - 1) | V_ACT_HEIGHT(vactive - 1),
+	       &regs->win0_act_info);
+
+	writel(V_DSP_XST(edid->hsync_len.typ + edid->hback_porch.typ) |
+	       V_DSP_YST(edid->vsync_len.typ + edid->vback_porch.typ),
+	       &regs->win0_dsp_st);
+
+	writel(V_DSP_WIDTH(hactive - 1) |
+		V_DSP_HEIGHT(vactive - 1),
+		&regs->win0_dsp_info);
+
+	clrsetbits_le32(&regs->win0_color_key, M_WIN0_KEY_EN | M_WIN0_KEY_COLOR,
+			V_WIN0_KEY_EN(0) | V_WIN0_KEY_COLOR(0));
+
+	switch (fb_bits_per_pixel) {
+	case 16:
+		rgb_mode = RGB565;
+		writel(V_RGB565_VIRWIDTH(hactive), &regs->win0_vir);
+		break;
+	case 24:
+		rgb_mode = RGB888;
+		writel(V_RGB888_VIRWIDTH(hactive), &regs->win0_vir);
+		break;
+	case 32:
+	default:
+		rgb_mode = ARGB8888;
+		writel(V_ARGB888_VIRWIDTH(hactive), &regs->win0_vir);
+		break;
+	}
+
+	if (hactive > 2560)
+		lb_mode = LB_RGB_3840X2;
+	else if (hactive > 1920)
+		lb_mode = LB_RGB_2560X4;
+	else if (hactive > 1280)
+		lb_mode = LB_RGB_1920X5;
+	else
+		lb_mode = LB_RGB_1280X8;
+
+	clrsetbits_le32(&regs->win0_ctrl0,
+			M_WIN0_LB_MODE | M_WIN0_DATA_FMT | M_WIN0_EN,
+			V_WIN0_LB_MODE(lb_mode) | V_WIN0_DATA_FMT(rgb_mode) |
+			V_WIN0_EN(1));
+
+	writel(fbbase, &regs->win0_yrgb_mst);
+	writel(0x01, &regs->reg_cfg_done); /* enable reg config */
+}
+
+void rkvop_mode_set(struct rk3288_vop *regs,
+		    const struct display_timing *edid, enum vop_modes mode)
+{
+	u32 hactive = edid->hactive.typ;
+	u32 vactive = edid->vactive.typ;
+	u32 hsync_len = edid->hsync_len.typ;
+	u32 hback_porch = edid->hback_porch.typ;
+	u32 vsync_len = edid->vsync_len.typ;
+	u32 vback_porch = edid->vback_porch.typ;
+	u32 hfront_porch = edid->hfront_porch.typ;
+	u32 vfront_porch = edid->vfront_porch.typ;
+	uint flags;
+
+	switch (mode) {
+	case VOP_MODE_HDMI:
+		clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN,
+				V_HDMI_OUT_EN(1));
+		break;
+	case VOP_MODE_EDP:
+	default:
+		clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN,
+				V_EDP_OUT_EN(1));
+		break;
+	}
+
+	flags = V_DSP_OUT_MODE(15) |
+		V_DSP_HSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_HSYNC_HIGH)) |
+		V_DSP_VSYNC_POL(!!(edid->flags & DISPLAY_FLAGS_VSYNC_HIGH));
+
+	clrsetbits_le32(&regs->dsp_ctrl0,
+			M_DSP_OUT_MODE | M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
+			flags);
+
+	writel(V_HSYNC(hsync_len) |
+	       V_HORPRD(hsync_len + hback_porch + hactive + hfront_porch),
+			&regs->dsp_htotal_hs_end);
+
+	writel(V_HEAP(hsync_len + hback_porch + hactive) |
+	       V_HASP(hsync_len + hback_porch),
+	       &regs->dsp_hact_st_end);
+
+	writel(V_VSYNC(vsync_len) |
+	       V_VERPRD(vsync_len + vback_porch + vactive + vfront_porch),
+	       &regs->dsp_vtotal_vs_end);
+
+	writel(V_VAEP(vsync_len + vback_porch + vactive)|
+	       V_VASP(vsync_len + vback_porch),
+	       &regs->dsp_vact_st_end);
+
+	writel(V_HEAP(hsync_len + hback_porch + hactive) |
+	       V_HASP(hsync_len + hback_porch),
+	       &regs->post_dsp_hact_info);
+
+	writel(V_VAEP(vsync_len + vback_porch + vactive)|
+	       V_VASP(vsync_len + vback_porch),
+	       &regs->post_dsp_vact_info);
+
+	writel(0x01, &regs->reg_cfg_done); /* enable reg config */
+}
+
+/**
+ * rk_display_init() - Try to enable the given display device
+ *
+ * This function performs many steps:
+ * - Finds the display device being referenced by @ep_node
+ * - Puts the VOP's ID into its uclass platform data
+ * - Probes the device to set it up
+ * - Reads the EDID timing information
+ * - Sets up the VOP clocks, etc. for the selected pixel clock and display mode
+ * - Enables the display (the display device handles this and will do different
+ *     things depending on the display type)
+ * - Tells the uclass about the display resolution so that the console will
+ *     appear correctly
+ *
+ * @dev:	VOP device that we want to connect to the display
+ * @fbbase:	Frame buffer address
+ * @l2bpp	Log2 of bits-per-pixels for the display
+ * @ep_node:	Device tree node to process - this is the offset of an endpoint
+ *		node within the VOP's 'port' list.
+ * @return 0 if OK, -ve if something went wrong
+ */
+int rk_display_init(struct udevice *dev, ulong fbbase,
+		    enum video_log2_bpp l2bpp, int ep_node)
+{
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	const void *blob = gd->fdt_blob;
+	struct rk_vop_priv *priv = dev_get_priv(dev);
+	int vop_id, remote_vop_id;
+	struct rk3288_vop *regs = priv->regs;
+	struct display_timing timing;
+	struct udevice *disp;
+	int ret, remote, i, offset;
+	struct display_plat *disp_uc_plat;
+	struct udevice *clk;
+
+	vop_id = fdtdec_get_int(blob, ep_node, "reg", -1);
+	debug("vop_id=%d\n", vop_id);
+	remote = fdtdec_lookup_phandle(blob, ep_node, "remote-endpoint");
+	if (remote < 0)
+		return -EINVAL;
+	remote_vop_id = fdtdec_get_int(blob, remote, "reg", -1);
+	debug("remote vop_id=%d\n", remote_vop_id);
+
+	for (i = 0, offset = remote; i < 3 && offset > 0; i++)
+		offset = fdt_parent_offset(blob, offset);
+	if (offset < 0) {
+		debug("%s: Invalid remote-endpoint position\n", dev->name);
+		return -EINVAL;
+	}
+
+	ret = uclass_find_device_by_of_offset(UCLASS_DISPLAY, offset, &disp);
+	if (ret) {
+		debug("%s: device '%s' display not found (ret=%d)\n", __func__,
+		      dev->name, ret);
+		return ret;
+	}
+
+	disp_uc_plat = dev_get_uclass_platdata(disp);
+	debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
+	disp_uc_plat->source_id = remote_vop_id;
+	disp_uc_plat->src_dev = dev;
+
+	ret = device_probe(disp);
+	if (ret) {
+		debug("%s: device '%s' display won't probe (ret=%d)\n",
+		      __func__, dev->name, ret);
+		return ret;
+	}
+
+	ret = display_read_timing(disp, &timing);
+	if (ret) {
+		debug("%s: Failed to read timings\n", __func__);
+		return ret;
+	}
+
+	ret = rkclk_get_clk(CLK_NEW, &clk);
+	if (!ret) {
+		ret = clk_set_periph_rate(clk, DCLK_VOP0 + vop_id,
+					  timing.pixelclock.typ);
+	}
+	if (ret) {
+		debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret);
+		return ret;
+	}
+
+	rkvop_mode_set(regs, &timing, vop_id);
+
+	rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
+
+	ret = display_enable(disp, 1 << l2bpp, &timing);
+	if (ret)
+		return ret;
+
+	uc_priv->xsize = timing.hactive.typ;
+	uc_priv->ysize = timing.vactive.typ;
+	uc_priv->bpix = l2bpp;
+	debug("fb=%lx, size=%d %d\n", fbbase, uc_priv->xsize, uc_priv->ysize);
+
+	return 0;
+}
+
+static int rk_vop_probe(struct udevice *dev)
+{
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+	const void *blob = gd->fdt_blob;
+	struct rk_vop_priv *priv = dev_get_priv(dev);
+	struct udevice *reg;
+	int ret, port, node;
+
+	/* Before relocation we don't need to do anything */
+	if (!(gd->flags & GD_FLG_RELOC))
+		return 0;
+
+	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	priv->regs = (struct rk3288_vop *)dev_get_addr(dev);
+
+	/* lcdc(vop) iodomain select 1.8V */
+	rk_setreg(&priv->grf->io_vsel, 1 << 0);
+
+	/*
+	 * Try some common regulators. We should really get these from the
+	 * device tree somehow.
+	 */
+	ret = regulator_autoset_by_name("vcc18_lcd", &reg);
+	if (ret)
+		debug("%s: Cannot autoset regulator vcc18_lcd\n", __func__);
+	ret = regulator_autoset_by_name("VCC18_LCD", &reg);
+	if (ret)
+		debug("%s: Cannot autoset regulator VCC18_LCD\n", __func__);
+	ret = regulator_autoset_by_name("vdd10_lcd_pwren_h", &reg);
+	if (ret) {
+		debug("%s: Cannot autoset regulator vdd10_lcd_pwren_h\n",
+		      __func__);
+	}
+	ret = regulator_autoset_by_name("vdd10_lcd", &reg);
+	if (ret) {
+		debug("%s: Cannot autoset regulator vdd10_lcd\n",
+		      __func__);
+	}
+	ret = regulator_autoset_by_name("VDD10_LCD", &reg);
+	if (ret) {
+		debug("%s: Cannot autoset regulator VDD10_LCD\n",
+		      __func__);
+	}
+	ret = regulator_autoset_by_name("vcc33_lcd", &reg);
+	if (ret)
+		debug("%s: Cannot autoset regulator vcc33_lcd\n", __func__);
+
+	/*
+	 * Try all the ports until we find one that works. In practice this
+	 * tries EDP first if available, then HDMI.
+	 */
+	port = fdt_subnode_offset(blob, dev->of_offset, "port");
+	if (port < 0)
+		return -EINVAL;
+	for (node = fdt_first_subnode(blob, port);
+	     node > 0;
+	     node = fdt_next_subnode(blob, node)) {
+		ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node);
+		if (ret)
+			debug("Device failed: ret=%d\n", ret);
+		if (!ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int rk_vop_bind(struct udevice *dev)
+{
+	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+
+	plat->size = 1920 * 1080 * 2;
+
+	return 0;
+}
+
+static const struct video_ops rk_vop_ops = {
+};
+
+static const struct udevice_id rk_vop_ids[] = {
+	{ .compatible = "rockchip,rk3288-vop" },
+	{ }
+};
+
+U_BOOT_DRIVER(rk_vop) = {
+	.name	= "rk_vop",
+	.id	= UCLASS_VIDEO,
+	.of_match = rk_vop_ids,
+	.ops	= &rk_vop_ops,
+	.bind	= rk_vop_bind,
+	.probe	= rk_vop_probe,
+	.priv_auto_alloc_size	= sizeof(struct rk_vop_priv),
+};
-- 
2.7.0.rc3.207.g0ac5344



More information about the U-Boot mailing list