[U-Boot] [PATCH v2 1/3] rockchip: video: Add mipi dsi driver for rk3399
Simon Glass
sjg at chromium.org
Sat Apr 15 17:25:16 UTC 2017
Hi Eric,
On 14 April 2017 at 10:10, Eric Gao <eric.gao at rock-chips.com> wrote:
> Add mipi dsi driver for rk chip. To enable this you need to enable DM, DM_VIDEO
> DM_ROCKCHIP_VIDEO, DISPLAY_MIPI in menuconfig. And enable rk808 and it's i2c.
>
> Signed-off-by: Eric Gao <eric.gao at rock-chips.com>
>
> ---
>
> arch/arm/include/asm/arch-rockchip/cru_rk3399.h | 1 +
> arch/arm/include/asm/arch-rockchip/grf_rk3399.h | 25 ++
> arch/arm/include/asm/arch-rockchip/mipi_rk3399.h | 195 ++++++++++
> arch/arm/include/asm/arch-rockchip/vop_rk3288.h | 1 +
> board/rockchip/evb_rk3399/evb-rk3399.c | 6 +
> drivers/video/Kconfig | 2 +
> drivers/video/rockchip/Kconfig | 38 ++
> drivers/video/rockchip/Makefile | 6 +-
> drivers/video/rockchip/rk_mipi.c | 464 +++++++++++++++++++++++
> drivers/video/rockchip/rk_vop.c | 38 +-
> 10 files changed, 769 insertions(+), 7 deletions(-)
> create mode 100644 arch/arm/include/asm/arch-rockchip/mipi_rk3399.h
> create mode 100644 drivers/video/rockchip/Kconfig
> create mode 100644 drivers/video/rockchip/rk_mipi.c
This looks pretty good to me but I think it needs another round.
Please can you split our this change a bit:
first patch: introduce your new Kconfig options (not the MIPI one
yet). Make sure that firefly-rk3288 and anything else that uses HDMI
still works. Same with boards that use EDP or LVDS. You will probably
need to add your new Kconfig options to their defconfig files
second patch: add the MIPI driver with its header file and
Makefile/Kconfig additions needed by the driver
third patch: rk_display_init() log2_bpp changes
fourth patch: change to plat->size
fifth patch: plumb driver into rv_vop.c and add the vop_rk3288.h change
Also make sure that the code is not compiled if CONFIG_VIDEO_ROCKCHIP
is not defined.
>
> diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h
> index cf830d0..e9e5810 100644
> --- a/arch/arm/include/asm/arch-rockchip/cru_rk3399.h
> +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3399.h
> @@ -70,6 +70,7 @@ struct rk3399_cru {
> };
> check_member(rk3399_cru, sdio1_con[1], 0x594);
> #define MHz 1000000
> +#define MHZ 1000000
Can you just use MHz instead?
> #define KHz 1000
> #define OSC_HZ (24*MHz)
> #define APLL_HZ (600*MHz)
> diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> index 62d8496..2bf58da 100644
> --- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> @@ -399,6 +399,31 @@ enum {
> GRF_UART_DBG_SEL_MASK = 3 << GRF_UART_DBG_SEL_SHIFT,
> GRF_UART_DBG_SEL_C = 2,
>
> + /* GRF_SOC_CON20 */
> + GRF_DSI0_VOP_SEL_SHIFT = 0,
> + GRF_DSI0_VOP_SEL_MASK = 1 << GRF_DSI0_VOP_SEL_SHIFT,
> + GRF_DSI0_VOP_SEL_B = 0,
> + GRF_DSI0_VOP_SEL_L,
> +
> + /* GRF_SOC_CON22 */
> + GRF_DPHY_TX0_RXMODE_SHIFT = 0,
> + GRF_DPHY_TX0_RXMODE_MASK =
> + 0xf << GRF_DPHY_TX0_RXMODE_SHIFT,
> + GRF_DPHY_TX0_RXMODE_EN = 0xb,
> + GRF_DPHY_TX0_RXMODE_DIS = 0,
> +
> + GRF_DPHY_TX0_TXSTOPMODE_SHIFT = 4,
> + GRF_DPHY_TX0_TXSTOPMODE_MASK =
> + 0xf0 << GRF_DPHY_TX0_TXSTOPMODE_SHIFT,
> + GRF_DPHY_TX0_TXSTOPMODE_EN = 0xc,
> + GRF_DPHY_TX0_TXSTOPMODE_DIS = 0,
> +
> + GRF_DPHY_TX0_TURNREQUEST_SHIFT = 12,
> + GRF_DPHY_TX0_TURNREQUEST_MASK =
> + 0xf000 << GRF_DPHY_TX0_TURNREQUEST_SHIFT,
> + GRF_DPHY_TX0_TURNREQUEST_EN = 0x1,
> + GRF_DPHY_TX0_TURNREQUEST_DIS = 0,
> +
> /* PMUGRF_GPIO0A_IOMUX */
> PMUGRF_GPIO0A6_SEL_SHIFT = 12,
> PMUGRF_GPIO0A6_SEL_MASK = 3 << PMUGRF_GPIO0A6_SEL_SHIFT,
> diff --git a/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h
> new file mode 100644
> index 0000000..f55ffb6
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-rockchip/mipi_rk3399.h
> @@ -0,0 +1,195 @@
> +/*
> + * Copyright (C) 2017-2025 Fuzhou Rockchip Electronics Co., Ltd
> + * author: Eric Gao <eric.gao at rock-chips.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#ifndef RK33_MIPI_DSI_H
> +#define RK33_MIPI_DSI_H
> +
> +/*
> + * All these mipi controller register declaration provide reg address offset,
> + * bits width, bit offset for a specified register bits. With these message, we
> + * can set or clear every bits individually for a 32bit widthregister. We use
> + * DSI_HOST_BITS macro definition to combinat these message using the following
> + * format: val(32bit) = addr(16bit) | width(8bit) | offest(8bit)
> + * For example:
> + * #define SHUTDOWNZ DSI_HOST_BITS(0x004, 1, 0)
> + * means SHUTDOWNZ is a signal reg bit with bit offset qual 0,and it's reg addr
> + * offset is 0x004.The conbinat result = (0x004 << 16) | (1 << 8) | 0
> + */
> +#define ADDR_SHIFT 16
> +#define BITS_SHIFT 8
> +#define OFFSET_SHIFT 0
> +#define DSI_HOST_BITS(addr, bits, bit_offset) \
> +((addr << ADDR_SHIFT) | (bits << BITS_SHIFT) | (bit_offset << OFFSET_SHIFT))
> +
> +/* DWC_DSI_VERSION_0x3133302A */
> +#define VERSION DSI_HOST_BITS(0x000, 32, 0)
> +#define SHUTDOWNZ DSI_HOST_BITS(0x004, 1, 0)
> +#define TO_CLK_DIVISION DSI_HOST_BITS(0x008, 8, 8)
> +#define TX_ESC_CLK_DIVISION DSI_HOST_BITS(0x008, 8, 0)
> +#define DPI_VCID DSI_HOST_BITS(0x00c, 2, 0)
> +#define EN18_LOOSELY DSI_HOST_BITS(0x010, 1, 8)
> +#define DPI_COLOR_CODING DSI_HOST_BITS(0x010, 4, 0)
> +#define COLORM_ACTIVE_LOW DSI_HOST_BITS(0x014, 1, 4)
> +#define SHUTD_ACTIVE_LOW DSI_HOST_BITS(0x014, 1, 3)
> +#define HSYNC_ACTIVE_LOW DSI_HOST_BITS(0x014, 1, 2)
> +#define VSYNC_ACTIVE_LOW DSI_HOST_BITS(0x014, 1, 1)
> +#define DATAEN_ACTIVE_LOW DSI_HOST_BITS(0x014, 1, 0)
> +#define OUTVACT_LPCMD_TIME DSI_HOST_BITS(0x018, 8, 16)
> +#define INVACT_LPCMD_TIME DSI_HOST_BITS(0x018, 8, 0)
> +#define CRC_RX_EN DSI_HOST_BITS(0x02c, 1, 4)
> +#define ECC_RX_EN DSI_HOST_BITS(0x02c, 1, 3)
> +#define BTA_EN DSI_HOST_BITS(0x02c, 1, 2)
> +#define EOTP_RX_EN DSI_HOST_BITS(0x02c, 1, 1)
> +#define EOTP_TX_EN DSI_HOST_BITS(0x02c, 1, 0)
> +#define GEN_VID_RX DSI_HOST_BITS(0x030, 2, 0)
> +#define CMD_VIDEO_MODE DSI_HOST_BITS(0x034, 1, 0)
> +#define VPG_ORIENTATION DSI_HOST_BITS(0x038, 1, 24)
> +#define VPG_MODE DSI_HOST_BITS(0x038, 1, 20)
> +#define VPG_EN DSI_HOST_BITS(0x038, 1, 16)
> +#define LP_CMD_EN DSI_HOST_BITS(0x038, 1, 15)
> +#define FRAME_BTA_ACK_EN DSI_HOST_BITS(0x038, 1, 14)
> +#define LP_HFP_EN DSI_HOST_BITS(0x038, 1, 13)
> +#define LP_HBP_EN DSI_HOST_BITS(0x038, 1, 12)
> +#define LP_VACT_EN DSI_HOST_BITS(0x038, 1, 11)
> +#define LP_VFP_EN DSI_HOST_BITS(0x038, 1, 10)
> +#define LP_VBP_EN DSI_HOST_BITS(0x038, 1, 9)
> +#define LP_VSA_EN DSI_HOST_BITS(0x038, 1, 8)
> +#define VID_MODE_TYPE DSI_HOST_BITS(0x038, 2, 0)
> +#define VID_PKT_SIZE DSI_HOST_BITS(0x03c, 14, 0)
> +#define NUM_CHUNKS DSI_HOST_BITS(0x040, 13, 0)
> +#define NULL_PKT_SIZE DSI_HOST_BITS(0x044, 13, 0)
> +#define VID_HSA_TIME DSI_HOST_BITS(0x048, 12, 0)
> +#define VID_HBP_TIME DSI_HOST_BITS(0x04c, 12, 0)
> +#define VID_HLINE_TIME DSI_HOST_BITS(0x050, 15, 0)
> +#define VID_VSA_LINES DSI_HOST_BITS(0x054, 10, 0)
> +#define VID_VBP_LINES DSI_HOST_BITS(0x058, 10, 0)
> +#define VID_VFP_LINES DSI_HOST_BITS(0x05c, 10, 0)
> +#define VID_ACTIVE_LINES DSI_HOST_BITS(0x060, 14, 0)
> +#define EDPI_CMD_SIZE DSI_HOST_BITS(0x064, 16, 0)
> +#define MAX_RD_PKT_SIZE DSI_HOST_BITS(0x068, 1, 24)
> +#define DCS_LW_TX DSI_HOST_BITS(0x068, 1, 19)
> +#define DCS_SR_0P_TX DSI_HOST_BITS(0x068, 1, 18)
> +#define DCS_SW_1P_TX DSI_HOST_BITS(0x068, 1, 17)
> +#define DCS_SW_0P_TX DSI_HOST_BITS(0x068, 1, 16)
> +#define GEN_LW_TX DSI_HOST_BITS(0x068, 1, 14)
> +#define GEN_SR_2P_TX DSI_HOST_BITS(0x068, 1, 13)
> +#define GEN_SR_1P_TX DSI_HOST_BITS(0x068, 1, 12)
> +#define GEN_SR_0P_TX DSI_HOST_BITS(0x068, 1, 11)
> +#define GEN_SW_2P_TX DSI_HOST_BITS(0x068, 1, 10)
> +#define GEN_SW_1P_TX DSI_HOST_BITS(0x068, 1, 9)
> +#define GEN_SW_0P_TX DSI_HOST_BITS(0x068, 1, 8)
> +#define ACK_RQST_EN DSI_HOST_BITS(0x068, 1, 1)
> +#define TEAR_FX_EN DSI_HOST_BITS(0x068, 1, 0)
> +#define GEN_WC_MSBYTE DSI_HOST_BITS(0x06c, 14, 16)
> +#define GEN_WC_LSBYTE DSI_HOST_BITS(0x06c, 8, 8)
> +#define GEN_VC DSI_HOST_BITS(0x06c, 2, 6)
> +#define GEN_DT DSI_HOST_BITS(0x06c, 6, 0)
> +#define GEN_PLD_DATA DSI_HOST_BITS(0x070, 32, 0)
> +#define GEN_RD_CMD_BUSY DSI_HOST_BITS(0x074, 1, 6)
> +#define GEN_PLD_R_FULL DSI_HOST_BITS(0x074, 1, 5)
> +#define GEN_PLD_R_EMPTY DSI_HOST_BITS(0x074, 1, 4)
> +#define GEN_PLD_W_FULL DSI_HOST_BITS(0x074, 1, 3)
> +#define GEN_PLD_W_EMPTY DSI_HOST_BITS(0x074, 1, 2)
> +#define GEN_CMD_FULL DSI_HOST_BITS(0x074, 1, 1)
> +#define GEN_CMD_EMPTY DSI_HOST_BITS(0x074, 1, 0)
> +#define HSTX_TO_CNT DSI_HOST_BITS(0x078, 16, 16)
> +#define LPRX_TO_CNT DSI_HOST_BITS(0x078, 16, 0)
> +#define HS_RD_TO_CNT DSI_HOST_BITS(0x07c, 16, 0)
> +#define LP_RD_TO_CNT DSI_HOST_BITS(0x080, 16, 0)
> +#define PRESP_TO_MODE DSI_HOST_BITS(0x084, 1, 24)
> +#define HS_WR_TO_CNT DSI_HOST_BITS(0x084, 16, 0)
> +#define LP_WR_TO_CNT DSI_HOST_BITS(0x088, 16, 0)
> +#define BTA_TO_CNT DSI_HOST_BITS(0x08c, 16, 0)
> +#define AUTO_CLKLANE_CTRL DSI_HOST_BITS(0x094, 1, 1)
> +#define PHY_TXREQUESTCLKHS DSI_HOST_BITS(0x094, 1, 0)
> +#define PHY_HS2LP_TIME_CLK_LANE DSI_HOST_BITS(0x098, 10, 16)
> +#define PHY_HS2HS_TIME_CLK_LANE DSI_HOST_BITS(0x098, 10, 0)
> +#define PHY_HS2LP_TIME DSI_HOST_BITS(0x09c, 8, 24)
> +#define PHY_LP2HS_TIME DSI_HOST_BITS(0x09c, 8, 16)
> +#define MAX_RD_TIME DSI_HOST_BITS(0x09c, 15, 0)
> +#define PHY_FORCEPLL DSI_HOST_BITS(0x0a0, 1, 3)
> +#define PHY_ENABLECLK DSI_HOST_BITS(0x0a0, 1, 2)
> +#define PHY_RSTZ DSI_HOST_BITS(0x0a0, 1, 1)
> +#define PHY_SHUTDOWNZ DSI_HOST_BITS(0x0a0, 1, 0)
> +#define PHY_STOP_WAIT_TIME DSI_HOST_BITS(0x0a4, 8, 8)
> +#define N_LANES DSI_HOST_BITS(0x0a4, 2, 0)
> +#define PHY_TXEXITULPSLAN DSI_HOST_BITS(0x0a8, 1, 3)
> +#define PHY_TXREQULPSLAN DSI_HOST_BITS(0x0a8, 1, 2)
> +#define PHY_TXEXITULPSCLK DSI_HOST_BITS(0x0a8, 1, 1)
> +#define PHY_TXREQULPSCLK DSI_HOST_BITS(0x0a8, 1, 0)
> +#define PHY_TX_TRIGGERS DSI_HOST_BITS(0x0ac, 4, 0)
> +#define PHYSTOPSTATECLKLANE DSI_HOST_BITS(0x0b0, 1, 2)
> +#define PHYLOCK DSI_HOST_BITS(0x0b0, 1, 0)
> +#define PHY_TESTCLK DSI_HOST_BITS(0x0b4, 1, 1)
> +#define PHY_TESTCLR DSI_HOST_BITS(0x0b4, 1, 0)
> +#define PHY_TESTEN DSI_HOST_BITS(0x0b8, 1, 16)
> +#define PHY_TESTDOUT DSI_HOST_BITS(0x0b8, 8, 8)
> +#define PHY_TESTDIN DSI_HOST_BITS(0x0b8, 8, 0)
> +#define PHY_TEST_CTRL1 DSI_HOST_BITS(0x0b8, 17, 0)
> +#define PHY_TEST_CTRL0 DSI_HOST_BITS(0x0b4, 2, 0)
> +#define INT_ST0 DSI_HOST_BITS(0x0bc, 21, 0)
> +#define INT_ST1 DSI_HOST_BITS(0x0c0, 18, 0)
> +#define INT_MKS0 DSI_HOST_BITS(0x0c4, 21, 0)
> +#define INT_MKS1 DSI_HOST_BITS(0x0c8, 18, 0)
> +#define INT_FORCE0 DSI_HOST_BITS(0x0d8, 21, 0)
> +#define INT_FORCE1 DSI_HOST_BITS(0x0dc, 18, 0)
> +
> +#define CODE_HS_RX_CLOCK 0x34
> +#define CODE_HS_RX_LANE0 0x44
> +#define CODE_HS_RX_LANE1 0x54
> +#define CODE_HS_RX_LANE2 0x84
> +#define CODE_HS_RX_LANE3 0x94
> +
> +#define CODE_PLL_VCORANGE_VCOCAP 0x10
> +#define CODE_PLL_CPCTRL 0x11
> +#define CODE_PLL_LPF_CP 0x12
> +#define CODE_PLL_INPUT_DIV_RAT 0x17
> +#define CODE_PLL_LOOP_DIV_RAT 0x18
> +#define CODE_PLL_INPUT_LOOP_DIV_RAT 0x19
> +#define CODE_BANDGAP_BIAS_CTRL 0x20
> +#define CODE_TERMINATION_CTRL 0x21
> +#define CODE_AFE_BIAS_BANDGAP_ANOLOG 0x22
> +
> +#define CODE_HSTXDATALANEREQUSETSTATETIME 0x70
> +#define CODE_HSTXDATALANEPREPARESTATETIME 0x71
> +#define CODE_HSTXDATALANEHSZEROSTATETIME 0x72
> +
> +/* Transmission mode between vop and MIPI controller */
> +enum vid_mode_type_t {
> + NON_BURST_SYNC_PLUSE = 0,
> + NON_BURST_SYNC_EVENT,
> + BURST_MODE,
> +};
> +
> +enum cmd_video_mode {
> + VIDEO_MODE = 0,
> + CMD_MODE,
> +};
> +
> +/* Indicate MIPI DSI color mode */
> +enum dpi_color_coding {
> + DPI_16BIT_CFG_1 = 0,
> + DPI_16BIT_CFG_2,
> + DPI_16BIT_CFG_3,
> + DPI_18BIT_CFG_1,
> + DPI_18BIT_CFG_2,
> + DPI_24BIT,
> + DPI_20BIT_YCBCR_422_LP,
> + DPI_24BIT_YCBCR_422,
> + DPI_16BIT_YCBCR_422,
> + DPI_30BIT,
> + DPI_36BIT,
> + DPI_12BIT_YCBCR_420,
> +};
> +
> +/* Indicate which VOP the MIPI DSI use, bit or little one */
> +enum vop_id {
> + VOP_B = 0,
> + VOP_L,
> +};
> +
> +#endif /* end of RK33_MIPI_DSI_H */
> diff --git a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h
> index 0ce3d67..d5599ec 100644
> --- a/arch/arm/include/asm/arch-rockchip/vop_rk3288.h
> +++ b/arch/arm/include/asm/arch-rockchip/vop_rk3288.h
> @@ -90,6 +90,7 @@ enum vop_modes {
> VOP_MODE_EDP = 0,
> VOP_MODE_HDMI,
> VOP_MODE_LVDS,
> + VOP_MODE_MIPI,
> VOP_MODE_NONE,
> VOP_MODE_AUTO_DETECT,
> VOP_MODE_UNKNOWN,
> diff --git a/board/rockchip/evb_rk3399/evb-rk3399.c b/board/rockchip/evb_rk3399/evb-rk3399.c
> index c437f1b..ec2b023 100644
> --- a/board/rockchip/evb_rk3399/evb-rk3399.c
> +++ b/board/rockchip/evb_rk3399/evb-rk3399.c
> @@ -28,6 +28,12 @@ int board_init(void)
> goto out;
> }
>
> + ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_PWM0);
> + if (ret) {
> + debug("%s PWM0 pinctrl init fail!\n", __func__);
> + goto out;
> + }
> +
> ret = pinctrl_request_noflags(pinctrl, PERIPH_ID_PWM2);
> if (ret) {
> debug("%s PWM2 pinctrl init fail!\n", __func__);
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 2069576..4b03a9a 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -405,6 +405,8 @@ config VIDEO_ROCKCHIP
> (DSI). This driver supports the on-chip video output device, and
> targets the Rockchip RK3288.
>
> +source "drivers/video/rockchip/Kconfig"
> +
> config VIDEO_SANDBOX_SDL
> bool "Enable sandbox video console using SDL"
> depends on SANDBOX
> diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig
> new file mode 100644
> index 0000000..811be83
> --- /dev/null
> +++ b/drivers/video/rockchip/Kconfig
> @@ -0,0 +1,38 @@
> +#
> +# Video drivers selection for rockchip soc. These configs only impact the
> +# compile process. You can surely check all the options. In this case, all the
> +# display driver will be compiled, but which drivers finally will be used is
> +# decided by device tree configuration. What's more, enable needed power for
> +# display by configure the device tree, and the vop driver will do the rest.
> +#
> +# Author: Eric Gao <eric.gao at rock-chips.com>
> +#
> +
> +menu "Video Display Port"
> +
> +config DISPLAY_MIPI
DISPLAY_ROCKCHIP_MIPI?
If you want this to apply to all of U-Boot then it should not be in a
rockchip directory. I think it is best to leave it rockchip-specific,
and add ROCKCHIP_ to the name.
> + bool "MIPI Port"
> + depends on VIDEO_ROCKCHIP
> + help
> + "Mobile Industry Processor Interface"
Please remove quotes:
This enables Mobile Industry Processor Interface (MIPI) display
support...some brief words about what MIPI is
others similar
> + This MIPI Controller and MIPI PHY is designed by Synopsys, which
> + support 16,18, 24 bits per pixel. And upto 2k resolution ratio.
> +
> +config DISPLAY_EDP
> + bool "EDP Port"
> + depends on VIDEO_ROCKCHIP
> + help
> + "Embedded DisplayPort"
> +
> +config DISPLAY_LVDS
> + bool "LVDS Port"
> + depends on VIDEO_ROCKCHIP
> + help
> + "Low-voltage Differential Signaling"
> +
> +config DISPLAY_HDMI
> + bool "HDMI port"
> + depends on VIDEO_ROCKCHIP
> + help
> + "High-Definition Multimedia Interface"
> +endmenu
> diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile
> index 7962f86..a14db04 100644
> --- a/drivers/video/rockchip/Makefile
> +++ b/drivers/video/rockchip/Makefile
> @@ -5,4 +5,8 @@
> # SPDX-License-Identifier: GPL-2.0+
> #
>
> -obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o
> +obj-$(CONFIG_VIDEO_ROCKCHIP) += rk_vop.o
> +obj-$(CONFIG_DISPLAY_MIPI) += rk_mipi.o
> +obj-$(CONFIG_DISPLAY_EDP) += rk_edp.o
> +obj-$(CONFIG_DISPLAY_LVDS) += rk_lvds.o
> +obj-$(CONFIG_DISPLAY_HDMI) += rk_hdmi.o
Please rebase on u-boot-dm/master. You'll need to include the dwc file with HDMI
> diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c
> new file mode 100644
> index 0000000..58541d6
> --- /dev/null
> +++ b/drivers/video/rockchip/rk_mipi.c
> @@ -0,0 +1,464 @@
> +/*
> + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
> + * Author: Eric Gao <eric.gao at rock-chips.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <clk.h>
> +#include <display.h>
> +#include <dm.h>
> +#include <dt-bindings/clock/rk3288-cru.h>
This should go before linux/ below
> +#include <dm/uclass-internal.h>
this should go before dt-bindings
> +#include <fdtdec.h>
> +#include <panel.h>
> +#include <regmap.h>
> +#include <syscon.h>
> +#include <asm/gpio.h>
> +#include <asm/io.h>
> +#include <asm/hardware.h>
> +#include <asm/arch/mipi_rk3399.h>
> +#include <asm/arch/clock.h>
> +#include <asm/arch/grf_rk3399.h>
> +#include <asm/arch/cru_rk3399.h>
> +#include <linux/kernel.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct mipi_dsi {
Please add comment as t owhat this is
> + u32 ref_clk;
> + u32 sys_clk;
> + u32 pix_clk;
> + u32 phy_clk;
> + u32 txbyte_clk;
> + u32 txesc_clk;
> +};
> +
> +struct rk_mipi_priv {
> + void __iomem *regs;
> + struct rk3399_grf_regs *grf;
> + struct udevice *panel;
> + struct mipi_dsi *dsi;
> +};
> +
> +static int rk_mipi_read_timing(struct udevice *dev,
> + struct display_timing *timing)
> +{
> + if (fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(dev),
> + 0, timing)) {
> + debug("%s: Failed to decode display timing\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +/*
> + * Register write function used only for mipi dsi controller.
> + * Parameter:
> + * reg: combination of regaddr(16bit)|bitswidth(8bit)|offset(8bit) you can use
> + * define in rk_mipi.h directly for this parameter
> + * val: value that will be write to specified bits of register
> + */
> +static void rk_mipi_dsi_write(u32 regs, u32 reg, u32 val)
> +{
> + u32 dat;
> + u32 mask;
> + u32 offset = (reg >> OFFSET_SHIFT & 0xff);
> + u32 bits = ((reg >> BITS_SHIFT) & 0xff);
> + u64 addr = ((reg >> ADDR_SHIFT) + regs);
> +
> + /* Mask for specifiled bits,the corresponding bits will be clear */
> + mask = (~((0xffffffff << offset) & (0xffffffff >>
> + (32 - offset - bits))));
> +
> + /* Make sure val in the available range */
> + val &= (~(0xffffffff << bits));
Drop the outer brackets
> +
> + /* Get register's original val */
> + dat = readl(addr);
> +
> + /* Clear specified bits */
> + dat &= mask;
> +
> + /* Fill specified bits */
> + dat |= (val << offset);
> +
> + writel(dat, addr);
> +}
> +
> +static int rk_mipi_dsi_enable(struct udevice *dev,
> + const struct display_timing *timing)
> +{
> + int node, timing_node;
> + int val;
> + struct rk_mipi_priv *priv = dev_get_priv(dev);
> + u64 regs = (u64)(priv->regs);
Drop the brackets around priv->regs
> + struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);
> + u32 txbyte_clk = priv->dsi->txbyte_clk;
> + u32 txesc_clk = priv->dsi->txesc_clk;
> +
> + txesc_clk = txbyte_clk/(txbyte_clk/txesc_clk + 1);
> +
> + /* Select the video source */
> + switch (disp_uc_plat->source_id) {
> + case VOP_B:
> + rk_clrsetreg(&priv->grf->soc_con20, GRF_DSI0_VOP_SEL_MASK,
> + GRF_DSI0_VOP_SEL_B << GRF_DSI0_VOP_SEL_SHIFT);
> + break;
> + case VOP_L:
> + rk_clrsetreg(&priv->grf->soc_con20, GRF_DSI0_VOP_SEL_MASK,
> + GRF_DSI0_VOP_SEL_L << GRF_DSI0_VOP_SEL_SHIFT);
> + break;
> + default:
debug()
> + return -EINVAL;
> + }
> +
> + /* Set Controller as TX mode */
> + val = GRF_DPHY_TX0_RXMODE_DIS << GRF_DPHY_TX0_RXMODE_SHIFT;
> + rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_RXMODE_MASK, val);
> +
> + /* Exit tx stop mode */
> + val |= GRF_DPHY_TX0_TXSTOPMODE_DIS << GRF_DPHY_TX0_TXSTOPMODE_SHIFT;
> + rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_TXSTOPMODE_MASK, val);
> +
> + /* Disable turnequest */
> + val |= GRF_DPHY_TX0_TURNREQUEST_DIS << GRF_DPHY_TX0_TURNREQUEST_SHIFT;
> + rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_TURNREQUEST_MASK, val);
> +
> + /* Set Display timing parameter */
> + rk_mipi_dsi_write(regs, VID_HSA_TIME, timing->hsync_len.typ);
> + rk_mipi_dsi_write(regs, VID_HBP_TIME, timing->hback_porch.typ);
> + rk_mipi_dsi_write(regs, VID_HLINE_TIME, (timing->hsync_len.typ
> + + timing->hback_porch.typ + timing->hactive.typ
> + + timing->hfront_porch.typ));
> + rk_mipi_dsi_write(regs, VID_VSA_LINES, timing->vsync_len.typ);
> + rk_mipi_dsi_write(regs, VID_VBP_LINES, timing->vback_porch.typ);
> + rk_mipi_dsi_write(regs, VID_VFP_LINES, timing->vfront_porch.typ);
> + rk_mipi_dsi_write(regs, VID_ACTIVE_LINES, timing->vactive.typ);
> +
> + /* Set Signal Polarity */
> + val = (timing->flags & DISPLAY_FLAGS_HSYNC_LOW) ? 1 : 0;
> + rk_mipi_dsi_write(regs, HSYNC_ACTIVE_LOW, val);
> +
> + val = (timing->flags & DISPLAY_FLAGS_VSYNC_LOW) ? 1 : 0;
> + rk_mipi_dsi_write(regs, VSYNC_ACTIVE_LOW, val);
> +
> + val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0;
> + rk_mipi_dsi_write(regs, DISPLAY_FLAGS_DE_LOW, val);
> +
> + val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0;
> + rk_mipi_dsi_write(regs, COLORM_ACTIVE_LOW, val);
> +
> + /* Set video mode */
> + rk_mipi_dsi_write(regs, CMD_VIDEO_MODE, VIDEO_MODE);
> +
> + /* Set video mode transmission type as burst mode */
> + rk_mipi_dsi_write(regs, VID_MODE_TYPE, BURST_MODE);
> +
> + /* Set pix num in a video package */
> + rk_mipi_dsi_write(regs, VID_PKT_SIZE, 0x4b0);
> +
> + /* Set dpi color coding depth 24 bit */
> + timing_node = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
> + "display-timings");
> + node = fdt_first_subnode(gd->fdt_blob, timing_node);
> + val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
> + switch (val) {
> + case 16:
> + rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_16BIT_CFG_1);
> + break;
> + case 24:
> + rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_24BIT);
> + break;
> + case 30:
> + rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_30BIT);
> + break;
> + default:
> + rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_24BIT);
> + }
> + /* Enable low power mode */
> + rk_mipi_dsi_write(regs, LP_CMD_EN, 1);
> + rk_mipi_dsi_write(regs, LP_HFP_EN, 1);
> + rk_mipi_dsi_write(regs, LP_VACT_EN, 1);
> + rk_mipi_dsi_write(regs, LP_VFP_EN, 1);
> + rk_mipi_dsi_write(regs, LP_VBP_EN, 1);
> + rk_mipi_dsi_write(regs, LP_VSA_EN, 1);
> +
> + /* Division for timeout counter clk */
> + rk_mipi_dsi_write(regs, TO_CLK_DIVISION, 0x0a);
> +
> + /* Tx esc clk division from txbyte clk */
> + rk_mipi_dsi_write(regs, TX_ESC_CLK_DIVISION, txbyte_clk/txesc_clk);
> +
> + /* Timeout count for hs<->lp transation between Line period */
> + rk_mipi_dsi_write(regs, HSTX_TO_CNT, 0x3e8);
> +
> + /* Phy State transfer timing */
> + rk_mipi_dsi_write(regs, PHY_STOP_WAIT_TIME, 32);
> + rk_mipi_dsi_write(regs, PHY_TXREQUESTCLKHS, 1);
> + rk_mipi_dsi_write(regs, PHY_HS2LP_TIME, 0x14);
> + rk_mipi_dsi_write(regs, PHY_LP2HS_TIME, 0x10);
> + rk_mipi_dsi_write(regs, MAX_RD_TIME, 0x2710);
> +
> + /* Power on */
> + rk_mipi_dsi_write(regs, SHUTDOWNZ, 1);
> +
> + return 0;
> +}
> +
> +/* rk mipi dphy write function */
This seems to write test data. Please expand this comment to explain
it properly.
> +static void rk_mipi_phy_write(u32 regs, unsigned char test_code,
> + unsigned char *test_data, unsigned char size)
> +{
> + int i = 0;
blank line here
> + /* Write Test code */
> + rk_mipi_dsi_write(regs, PHY_TESTCLK, 1);
> + rk_mipi_dsi_write(regs, PHY_TESTDIN, test_code);
> + rk_mipi_dsi_write(regs, PHY_TESTEN, 1);
> + rk_mipi_dsi_write(regs, PHY_TESTCLK, 0);
> + rk_mipi_dsi_write(regs, PHY_TESTEN, 0);
> +
> + /* Write Test data */
> + for (i = 0; i < size; i++) {
> + rk_mipi_dsi_write(regs, PHY_TESTCLK, 0);
> + rk_mipi_dsi_write(regs, PHY_TESTDIN, test_data[i]);
> + rk_mipi_dsi_write(regs, PHY_TESTCLK, 1);
> + }
> +}
> +
> +/*
> + * Mipi dphy config function. Calculate the suitable prediv, feedback div,
> + * fsfreqrang value ,cap ,lpf and so on according to the given pix clk rate,
> + * and then enable phy.
> + */
> +static int rk_mipi_phy_enable(struct udevice *dev)
> +{
> + int i;
> + struct rk_mipi_priv *priv = dev_get_priv(dev);
> + u64 regs = (u64)(priv->regs);
> + u64 fbdiv;
> + u64 prediv = 1;
> + u32 max_fbdiv = 512;
> + u32 max_prediv, min_prediv;
> + u64 ddr_clk = priv->dsi->phy_clk;
> + u32 refclk = priv->dsi->ref_clk;
> + u32 remain = refclk;
> + unsigned char test_data[2] = {0};
> +
> + int freq_rang[][2] = {
> + {90, 0x01}, {100, 0x10}, {110, 0x20}, {130, 0x01},
> + {140, 0x11}, {150, 0x21}, {170, 0x02}, {180, 0x12},
> + {200, 0x22}, {220, 0x03}, {240, 0x13}, {250, 0x23},
> + {270, 0x04}, {300, 0x14}, {330, 0x05}, {360, 0x15},
> + {400, 0x25}, {450, 0x06}, {500, 0x16}, {550, 0x07},
> + {600, 0x17}, {650, 0x08}, {700, 0x18}, {750, 0x09},
> + {800, 0x19}, {850, 0x29}, {900, 0x39}, {950, 0x0a},
> + {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
> + {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
> + {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
> + };
> +
> + /* Shutdown mode */
> + rk_mipi_dsi_write(regs, PHY_SHUTDOWNZ, 0);
> + rk_mipi_dsi_write(regs, PHY_RSTZ, 0);
> + rk_mipi_dsi_write(regs, PHY_TESTCLR, 1);
> +
> + /* Pll locking */
> + rk_mipi_dsi_write(regs, PHY_TESTCLR, 0);
> +
> + /* config cp and lfp */
> + test_data[0] = 0x80 | (ddr_clk / (200 * MHZ)) << 3 | 0x3;
> + rk_mipi_phy_write(regs, CODE_PLL_VCORANGE_VCOCAP, test_data, 1);
> +
> + test_data[0] = 0x8;
> + rk_mipi_phy_write(regs, CODE_PLL_CPCTRL, test_data, 1);
> +
> + test_data[0] = 0x80 | 0x40;
> + rk_mipi_phy_write(regs, CODE_PLL_LPF_CP, test_data, 1);
> +
> + /* select the suitable value for fsfreqrang reg */
> + for (i = 0; i < ARRAY_SIZE(freq_rang); i++) {
> + if (ddr_clk / (MHZ) >= freq_rang[i][0])
> + break;
> + }
> + if (i == ARRAY_SIZE(freq_rang)) {
> + debug("%s@%d: Dphy freq out of range!\n", __func__, __LINE__);
> + return -EINVAL;
> + }
> + test_data[0] = freq_rang[i][1] << 1;
> + rk_mipi_phy_write(regs, CODE_HS_RX_LANE0, test_data, 1);
> +
> + /*
> + * Calculate the best ddrclk and it's corresponding div value. If the
> + * given pixelclock is great than 250M, ddrclk will be fix 1500M.
> + * Otherwise,
> + * it's equal to ddr_clk= pixclk * 6. 40MHZ >= refclk / prediv >= 5MHZ
> + * according to spec.
> + */
> + max_prediv = (refclk / (5 * MHZ));
> + min_prediv = ((refclk / (40 * MHZ)) ? (refclk / (40 * MHZ) + 1) : 1);
> +
> + debug("%s@%d:DEBUG: MAX_PREDIV=%u, MIN_PREDIV=%u\n", __func__, __LINE__,
> + max_prediv, min_prediv);
> +
> + if (max_prediv < min_prediv) {
> + debug("%s@%d: Err: Invalid refclk value\n", __func__, __LINE__);
> + return -EINVAL;
> + }
> +
> + /* Calculate the best refclk and feedback division value for dphy pll */
> + for (i = min_prediv; i < max_prediv; i++) {
> + if ((ddr_clk * i % refclk < remain) &&
> + (ddr_clk * i / refclk) < max_fbdiv) {
> + prediv = i;
> + remain = ddr_clk * i % refclk;
> + }
> + }
> + fbdiv = ddr_clk * prediv / refclk;
> + ddr_clk = refclk * fbdiv / prediv;
> + priv->dsi->phy_clk = ddr_clk;
> +
> + debug("%s@%d: DEBUG: refclk=%u, refclk=%llu, fbdiv=%llu, phyclk=%llu\n",
> + __func__, __LINE__, refclk, prediv, fbdiv, ddr_clk);
> +
> + /* config prediv and feedback reg */
> + test_data[0] = prediv - 1;
> + rk_mipi_phy_write(regs, CODE_PLL_INPUT_DIV_RAT, test_data, 1);
> + test_data[0] = (fbdiv - 1) & 0x1f;
> + rk_mipi_phy_write(regs, CODE_PLL_LOOP_DIV_RAT, test_data, 1);
> + test_data[0] = (fbdiv - 1) >> 5 | 0x80;
> + rk_mipi_phy_write(regs, CODE_PLL_LOOP_DIV_RAT, test_data, 1);
> + test_data[0] = 0x30;
> + rk_mipi_phy_write(regs, CODE_PLL_INPUT_LOOP_DIV_RAT, test_data, 1);
> +
> + /* rest config */
> + test_data[0] = 0x4d;
> + rk_mipi_phy_write(regs, CODE_BANDGAP_BIAS_CTRL, test_data, 1);
> +
> + test_data[0] = 0x3d;
> + rk_mipi_phy_write(regs, CODE_TERMINATION_CTRL, test_data, 1);
> +
> + test_data[0] = 0xdf;
> + rk_mipi_phy_write(regs, CODE_TERMINATION_CTRL, test_data, 1);
> +
> + test_data[0] = 0x7;
> + rk_mipi_phy_write(regs, CODE_AFE_BIAS_BANDGAP_ANOLOG, test_data, 1);
> +
> + test_data[0] = 0x80 | 0x7;
> + rk_mipi_phy_write(regs, CODE_AFE_BIAS_BANDGAP_ANOLOG, test_data, 1);
> +
> + test_data[0] = 0x80 | 15;
> + rk_mipi_phy_write(regs, CODE_HSTXDATALANEREQUSETSTATETIME,
> + test_data, 1);
> + test_data[0] = 0x80 | 85;
> + rk_mipi_phy_write(regs, CODE_HSTXDATALANEPREPARESTATETIME,
> + test_data, 1);
> + test_data[0] = 0x40 | 10;
> + rk_mipi_phy_write(regs, CODE_HSTXDATALANEHSZEROSTATETIME,
> + test_data, 1);
> +
> + /* enter into stop mode */
> + rk_mipi_dsi_write(regs, N_LANES, 0x03);
> + rk_mipi_dsi_write(regs, PHY_ENABLECLK, 1);
> + rk_mipi_dsi_write(regs, PHY_FORCEPLL, 1);
> + rk_mipi_dsi_write(regs, PHY_SHUTDOWNZ, 1);
> + rk_mipi_dsi_write(regs, PHY_RSTZ, 1);
> +
> + return 0;
> +}
> +
> +static int rk_mipi_enable(struct udevice *dev, int panel_bpp,
> + const struct display_timing *timing)
> +{
Please add a comment as to why this does nothing
> + return 0;
> +}
> +
> +static int rk_mipi_ofdata_to_platdata(struct udevice *dev)
> +{
> + struct rk_mipi_priv *priv = dev_get_priv(dev);
> +
> + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> + if (!priv->grf) {
> + debug("%s@%d: Get syscon ref fail\n", __func__, __LINE__);
> + return -ENXIO;
> + }
> + priv->regs = (void *)dev_get_addr(dev);
> + if (!priv->regs) {
> + debug("%s@%d: Get MIPI dsi address fail\n", __func__, __LINE__);
> + return -ENXIO;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Probe function: check panel existence and readingit's timing. Then config
> + * mipi dsi controller and enable it according to the timing parameter.
> + */
> +static int rk_mipi_probe(struct udevice *dev)
> +{
> + struct rk_mipi_priv *priv = dev_get_priv(dev);
> + struct display_timing timing;
> + int ret;
> +
> + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
> + &priv->panel);
> + if (ret) {
> + debug("Err:Can't find panel@%s, ret = %d\n", __func__, ret);
> + return ret;
> + }
> + /* Read panel timing,and save to struct timing */
> + rk_mipi_read_timing(dev, &timing);
> +
> + /* fill the mipi controller parameter */
> + priv->dsi->ref_clk = 24*MHZ;
> + priv->dsi->sys_clk = priv->dsi->ref_clk;
> + priv->dsi->pix_clk = timing.pixelclock.typ;
> + priv->dsi->phy_clk = priv->dsi->pix_clk * 6;
> + priv->dsi->txbyte_clk = priv->dsi->phy_clk / 8;
> + priv->dsi->txesc_clk = 20*MHZ;
> +
> + /* config mipi dsi according to timing and enable it */
> + ret = rk_mipi_dsi_enable(dev, &timing);
> + if (ret) {
> + debug("Err: mipi dsi enable fail@%s,ret=%d\n", __func__, ret);
How about:
debug("%s: rk_mipi_dsi_enable() failed (err=%d)", __func__, ret)
> + return ret;
> + }
> +
> + /* init mipi dsi phy */
> + ret = rk_mipi_phy_enable(dev);
> + if (ret) {
> + debug("Err: mipi phy enable fail@%s,ret=%d\n", __func__, ret);
> + return ret;
> + }
> +
> + /* enable backlight */
> + ret = panel_enable_backlight(priv->panel);
> + if (ret) {
> + debug("Err: fail to enable bg@%s,ret=%d\n", __func__, ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct dm_display_ops rk_mipi_dsi_ops = {
> + .read_timing = rk_mipi_read_timing,
> + .enable = rk_mipi_enable,
> +};
> +
> +static const struct udevice_id rk_mipi_dsi_ids[] = {
> + { .compatible = "rockchip,rk3399_mipi_dsi" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(rk_mipi_dsi) = {
> + .name = "rk_mipi_dsi",
> + .id = UCLASS_DISPLAY,
> + .of_match = rk_mipi_dsi_ids,
> + .ofdata_to_platdata = rk_mipi_ofdata_to_platdata,
> + .probe = rk_mipi_probe,
> + .ops = &rk_mipi_dsi_ops,
> + .priv_auto_alloc_size = sizeof(struct rk_mipi_priv),
> +};
> diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
> index aeecb58..2ea7954 100644
> --- a/drivers/video/rockchip/rk_vop.c
> +++ b/drivers/video/rockchip/rk_vop.c
> @@ -109,6 +109,10 @@ void rkvop_mode_set(struct rk3288_vop *regs,
> clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
> V_HDMI_OUT_EN(1));
> break;
> + case VOP_MODE_MIPI:
> + clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
> + V_MIPI_OUT_EN(1));
> + break;
> case VOP_MODE_EDP:
> default:
> clrsetbits_le32(®s->sys_ctrl, M_ALL_OUT_EN,
> @@ -178,13 +182,11 @@ void rkvop_mode_set(struct rk3288_vop *regs,
> *
> * @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)
> +int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node)
> {
> struct video_priv *uc_priv = dev_get_uclass_priv(dev);
> const void *blob = gd->fdt_blob;
> @@ -196,6 +198,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
> int ret, remote, i, offset;
> struct display_plat *disp_uc_plat;
> struct clk clk;
> + enum video_log2_bpp l2bpp;
>
> vop_id = fdtdec_get_int(blob, ep_node, "reg", -1);
> debug("vop_id=%d\n", vop_id);
> @@ -245,11 +248,26 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
> ret = clk_get_by_index(dev, 1, &clk);
> if (!ret)
> ret = clk_set_rate(&clk, timing.pixelclock.typ);
> - if (ret) {
> + /* clk_set_rate return clk rate,normally it is a none zero value */
> + if (!ret) {
> debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret);
> return ret;
> }
>
> + /* Set bitwidth for vop display according to vop mode */
> + switch (vop_id) {
> + case VOP_MODE_EDP:
> + case VOP_MODE_HDMI:
> + case VOP_MODE_LVDS:
> + l2bpp = VIDEO_BPP16;
> + break;
> + case VOP_MODE_MIPI:
> + l2bpp = VIDEO_BPP32;
> + break;
> + default:
> + l2bpp = VIDEO_BPP16;
> + }
> +
> rkvop_mode_set(regs, &timing, vop_id);
>
> rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
> @@ -327,7 +345,7 @@ static int rk_vop_probe(struct udevice *dev)
> 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);
> + ret = rk_display_init(dev, plat->base, node);
> if (ret)
> debug("Device failed: ret=%d\n", ret);
> if (!ret)
> @@ -342,7 +360,13 @@ static int rk_vop_bind(struct udevice *dev)
> {
> struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
>
> - plat->size = 1920 * 1080 * 2;
> +/*
> + * plat->size is only used for reserve fb space in memory befor relocation.
> + * So we just need to make sure it's big enough for all condition. And
> + * actually, we now know nothing about the display port type, color depth
> + * and it's resolution ratio. So we can't calculate fb size accurately.
> + */
> + plat->size = 1920 * 1200 * 4;
>
> return 0;
> }
> @@ -351,6 +375,8 @@ static const struct video_ops rk_vop_ops = {
> };
>
> static const struct udevice_id rk_vop_ids[] = {
> + { .compatible = "rockchip,rk3399-vop-big" },
> + { .compatible = "rockchip,rk3399-vop-lit" },
> { .compatible = "rockchip,rk3288-vop" },
> { }
> };
> --
> 1.9.1
>
>
Regards,
Simon
More information about the U-Boot
mailing list