rockchip/rk3399: Add MIPI driver
This patch configures clock for mipi and then adds mipi driver for support innolux-p079zca mipi panel in rk3399 scarlet. Change-Id: I02475eefb187c619c614b1cd20e97074bc8d917f Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com> Reviewed-on: https://review.coreboot.org/19477 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
2684efc492
commit
fe122d4dfc
|
@ -119,6 +119,7 @@ enum vop_modes {
|
||||||
*/
|
*/
|
||||||
VOP_MODE_EDP = 0,
|
VOP_MODE_EDP = 0,
|
||||||
VOP_MODE_HDMI,
|
VOP_MODE_HDMI,
|
||||||
|
VOP_MODE_MIPI,
|
||||||
VOP_MODE_NONE,
|
VOP_MODE_NONE,
|
||||||
VOP_MODE_AUTO_DETECT,
|
VOP_MODE_AUTO_DETECT,
|
||||||
VOP_MODE_UNKNOWN,
|
VOP_MODE_UNKNOWN,
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <soc/edp.h>
|
#include <soc/edp.h>
|
||||||
#include <soc/vop.h>
|
#include <soc/vop.h>
|
||||||
|
|
||||||
|
|
||||||
static struct rockchip_vop_regs * const vop_regs[] = {
|
static struct rockchip_vop_regs * const vop_regs[] = {
|
||||||
(struct rockchip_vop_regs *)VOP_BIG_BASE,
|
(struct rockchip_vop_regs *)VOP_BIG_BASE,
|
||||||
(struct rockchip_vop_regs *)VOP_LIT_BASE
|
(struct rockchip_vop_regs *)VOP_LIT_BASE
|
||||||
|
@ -109,6 +108,7 @@ void rkvop_mode_set(u32 vop_id, const struct edid *edid, u32 mode)
|
||||||
u32 vfront_porch = edid->mode.vso;
|
u32 vfront_porch = edid->mode.vso;
|
||||||
u32 vsync_len = edid->mode.vspw;
|
u32 vsync_len = edid->mode.vspw;
|
||||||
u32 vback_porch = edid->mode.vbl - edid->mode.vso - edid->mode.vspw;
|
u32 vback_porch = edid->mode.vbl - edid->mode.vso - edid->mode.vspw;
|
||||||
|
u32 dsp_out_mode;
|
||||||
struct rockchip_vop_regs *preg = vop_regs[vop_id];
|
struct rockchip_vop_regs *preg = vop_regs[vop_id];
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
@ -116,17 +116,25 @@ void rkvop_mode_set(u32 vop_id, const struct edid *edid, u32 mode)
|
||||||
case VOP_MODE_HDMI:
|
case VOP_MODE_HDMI:
|
||||||
clrsetbits_le32(&preg->sys_ctrl,
|
clrsetbits_le32(&preg->sys_ctrl,
|
||||||
M_ALL_OUT_EN, V_HDMI_OUT_EN(1));
|
M_ALL_OUT_EN, V_HDMI_OUT_EN(1));
|
||||||
|
dsp_out_mode = 15;
|
||||||
|
break;
|
||||||
|
case VOP_MODE_MIPI:
|
||||||
|
clrsetbits_le32(&preg->sys_ctrl,
|
||||||
|
M_ALL_OUT_EN, V_MIPI_OUT_EN(1));
|
||||||
|
dsp_out_mode = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VOP_MODE_EDP:
|
case VOP_MODE_EDP:
|
||||||
default:
|
default:
|
||||||
clrsetbits_le32(&preg->sys_ctrl,
|
clrsetbits_le32(&preg->sys_ctrl,
|
||||||
M_ALL_OUT_EN, V_EDP_OUT_EN(1));
|
M_ALL_OUT_EN, V_EDP_OUT_EN(1));
|
||||||
|
dsp_out_mode = 15;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
clrsetbits_le32(&preg->dsp_ctrl0,
|
clrsetbits_le32(&preg->dsp_ctrl0,
|
||||||
M_DSP_OUT_MODE | M_DSP_VSYNC_POL | M_DSP_HSYNC_POL,
|
M_DSP_OUT_MODE | M_DSP_VSYNC_POL |
|
||||||
V_DSP_OUT_MODE(15) |
|
M_DSP_HSYNC_POL,
|
||||||
|
V_DSP_OUT_MODE(dsp_out_mode) |
|
||||||
V_DSP_HSYNC_POL(edid->mode.phsync == '+') |
|
V_DSP_HSYNC_POL(edid->mode.phsync == '+') |
|
||||||
V_DSP_VSYNC_POL(edid->mode.pvsync == '+'));
|
V_DSP_VSYNC_POL(edid->mode.pvsync == '+'));
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ ramstage-$(CONFIG_DRIVERS_UART) += ../common/uart.c
|
||||||
ramstage-y += clock.c
|
ramstage-y += clock.c
|
||||||
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display.c
|
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display.c
|
||||||
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += ../common/edp.c
|
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += ../common/edp.c
|
||||||
|
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += mipi.c
|
||||||
ramstage-y += ../common/gpio.c
|
ramstage-y += ../common/gpio.c
|
||||||
ramstage-y += gpio.c
|
ramstage-y += gpio.c
|
||||||
ramstage-y += ../common/i2c.c
|
ramstage-y += ../common/i2c.c
|
||||||
|
|
|
@ -26,6 +26,18 @@ struct soc_rockchip_rk3399_config {
|
||||||
u32 bl_pwm_to_enable_udelay;
|
u32 bl_pwm_to_enable_udelay;
|
||||||
u32 framebuffer_bits_per_pixel;
|
u32 framebuffer_bits_per_pixel;
|
||||||
u32 vop_mode;
|
u32 vop_mode;
|
||||||
|
u32 panel_pixel_clock; /* below only be considered for MIPI displays */
|
||||||
|
u32 panel_refresh;
|
||||||
|
u32 panel_ha;
|
||||||
|
u32 panel_hbl;
|
||||||
|
u32 panel_hso;
|
||||||
|
u32 panel_hspw;
|
||||||
|
u32 panel_va;
|
||||||
|
u32 panel_vbl;
|
||||||
|
u32 panel_vso;
|
||||||
|
u32 panel_vspw;
|
||||||
|
u32 panel_display_on_mdelay;
|
||||||
|
u32 panel_video_mode_mdelay;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __SOC_ROCKCHIP_RK3399_CHIP_H__ */
|
#endif /* __SOC_ROCKCHIP_RK3399_CHIP_H__ */
|
||||||
|
|
|
@ -953,3 +953,13 @@ void rkclk_configure_edp(unsigned int hz)
|
||||||
(src_clk_div - 1) <<
|
(src_clk_div - 1) <<
|
||||||
CLK_PCLK_EDP_DIV_CON_SHIFT));
|
CLK_PCLK_EDP_DIV_CON_SHIFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rkclk_configure_mipi(void)
|
||||||
|
{
|
||||||
|
/* Enable clk_mipidphy_ref and clk_mipidphy_cfg */
|
||||||
|
write32(&cru_ptr->clkgate_con[11],
|
||||||
|
RK_CLRBITS(1 << 14 | 1 << 15));
|
||||||
|
/* Enable pclk_mipi_dsi0 */
|
||||||
|
write32(&cru_ptr->clkgate_con[29],
|
||||||
|
RK_CLRBITS(1 << 1));
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <soc/gpio.h>
|
#include <soc/gpio.h>
|
||||||
#include <soc/grf.h>
|
#include <soc/grf.h>
|
||||||
#include <soc/mmu_operations.h>
|
#include <soc/mmu_operations.h>
|
||||||
|
#include <soc/mipi.h>
|
||||||
#include <soc/soc.h>
|
#include <soc/soc.h>
|
||||||
#include <soc/vop.h>
|
#include <soc/vop.h>
|
||||||
|
|
||||||
|
@ -47,6 +48,21 @@ static void reset_edp(void)
|
||||||
printk(BIOS_WARNING, "Retrying epd initialization.\n");
|
printk(BIOS_WARNING, "Retrying epd initialization.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rk_get_mipi_mode(struct edid *edid, device_t dev)
|
||||||
|
{
|
||||||
|
struct soc_rockchip_rk3399_config *conf = dev->chip_info;
|
||||||
|
|
||||||
|
edid->mode.pixel_clock = conf->panel_pixel_clock;
|
||||||
|
edid->mode.refresh = conf->panel_refresh;
|
||||||
|
edid->mode.ha = conf->panel_ha;
|
||||||
|
edid->mode.hbl = conf->panel_hbl;
|
||||||
|
edid->mode.hso = conf->panel_hso;
|
||||||
|
edid->mode.hspw = conf->panel_hspw;
|
||||||
|
edid->mode.va = conf->panel_va;
|
||||||
|
edid->mode.vbl = conf->panel_vbl;
|
||||||
|
edid->mode.vso = conf->panel_vso;
|
||||||
|
edid->mode.vspw = conf->panel_vspw;
|
||||||
|
}
|
||||||
void rk_display_init(device_t dev)
|
void rk_display_init(device_t dev)
|
||||||
{
|
{
|
||||||
struct edid edid;
|
struct edid edid;
|
||||||
|
@ -60,8 +76,6 @@ void rk_display_init(device_t dev)
|
||||||
switch (conf->vop_mode) {
|
switch (conf->vop_mode) {
|
||||||
case VOP_MODE_NONE:
|
case VOP_MODE_NONE:
|
||||||
return;
|
return;
|
||||||
case VOP_MODE_AUTO_DETECT:
|
|
||||||
/* try EDP first, then HDMI */
|
|
||||||
case VOP_MODE_EDP:
|
case VOP_MODE_EDP:
|
||||||
printk(BIOS_DEBUG, "Attempting to set up EDP display.\n");
|
printk(BIOS_DEBUG, "Attempting to set up EDP display.\n");
|
||||||
rkclk_configure_vop_aclk(vop_id, 200 * MHz);
|
rkclk_configure_vop_aclk(vop_id, 200 * MHz);
|
||||||
|
@ -91,11 +105,22 @@ retry_edp:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VOP_MODE_HDMI:
|
case VOP_MODE_MIPI:
|
||||||
printk(BIOS_WARNING, "HDMI display is NOT supported yet.\n");
|
printk(BIOS_DEBUG, "Attempting to setup MIPI display.\n");
|
||||||
return;
|
|
||||||
|
rkclk_configure_mipi();
|
||||||
|
rkclk_configure_vop_aclk(vop_id, 200 * MHz);
|
||||||
|
|
||||||
|
/* disable turnrequest turndisable forcetxstop forcerxmode */
|
||||||
|
write32(&rk3399_grf->soc_con22, RK_CLRBITS(0xffff));
|
||||||
|
/* select mipi-dsi0 signal from vop0 */
|
||||||
|
write32(&rk3399_grf->soc_con20, RK_CLRBITS(1 << 0));
|
||||||
|
|
||||||
|
rk_get_mipi_mode(&edid, dev);
|
||||||
|
detected_mode = VOP_MODE_MIPI;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printk(BIOS_WARNING, "Cannot read any EDID info, aborting.\n");
|
printk(BIOS_WARNING, "Unsupported vop_mode, aborting.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,20 +137,21 @@ retry_edp:
|
||||||
rkvop_prepare(vop_id, &edid);
|
rkvop_prepare(vop_id, &edid);
|
||||||
|
|
||||||
switch (detected_mode) {
|
switch (detected_mode) {
|
||||||
case VOP_MODE_HDMI:
|
case VOP_MODE_MIPI:
|
||||||
/* should not be here before HDMI supported */
|
rk_mipi_prepare(&edid, conf->panel_display_on_mdelay, conf->panel_video_mode_mdelay);
|
||||||
return;
|
break;
|
||||||
case VOP_MODE_EDP:
|
case VOP_MODE_EDP:
|
||||||
default:
|
|
||||||
/* will enable edp in depthcharge */
|
/* will enable edp in depthcharge */
|
||||||
if (rk_edp_prepare()) {
|
if (rk_edp_prepare()) {
|
||||||
reset_edp();
|
reset_edp();
|
||||||
goto retry_edp; /* Rerun entire init sequence */
|
goto retry_edp; /* Rerun entire init sequence */
|
||||||
}
|
}
|
||||||
mainboard_power_on_backlight();
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
mainboard_power_on_backlight();
|
||||||
set_vbe_mode_info_valid(&edid, (uintptr_t)0);
|
set_vbe_mode_info_valid(&edid, (uintptr_t)0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#define SARADC_BASE 0xff100000
|
#define SARADC_BASE 0xff100000
|
||||||
#define RK_PWM_BASE 0xff420000
|
#define RK_PWM_BASE 0xff420000
|
||||||
#define EDP_BASE 0xff970000
|
#define EDP_BASE 0xff970000
|
||||||
|
#define MIPI_BASE 0xff960000
|
||||||
|
|
||||||
#define VOP_BIG_BASE 0xff900000 /* corresponds to vop_id 0 */
|
#define VOP_BIG_BASE 0xff900000 /* corresponds to vop_id 0 */
|
||||||
#define VOP_LIT_BASE 0xff8f0000 /* corresponds to vop_id 1 */
|
#define VOP_LIT_BASE 0xff8f0000 /* corresponds to vop_id 1 */
|
||||||
|
|
|
@ -120,5 +120,6 @@ void rkclk_ddr_reset(u32 ch, u32 ctl, u32 phy);
|
||||||
int rkclk_was_watchdog_reset(void);
|
int rkclk_was_watchdog_reset(void);
|
||||||
uint32_t rkclk_i2c_clock_for_bus(unsigned bus);
|
uint32_t rkclk_i2c_clock_for_bus(unsigned bus);
|
||||||
void rkclk_configure_edp(unsigned int hz);
|
void rkclk_configure_edp(unsigned int hz);
|
||||||
|
void rkclk_configure_mipi(void);
|
||||||
|
|
||||||
#endif /* __SOC_ROCKCHIP_RK3399_CLOCK_H__ */
|
#endif /* __SOC_ROCKCHIP_RK3399_CLOCK_H__ */
|
||||||
|
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright 2017 Rockchip Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RK_MIPI_H
|
||||||
|
#define __RK_MIPI_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct rk_mipi_regs {
|
||||||
|
u32 dsi_version;
|
||||||
|
u32 dsi_pwr_up;
|
||||||
|
u32 dsi_clk_cfg;
|
||||||
|
u32 dsi_dpi_vcid;
|
||||||
|
u32 dsi_dpi_color_coding;
|
||||||
|
u32 dsi_dpi_cfg_pol;
|
||||||
|
u32 dsi_dpi_lp_cmd_tim;
|
||||||
|
u8 reserved0[0x28 - 0x18];
|
||||||
|
u32 dsi_pckhdl_cfg;
|
||||||
|
u8 reserved1[0x30 - 0x2c];
|
||||||
|
u32 dsi_mode_cfg;
|
||||||
|
u32 dsi_vid_mode_cfg;
|
||||||
|
u32 dsi_vid_pkt_size;
|
||||||
|
u32 dsi_vid_num_chumks;
|
||||||
|
u32 dsi_vid_null_pkt_size;
|
||||||
|
u32 dsi_vid_hsa_time;
|
||||||
|
u32 dsi_vid_hbp_time;
|
||||||
|
u32 dsi_vid_hline_time;
|
||||||
|
u32 dsi_vid_vsa_lines;
|
||||||
|
u32 dsi_vid_vbp_lines;
|
||||||
|
u32 dsi_vid_vfp_lines;
|
||||||
|
u32 dsi_vid_vactive_lines;
|
||||||
|
u32 dsi_edpi_cmd_size;
|
||||||
|
u32 dsi_cmd_mode_cfg;
|
||||||
|
u32 dsi_gen_hdr;
|
||||||
|
u32 dsi_gen_pld_data;
|
||||||
|
u32 dsi_cmd_pkt_status;
|
||||||
|
u32 dsi_to_cnt_cfg;
|
||||||
|
u8 reserved2[0x88 - 0x78];
|
||||||
|
u32 dsi_bta_to_cnt;
|
||||||
|
u32 reserved3;
|
||||||
|
u32 dsi_lpclk_ctrl;
|
||||||
|
u32 dsi_phy_tmr_lpclk_cfg;
|
||||||
|
u32 dsi_phy_tmr_cfg;
|
||||||
|
u32 dsi_phy_rstz;
|
||||||
|
u32 dsi_phy_if_cfg;
|
||||||
|
u8 reserved4[0xac - 0xa4];
|
||||||
|
u32 dsi_phy_status;
|
||||||
|
u32 dsi_phy_tst_ctrl0;
|
||||||
|
u32 dsi_phy_tst_ctrl1;
|
||||||
|
u32 dsi_int_st0;
|
||||||
|
u32 dsi_int_st1;
|
||||||
|
u32 dsi_int_msk0;
|
||||||
|
u32 dsi_int_msk1;
|
||||||
|
};
|
||||||
|
check_member(rk_mipi_regs, dsi_int_msk1, 0xc8);
|
||||||
|
|
||||||
|
#define RESET 0
|
||||||
|
#define POWERUP BIT(0)
|
||||||
|
|
||||||
|
#define TO_CLK_DIVIDSION(div) (((div) & 0xff) << 8)
|
||||||
|
#define TX_ESC_CLK_DIVIDSION(div) (((div) & 0xff) << 0)
|
||||||
|
|
||||||
|
#define EN18_LOOSELY BIT(8)
|
||||||
|
#define DPI_COLOR_CODING_16BIT_1 0x0
|
||||||
|
#define DPI_COLOR_CODING_16BIT_2 0x1
|
||||||
|
#define DPI_COLOR_CODING_16BIT_3 0x2
|
||||||
|
#define DPI_COLOR_CODING_18BIT_1 0x3
|
||||||
|
#define DPI_COLOR_CODING_18BIT_2 0x4
|
||||||
|
#define DPI_COLOR_CODING_24BIT 0x5
|
||||||
|
|
||||||
|
#define COLORM_ACTIVE_LOW BIT(4)
|
||||||
|
#define SHUTD_ACTIVE_LOW BIT(3)
|
||||||
|
#define HSYNC_ACTIVE_LOW BIT(2)
|
||||||
|
#define VSYNC_ACTIVE_LOW BIT(1)
|
||||||
|
#define DATAEN_ACTIVE_LOW BIT(0)
|
||||||
|
|
||||||
|
#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16)
|
||||||
|
#define INVACT_LPCMD_TIME(p) ((p) & 0xff)
|
||||||
|
|
||||||
|
#define EN_CRC_RX BIT(4)
|
||||||
|
#define EN_ECC_RX BIT(3)
|
||||||
|
#define EN_BTA BIT(2)
|
||||||
|
#define EN_EOTP_RX BIT(1)
|
||||||
|
#define EN_EOTP_TX BIT(0)
|
||||||
|
|
||||||
|
#define ENABLE_VIDEO_MODE 0
|
||||||
|
#define ENABLE_CMD_MODE BIT(0)
|
||||||
|
|
||||||
|
#define FRAME_BTA_ACK BIT(14)
|
||||||
|
#define ENABLE_LOW_POWER (0x3f << 8)
|
||||||
|
#define ENABLE_LOW_POWER_MASK (0x3f << 8)
|
||||||
|
#define VID_MODE_TYPE_BURST_SYNC_PULSES 0x0
|
||||||
|
#define VID_MODE_TYPE_BURST_SYNC_EVENTS 0x1
|
||||||
|
#define VID_MODE_TYPE_BURST 0x2
|
||||||
|
|
||||||
|
#define VID_PKT_SIZE(p) (((p) & 0x3fff) << 0)
|
||||||
|
#define VID_PKT_MAX_SIZE 0x3fff
|
||||||
|
|
||||||
|
#define MAX_RD_PKT_SIZE_LP BIT(24)
|
||||||
|
#define DCS_LW_TX_LP BIT(19)
|
||||||
|
#define DCS_SR_0P_TX_LP BIT(18)
|
||||||
|
#define DCS_SW_1P_TX_LP BIT(17)
|
||||||
|
#define DCS_SW_0P_TX_LP BIT(16)
|
||||||
|
#define GEN_LW_TX_LP BIT(14)
|
||||||
|
#define GEN_SR_2P_TX_LP BIT(13)
|
||||||
|
#define GEN_SR_1P_TX_LP BIT(12)
|
||||||
|
#define GEN_SR_0P_TX_LP BIT(11)
|
||||||
|
#define GEN_SW_2P_TX_LP BIT(10)
|
||||||
|
#define GEN_SW_1P_TX_LP BIT(9)
|
||||||
|
#define GEN_SW_0P_TX_LP BIT(8)
|
||||||
|
#define EN_ACK_RQST BIT(1)
|
||||||
|
#define EN_TEAR_FX BIT(0)
|
||||||
|
|
||||||
|
#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \
|
||||||
|
DCS_LW_TX_LP | \
|
||||||
|
DCS_SR_0P_TX_LP | \
|
||||||
|
DCS_SW_1P_TX_LP | \
|
||||||
|
DCS_SW_0P_TX_LP | \
|
||||||
|
GEN_LW_TX_LP | \
|
||||||
|
GEN_SR_2P_TX_LP | \
|
||||||
|
GEN_SR_1P_TX_LP | \
|
||||||
|
GEN_SR_0P_TX_LP | \
|
||||||
|
GEN_SW_2P_TX_LP | \
|
||||||
|
GEN_SW_1P_TX_LP | \
|
||||||
|
GEN_SW_0P_TX_LP)
|
||||||
|
|
||||||
|
#define GEN_HDATA(data) (((data) & 0xffff) << 8)
|
||||||
|
#define GEN_HDATA_MASK (0xffff << 8)
|
||||||
|
#define GEN_HTYPE(type) (((type) & 0xff) << 0)
|
||||||
|
#define GEN_HTYPE_MASK 0xff
|
||||||
|
|
||||||
|
#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16)
|
||||||
|
#define LPRX_TO_CNT(p) ((p) & 0xffff)
|
||||||
|
|
||||||
|
#define AUTO_CLKLANE_CTRL BIT(1)
|
||||||
|
#define PHY_TXREQUESTCLKHS BIT(0)
|
||||||
|
|
||||||
|
#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16)
|
||||||
|
#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff)
|
||||||
|
|
||||||
|
#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24)
|
||||||
|
#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16)
|
||||||
|
#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff)
|
||||||
|
|
||||||
|
#define PHY_DISFORCEPLL 0
|
||||||
|
#define PHY_ENFORCEPLL BIT(3)
|
||||||
|
#define PHY_DISABLECLK 0
|
||||||
|
#define PHY_ENABLECLK BIT(2)
|
||||||
|
#define PHY_RSTZ 0
|
||||||
|
#define PHY_UNRSTZ BIT(1)
|
||||||
|
#define PHY_SHUTDOWNZ 0
|
||||||
|
#define PHY_UNSHUTDOWNZ BIT(0)
|
||||||
|
|
||||||
|
#define N_LANES(n) ((((n) - 1) & 0x3) << 0)
|
||||||
|
#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8)
|
||||||
|
|
||||||
|
#define LOCK BIT(0)
|
||||||
|
#define STOP_STATE_CLK_LANE BIT(2)
|
||||||
|
|
||||||
|
#define PHY_TESTCLK BIT(1)
|
||||||
|
#define PHY_UNTESTCLK 0
|
||||||
|
#define PHY_TESTCLR BIT(0)
|
||||||
|
#define PHY_UNTESTCLR 0
|
||||||
|
|
||||||
|
#define PHY_TESTEN BIT(16)
|
||||||
|
#define PHY_UNTESTEN 0
|
||||||
|
#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
|
||||||
|
#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
|
||||||
|
|
||||||
|
#define BYPASS_VCO_RANGE BIT(7)
|
||||||
|
#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
|
||||||
|
#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
|
||||||
|
#define VCO_IN_CAP_CON_LOW (0x1 << 1)
|
||||||
|
#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
|
||||||
|
#define REF_BIAS_CUR_SEL BIT(0)
|
||||||
|
|
||||||
|
#define CP_CURRENT_3MA BIT(3)
|
||||||
|
#define CP_PROGRAM_EN BIT(7)
|
||||||
|
#define LPF_PROGRAM_EN BIT(6)
|
||||||
|
#define LPF_RESISTORS_20_KOHM 0
|
||||||
|
|
||||||
|
#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
|
||||||
|
|
||||||
|
#define INPUT_DIVIDER(val) ((val - 1) & 0x7f)
|
||||||
|
#define LOW_PROGRAM_EN 0
|
||||||
|
#define HIGH_PROGRAM_EN BIT(7)
|
||||||
|
#define LOOP_DIV_LOW_SEL(val) ((val - 1) & 0x1f)
|
||||||
|
#define LOOP_DIV_HIGH_SEL(val) (((val - 1) >> 5) & 0x1f)
|
||||||
|
#define PLL_LOOP_DIV_EN BIT(5)
|
||||||
|
#define PLL_INPUT_DIV_EN BIT(4)
|
||||||
|
|
||||||
|
#define POWER_CONTROL BIT(6)
|
||||||
|
#define INTERNAL_REG_CURRENT BIT(3)
|
||||||
|
#define BIAS_BLOCK_ON BIT(2)
|
||||||
|
#define BANDGAP_ON BIT(0)
|
||||||
|
|
||||||
|
#define TER_RESISTOR_HIGH BIT(7)
|
||||||
|
#define TER_RESISTOR_LOW 0
|
||||||
|
#define LEVEL_SHIFTERS_ON BIT(6)
|
||||||
|
#define TER_CAL_DONE BIT(5)
|
||||||
|
#define SETRD_MAX (0x7 << 2)
|
||||||
|
#define POWER_MANAGE BIT(1)
|
||||||
|
#define TER_RESISTORS_ON BIT(0)
|
||||||
|
|
||||||
|
#define BIASEXTR_SEL(val) ((val) & 0x7)
|
||||||
|
#define BANDGAP_SEL(val) ((val) & 0x7)
|
||||||
|
#define TLP_PROGRAM_EN BIT(7)
|
||||||
|
#define THS_PRE_PROGRAM_EN BIT(7)
|
||||||
|
#define THS_ZERO_PROGRAM_EN BIT(6)
|
||||||
|
|
||||||
|
#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
|
||||||
|
#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
|
||||||
|
#define PLL_LPF_AND_CP_CONTROL 0x12
|
||||||
|
#define PLL_INPUT_DIVIDER_RATIO 0x17
|
||||||
|
#define PLL_LOOP_DIVIDER_RATIO 0x18
|
||||||
|
#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
|
||||||
|
#define BANDGAP_AND_BIAS_CONTROL 0x20
|
||||||
|
#define TERMINATION_RESISTER_CONTROL 0x21
|
||||||
|
#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
|
||||||
|
#define HS_RX_CONTROL_OF_LANE_0 0x44
|
||||||
|
|
||||||
|
enum mipi_dsi_pixel_format {
|
||||||
|
MIPI_DSI_FMT_RGB888,
|
||||||
|
MIPI_DSI_FMT_RGB666,
|
||||||
|
MIPI_DSI_FMT_RGB666_PACKED,
|
||||||
|
MIPI_DSI_FMT_RGB565,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BANDGAP_97_07,
|
||||||
|
BANDGAP_98_05,
|
||||||
|
BANDGAP_99_02,
|
||||||
|
BANDGAP_100_00,
|
||||||
|
BANDGAP_93_17,
|
||||||
|
BANDGAP_94_15,
|
||||||
|
BANDGAP_95_12,
|
||||||
|
BANDGAP_96_10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BIASEXTR_87_1,
|
||||||
|
BIASEXTR_91_5,
|
||||||
|
BIASEXTR_95_9,
|
||||||
|
BIASEXTR_100,
|
||||||
|
BIASEXTR_105_94,
|
||||||
|
BIASEXTR_111_88,
|
||||||
|
BIASEXTR_118_8,
|
||||||
|
BIASEXTR_127_7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rk_mipi_dsi_mode {
|
||||||
|
MIPI_DSI_CMD_MODE,
|
||||||
|
MIPI_DSI_VID_MODE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MIPI_DCS_NOP = 0x00,
|
||||||
|
MIPI_DCS_EXIT_SLEEP_MODE = 0x11,
|
||||||
|
MIPI_DCS_SET_DISPLAY_ON = 0x29,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dphy_pll_testdin_map {
|
||||||
|
unsigned int max_mbps;
|
||||||
|
u8 testdin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rk_mipi_dsi {
|
||||||
|
u64 lane_bps; /* per lane */
|
||||||
|
u32 lanes;
|
||||||
|
u32 format;
|
||||||
|
u16 input_div;
|
||||||
|
u16 feedback_div;
|
||||||
|
};
|
||||||
|
|
||||||
|
void rk_mipi_prepare(const struct edid *edid, u32 display_on_mdelay, u32 video_mode_mdelay);
|
||||||
|
#endif
|
|
@ -0,0 +1,436 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright 2017 Rockchip Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <device/device.h>
|
||||||
|
#include <edid.h>
|
||||||
|
#include <gpio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/clock.h>
|
||||||
|
#include <soc/display.h>
|
||||||
|
#include <soc/mipi.h>
|
||||||
|
#include <soc/soc.h>
|
||||||
|
#include <timer.h>
|
||||||
|
|
||||||
|
static struct rk_mipi_dsi rk_mipi;
|
||||||
|
static struct rk_mipi_regs *mipi_regs = (void *)MIPI_BASE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The controller should generate 2 frames before
|
||||||
|
* preparing the peripheral.
|
||||||
|
*/
|
||||||
|
static void rk_mipi_dsi_wait_for_two_frames(struct rk_mipi_dsi *dsi,
|
||||||
|
const struct edid *edid)
|
||||||
|
{
|
||||||
|
int two_frames;
|
||||||
|
unsigned int refresh = edid->mode.refresh;
|
||||||
|
|
||||||
|
two_frames = div_round_up(MSECS_PER_SEC * 2, refresh);
|
||||||
|
mdelay(two_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dphy_pll_testdin_map dptdin_map[] = {
|
||||||
|
{ 90, 0x00}, { 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}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int max_mbps_to_testdin(unsigned int max_mbps)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
|
||||||
|
if (dptdin_map[i].max_mbps > max_mbps)
|
||||||
|
return dptdin_map[i].testdin;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_phy_write(struct rk_mipi_dsi *dsi,
|
||||||
|
u8 test_code,
|
||||||
|
u8 test_data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
|
||||||
|
* is latched internally as the current test code. Test data is
|
||||||
|
* programmed internally by rising edge on TESTCLK.
|
||||||
|
*/
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLK | PHY_UNTESTCLR);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl1, PHY_TESTEN | PHY_TESTDOUT(0) |
|
||||||
|
PHY_TESTDIN(test_code));
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLK | PHY_UNTESTCLR);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
|
||||||
|
PHY_TESTDIN(test_data));
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLK | PHY_UNTESTCLR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
int ret, testdin, vco;
|
||||||
|
|
||||||
|
int lane_mbps = div_round_up(dsi->lane_bps, USECS_PER_SEC);
|
||||||
|
vco = (lane_mbps < 200) ? 0 : (lane_mbps + 100) / 200;
|
||||||
|
|
||||||
|
testdin = max_mbps_to_testdin(lane_mbps);
|
||||||
|
if (testdin < 0) {
|
||||||
|
printk(BIOS_DEBUG, "failed to get testdin for %dmbps\n",
|
||||||
|
lane_mbps);
|
||||||
|
return testdin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start by clearing PHY state */
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLR);
|
||||||
|
write32(&mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
|
||||||
|
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
|
||||||
|
BYPASS_VCO_RANGE |
|
||||||
|
VCO_RANGE_CON_SEL(vco) |
|
||||||
|
VCO_IN_CAP_CON_LOW |
|
||||||
|
REF_BIAS_CUR_SEL);
|
||||||
|
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
|
||||||
|
CP_CURRENT_3MA);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
|
||||||
|
CP_PROGRAM_EN |
|
||||||
|
LPF_PROGRAM_EN |
|
||||||
|
LPF_RESISTORS_20_KOHM);
|
||||||
|
|
||||||
|
rk_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
|
||||||
|
HSFREQRANGE_SEL(testdin));
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
|
||||||
|
INPUT_DIVIDER(dsi->input_div));
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
|
||||||
|
LOOP_DIV_LOW_SEL(dsi->feedback_div) |
|
||||||
|
LOW_PROGRAM_EN);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
|
||||||
|
LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
|
||||||
|
HIGH_PROGRAM_EN);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
|
||||||
|
PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
|
||||||
|
LOW_PROGRAM_EN |
|
||||||
|
BIASEXTR_SEL(BIASEXTR_127_7));
|
||||||
|
rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
|
||||||
|
HIGH_PROGRAM_EN |
|
||||||
|
BANDGAP_SEL(BANDGAP_96_10));
|
||||||
|
rk_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
|
||||||
|
POWER_CONTROL | INTERNAL_REG_CURRENT |
|
||||||
|
BIAS_BLOCK_ON | BANDGAP_ON);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
|
||||||
|
TER_RESISTOR_LOW | TER_CAL_DONE |
|
||||||
|
SETRD_MAX | TER_RESISTORS_ON);
|
||||||
|
rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
|
||||||
|
TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
|
||||||
|
SETRD_MAX | POWER_MANAGE |
|
||||||
|
TER_RESISTORS_ON);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_rstz, PHY_ENFORCEPLL | PHY_ENABLECLK |
|
||||||
|
PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
||||||
|
{
|
||||||
|
switch (fmt) {
|
||||||
|
case MIPI_DSI_FMT_RGB888:
|
||||||
|
case MIPI_DSI_FMT_RGB666:
|
||||||
|
return 24;
|
||||||
|
|
||||||
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
||||||
|
return 18;
|
||||||
|
|
||||||
|
case MIPI_DSI_FMT_RGB565:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi,
|
||||||
|
const struct edid *edid)
|
||||||
|
{
|
||||||
|
u32 i, pre;
|
||||||
|
u64 pclk, pllref, tmp, target_bps;
|
||||||
|
u32 m = 1, n = 1;
|
||||||
|
u32 max_bps = 1500 * MHz;
|
||||||
|
int bpp;
|
||||||
|
|
||||||
|
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
|
||||||
|
if (bpp < 0) {
|
||||||
|
printk(BIOS_DEBUG, "failed to get bpp for pixel format %d\n",
|
||||||
|
dsi->format);
|
||||||
|
return bpp;
|
||||||
|
}
|
||||||
|
pclk = edid->mode.pixel_clock * MSECS_PER_SEC;
|
||||||
|
/* take 1 / 0.8, since mbps must bigger than bandwidth of RGB */
|
||||||
|
target_bps = pclk / dsi->lanes * bpp / 8 * 10;
|
||||||
|
if (target_bps >= max_bps) {
|
||||||
|
printk(BIOS_DEBUG, "DPHY clock frequency is out of range\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pllref = OSC_HZ;
|
||||||
|
tmp = pllref;
|
||||||
|
/*
|
||||||
|
* The limits on the PLL divisor are:
|
||||||
|
*
|
||||||
|
* 5MHz <= (pllref / n) <= 40MHz
|
||||||
|
*/
|
||||||
|
for (i = pllref / (5 * MHz); i > div_round_up(pllref, 40 * MHz); i--) {
|
||||||
|
pre = pllref / i;
|
||||||
|
if ((tmp > (target_bps % pre)) && (target_bps / pre < 512)) {
|
||||||
|
tmp = target_bps % pre;
|
||||||
|
n = i;
|
||||||
|
m = target_bps / pre;
|
||||||
|
}
|
||||||
|
if (tmp == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dsi->lane_bps = pllref / n * m;
|
||||||
|
dsi->input_div = n;
|
||||||
|
dsi->feedback_div = m;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_dpi_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
u32 color = 0;
|
||||||
|
|
||||||
|
switch (dsi->format) {
|
||||||
|
case MIPI_DSI_FMT_RGB888:
|
||||||
|
color = DPI_COLOR_CODING_24BIT;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666:
|
||||||
|
color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
||||||
|
color = DPI_COLOR_CODING_18BIT_1;
|
||||||
|
break;
|
||||||
|
case MIPI_DSI_FMT_RGB565:
|
||||||
|
color = DPI_COLOR_CODING_16BIT_1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_dpi_vcid, 0);
|
||||||
|
write32(&mipi_regs->dsi_dpi_color_coding, color);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_dpi_cfg_pol, 0);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_dpi_lp_cmd_tim, OUTVACT_LPCMD_TIME(4) |
|
||||||
|
INVACT_LPCMD_TIME(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_packet_handler_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_pckhdl_cfg, EN_CRC_RX | EN_ECC_RX | EN_BTA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_video_mode_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_vid_mode_cfg,
|
||||||
|
VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_video_packet_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_vid_pkt_size, VID_PKT_SIZE(0x300));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_command_mode_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_to_cnt_cfg,
|
||||||
|
HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
|
||||||
|
write32(&mipi_regs->dsi_bta_to_cnt, 0xd00);
|
||||||
|
write32(&mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
|
||||||
|
write32(&mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get lane byte clock cycles. */
|
||||||
|
static u32 rk_mipi_dsi_get_hcomponent_lbcc(struct rk_mipi_dsi *dsi,
|
||||||
|
u32 hcomponent,
|
||||||
|
const struct edid *edid)
|
||||||
|
{
|
||||||
|
u32 lbcc;
|
||||||
|
u64 lbcc_tmp;
|
||||||
|
|
||||||
|
lbcc_tmp = hcomponent * dsi->lane_bps / (8 * MSECS_PER_SEC);
|
||||||
|
lbcc = div_round_up(lbcc_tmp, edid->mode.pixel_clock);
|
||||||
|
|
||||||
|
return lbcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_line_timer_config(struct rk_mipi_dsi *dsi,
|
||||||
|
const struct edid *edid)
|
||||||
|
{
|
||||||
|
u32 htotal, hsa, hbp, lbcc;
|
||||||
|
|
||||||
|
htotal = edid->mode.ha + edid->mode.hbl;
|
||||||
|
hsa = edid->mode.hspw;
|
||||||
|
hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw;
|
||||||
|
|
||||||
|
lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, htotal, edid);
|
||||||
|
write32(&mipi_regs->dsi_vid_hline_time, lbcc);
|
||||||
|
|
||||||
|
lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hsa, edid);
|
||||||
|
write32(&mipi_regs->dsi_vid_hsa_time, lbcc);
|
||||||
|
lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hbp, edid);
|
||||||
|
write32(&mipi_regs->dsi_vid_hbp_time, lbcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_vertical_timing_config(struct rk_mipi_dsi *dsi,
|
||||||
|
const struct edid *edid)
|
||||||
|
{
|
||||||
|
u32 vactive, vsa, vfp, vbp;
|
||||||
|
|
||||||
|
vactive = edid->mode.va;
|
||||||
|
vsa = edid->mode.vspw;
|
||||||
|
vfp = edid->mode.vso;
|
||||||
|
vbp = edid->mode.vbl - edid->mode.vso - edid->mode.vspw;
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_vid_vactive_lines, vactive);
|
||||||
|
write32(&mipi_regs->dsi_vid_vsa_lines, vsa);
|
||||||
|
write32(&mipi_regs->dsi_vid_vfp_lines, vfp);
|
||||||
|
write32(&mipi_regs->dsi_vid_vbp_lines, vbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_dphy_timing_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* HS-PREPARE: 40ns + 4 * UI ~ 85ns + 6 * UI
|
||||||
|
* HS-EXIT: 100ns
|
||||||
|
*/
|
||||||
|
write32(&mipi_regs->dsi_phy_tmr_cfg, PHY_HS2LP_TIME(0x40) |
|
||||||
|
PHY_LP2HS_TIME(0x40) |
|
||||||
|
MAX_RD_TIME(10000));
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_phy_tmr_lpclk_cfg, PHY_CLKHS2LP_TIME(0x40) |
|
||||||
|
PHY_CLKLP2HS_TIME(0x40));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_clear_err(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
read32(&mipi_regs->dsi_int_st0);
|
||||||
|
read32(&mipi_regs->dsi_int_st1);
|
||||||
|
write32(&mipi_regs->dsi_int_msk0, 0);
|
||||||
|
write32(&mipi_regs->dsi_int_msk1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_dphy_interface_config(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_phy_if_cfg, PHY_STOP_WAIT_TIME(0x20) |
|
||||||
|
N_LANES(dsi->lanes));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_set_mode(struct rk_mipi_dsi *dsi,
|
||||||
|
enum rk_mipi_dsi_mode mode)
|
||||||
|
{
|
||||||
|
write32(&mipi_regs->dsi_pwr_up, RESET);
|
||||||
|
if (mode == MIPI_DSI_CMD_MODE) {
|
||||||
|
write32(&mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
|
||||||
|
} else {
|
||||||
|
write32(&mipi_regs->dsi_mode_cfg, ENABLE_VIDEO_MODE);
|
||||||
|
rk_mipi_dsi_video_mode_config(dsi);
|
||||||
|
write32(&mipi_regs->dsi_lpclk_ctrl, PHY_TXREQUESTCLKHS);
|
||||||
|
}
|
||||||
|
write32(&mipi_regs->dsi_pwr_up, POWERUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rk_mipi_dsi_init(struct rk_mipi_dsi *dsi)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The maximum permitted escape clock is 20MHz and it is derived from
|
||||||
|
* lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
|
||||||
|
*
|
||||||
|
* (lane_mbps >> 3) / esc_clk_division < 20
|
||||||
|
* which is:
|
||||||
|
* (lane_mbps >> 3) / 20 > esc_clk_division
|
||||||
|
*/
|
||||||
|
u32 esc_clk_division = div_round_up(dsi->lane_bps, 8 * 20 * USECS_PER_SEC);
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_pwr_up, RESET);
|
||||||
|
write32(&mipi_regs->dsi_phy_rstz, PHY_DISFORCEPLL | PHY_DISABLECLK |
|
||||||
|
PHY_RSTZ | PHY_SHUTDOWNZ);
|
||||||
|
write32(&mipi_regs->dsi_clk_cfg,
|
||||||
|
TO_CLK_DIVIDSION(10) |
|
||||||
|
TX_ESC_CLK_DIVIDSION(esc_clk_division));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk_mipi_dsi_dcs_transfer(struct rk_mipi_dsi *dsi, u32 hdr_val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
hdr_val = GEN_HDATA(hdr_val) | GEN_HTYPE(0x05);
|
||||||
|
ret = read32(&mipi_regs->dsi_cmd_pkt_status);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk(BIOS_DEBUG, "failed to get available command FIFO\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
write32(&mipi_regs->dsi_lpclk_ctrl, 0);
|
||||||
|
write32(&mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
|
||||||
|
write32(&mipi_regs->dsi_gen_hdr, hdr_val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk_mipi_prepare(const struct edid *edid, u32 display_on_mdelay, u32 video_mode_mdelay)
|
||||||
|
{
|
||||||
|
rk_mipi.lanes = 4;
|
||||||
|
rk_mipi.format = MIPI_DSI_FMT_RGB888;
|
||||||
|
if (rk_mipi_dsi_get_lane_bps(&rk_mipi, edid) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rk_mipi_dsi_init(&rk_mipi);
|
||||||
|
rk_mipi_dsi_dpi_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_packet_handler_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_video_mode_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_video_packet_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_command_mode_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_line_timer_config(&rk_mipi, edid);
|
||||||
|
rk_mipi_dsi_vertical_timing_config(&rk_mipi, edid);
|
||||||
|
rk_mipi_dsi_dphy_timing_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_dphy_interface_config(&rk_mipi);
|
||||||
|
rk_mipi_dsi_clear_err(&rk_mipi);
|
||||||
|
rk_mipi_dsi_phy_init(&rk_mipi);
|
||||||
|
rk_mipi_dsi_wait_for_two_frames(&rk_mipi, edid);
|
||||||
|
|
||||||
|
rk_mipi_dsi_set_mode(&rk_mipi, MIPI_DSI_CMD_MODE);
|
||||||
|
if (rk_mipi_dsi_dcs_transfer(&rk_mipi, MIPI_DCS_EXIT_SLEEP_MODE) < 0)
|
||||||
|
return;
|
||||||
|
mdelay(display_on_mdelay);
|
||||||
|
if (rk_mipi_dsi_dcs_transfer(&rk_mipi, MIPI_DCS_SET_DISPLAY_ON) < 0)
|
||||||
|
return;
|
||||||
|
mdelay(video_mode_mdelay);
|
||||||
|
|
||||||
|
rk_mipi_dsi_set_mode(&rk_mipi, MIPI_DSI_VID_MODE);
|
||||||
|
}
|
Loading…
Reference in New Issue