rockchip/rk3399: support dual mipi dsi
Refactor the mipi driver, so we can support dual mipi panel. And pass the panel data from mainboard.c, that we can support different panel with different board. Change-Id: Id1286c0ccbe50c89514c8daee66439116d3f1ca4 Signed-off-by: Lin Huang <hl@rock-chips.com> Reviewed-on: https://review.coreboot.org/22471 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Brian Norris <briannorris@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
45f1b01324
commit
25fb09b068
|
@ -17,16 +17,4 @@ chip soc/rockchip/rk3399
|
|||
device cpu_cluster 0 on end
|
||||
register "vop_mode" = "VOP_MODE_MIPI"
|
||||
register "framebuffer_bits_per_pixel" = "32"
|
||||
register "panel_pixel_clock" = "56900"
|
||||
register "panel_refresh" = "60"
|
||||
register "panel_ha" = "768"
|
||||
register "panel_hbl" = "120"
|
||||
register "panel_hso" = "40"
|
||||
register "panel_hspw" = "40"
|
||||
register "panel_va" = "1024"
|
||||
register "panel_vbl" = "44"
|
||||
register "panel_vso" = "20"
|
||||
register "panel_vspw" = "4"
|
||||
register "panel_display_on_mdelay" = "120"
|
||||
register "panel_video_mode_mdelay" = "5"
|
||||
end
|
||||
|
|
|
@ -375,6 +375,11 @@ void mainboard_power_on_backlight(void)
|
|||
prepare_backlight_i2c();
|
||||
}
|
||||
|
||||
const struct mipi_panel_data *mainboard_get_mipi_mode(struct edid *edid)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void mainboard_enable(device_t dev)
|
||||
{
|
||||
dev->ops->init = &mainboard_init;
|
||||
|
|
|
@ -120,6 +120,7 @@ enum vop_modes {
|
|||
VOP_MODE_EDP = 0,
|
||||
VOP_MODE_HDMI,
|
||||
VOP_MODE_MIPI,
|
||||
VOP_MODE_DUAL_MIPI,
|
||||
VOP_MODE_NONE,
|
||||
VOP_MODE_AUTO_DETECT,
|
||||
VOP_MODE_UNKNOWN,
|
||||
|
@ -139,7 +140,9 @@ enum vop_modes {
|
|||
#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_DUAL_MIPI_OUT_EN (1 << 3)
|
||||
#define M_ALL_OUT_EN (M_MIPI_OUT_EN | M_EDP_OUT_EN | M_HDMI_OUT_EN |\
|
||||
M_RGB_OUT_EN | M_DUAL_MIPI_OUT_EN)
|
||||
#define M_EDPI_WMS_FS (1 << 10)
|
||||
#define M_EDPI_WMS_MODE (1 << 9)
|
||||
#define M_EDPI_HALT_EN (1 << 8)
|
||||
|
@ -154,6 +157,7 @@ enum vop_modes {
|
|||
#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_DUAL_MIPI_EN(x) (((x) & 1) << 3)
|
||||
#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)
|
||||
|
|
|
@ -119,8 +119,13 @@ void rkvop_mode_set(u32 vop_id, const struct edid *edid, u32 mode)
|
|||
dsp_out_mode = 15;
|
||||
break;
|
||||
case VOP_MODE_MIPI:
|
||||
clrsetbits_le32(&preg->sys_ctrl,
|
||||
M_ALL_OUT_EN, V_MIPI_OUT_EN(1));
|
||||
clrsetbits_le32(&preg->sys_ctrl, M_ALL_OUT_EN,
|
||||
V_MIPI_OUT_EN(1));
|
||||
dsp_out_mode = 0;
|
||||
break;
|
||||
case VOP_MODE_DUAL_MIPI:
|
||||
clrsetbits_le32(&preg->sys_ctrl, M_ALL_OUT_EN,
|
||||
V_MIPI_OUT_EN(1) | V_DUAL_MIPI_EN(1));
|
||||
dsp_out_mode = 0;
|
||||
break;
|
||||
case VOP_MODE_EDP:
|
||||
|
|
|
@ -20,24 +20,8 @@
|
|||
#include <soc/vop.h> /* for vop_modes enum used in devicetree.cb */
|
||||
|
||||
struct soc_rockchip_rk3399_config {
|
||||
gpio_t lcd_bl_pwm_gpio;
|
||||
gpio_t lcd_bl_en_gpio;
|
||||
u32 bl_power_on_udelay;
|
||||
u32 bl_pwm_to_enable_udelay;
|
||||
u32 framebuffer_bits_per_pixel;
|
||||
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__ */
|
||||
|
|
|
@ -48,27 +48,13 @@ static void reset_edp(void)
|
|||
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)
|
||||
{
|
||||
struct edid edid;
|
||||
struct soc_rockchip_rk3399_config *conf = dev->chip_info;
|
||||
enum vop_modes detected_mode = VOP_MODE_UNKNOWN;
|
||||
int retry_count = 0;
|
||||
const struct mipi_panel_data *panel_data = NULL;
|
||||
|
||||
/* let's use vop0 in rk3399 */
|
||||
uint32_t vop_id = 0;
|
||||
|
@ -111,13 +97,42 @@ retry_edp:
|
|||
rkclk_configure_mipi();
|
||||
rkclk_configure_vop_aclk(vop_id, 200 * MHz);
|
||||
|
||||
/* disable turnrequest turndisable forcetxstop forcerxmode */
|
||||
/*
|
||||
* disable tx0 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;
|
||||
/* disable tx1 turndisable, forcetxstop, forcerxmode */
|
||||
write32(&rk3399_grf->soc_con23, RK_CLRBITS(0xfff0));
|
||||
|
||||
/*
|
||||
* enable dphy_tx1rx1_masterslavez,
|
||||
* clear dphy_tx1rx1_enableclk,
|
||||
* clear dphy_tx1rx1_basedir,
|
||||
* disable tx1 turnrequest
|
||||
*/
|
||||
write32(&rk3399_grf->soc_con24,
|
||||
RK_CLRSETBITS(1 << 7 | 1 << 6 | 1 << 5 | 0xf,
|
||||
1 << 7 | 0 << 6 | 0 << 5 | 0 << 0));
|
||||
|
||||
/* dphy_tx1rx1_enable */
|
||||
write32(&rk3399_grf->soc_con23, RK_SETBITS(0xf));
|
||||
|
||||
/* select mipi-dsi0 and mipi-dsi1 signal from vop0 */
|
||||
write32(&rk3399_grf->soc_con20,
|
||||
RK_CLRBITS((1 << 0) | (1 << 4)));
|
||||
|
||||
panel_data = mainboard_get_mipi_mode(&edid);
|
||||
if (panel_data) {
|
||||
if (panel_data->mipi_num > 1)
|
||||
detected_mode = VOP_MODE_DUAL_MIPI;
|
||||
else
|
||||
detected_mode = VOP_MODE_MIPI;
|
||||
} else {
|
||||
printk(BIOS_WARNING, "Can not get mipi panel data\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_WARNING, "Unsupported vop_mode, aborting.\n");
|
||||
|
@ -138,7 +153,8 @@ retry_edp:
|
|||
|
||||
switch (detected_mode) {
|
||||
case VOP_MODE_MIPI:
|
||||
rk_mipi_prepare(&edid, conf->panel_display_on_mdelay, conf->panel_video_mode_mdelay);
|
||||
case VOP_MODE_DUAL_MIPI:
|
||||
rk_mipi_prepare(&edid, panel_data);
|
||||
break;
|
||||
case VOP_MODE_EDP:
|
||||
/* will enable edp in depthcharge */
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
#define SARADC_BASE 0xff100000
|
||||
#define RK_PWM_BASE 0xff420000
|
||||
#define EDP_BASE 0xff970000
|
||||
#define MIPI_BASE 0xff960000
|
||||
#define MIPI0_BASE 0xff960000
|
||||
#define MIPI1_BASE 0xff968000
|
||||
|
||||
#define VOP_BIG_BASE 0xff900000 /* corresponds to vop_id 0 */
|
||||
#define VOP_LIT_BASE 0xff8f0000 /* corresponds to vop_id 1 */
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
#ifndef __SOC_ROCKCHIP_RK3399_DISPLAY_H__
|
||||
#define __SOC_ROCKCHIP_RK3399_DISPLAY_H__
|
||||
|
||||
#include <edid.h>
|
||||
#include <soc/mipi.h>
|
||||
|
||||
#define REF_CLK_24M (0x1 << 0)
|
||||
|
||||
void rk_display_init(device_t dev);
|
||||
void mainboard_power_on_backlight(void);
|
||||
|
||||
const struct mipi_panel_data *mainboard_get_mipi_mode(struct edid *edid);
|
||||
#endif
|
||||
|
|
|
@ -263,8 +263,9 @@ check_member(rk_mipi_regs, dsi_int_msk1, 0xc8);
|
|||
#define GEN_PLD_R_FULL BIT(5)
|
||||
#define GEN_RD_CMD_BUSY BIT(6)
|
||||
|
||||
#define MIPI_DSI_DCS_SHORT_WRITE 0x05
|
||||
#define MIPI_DSI_DCS_LONG_WRITE 0x39
|
||||
#define MIPI_DSI_DCS_SHORT_WRITE 0x05
|
||||
#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23
|
||||
#define MIPI_DSI_DCS_LONG_WRITE 0x39
|
||||
|
||||
enum mipi_dsi_pixel_format {
|
||||
MIPI_DSI_FMT_RGB888,
|
||||
|
@ -314,6 +315,7 @@ struct dphy_pll_parameter_map {
|
|||
};
|
||||
|
||||
struct rk_mipi_dsi {
|
||||
struct rk_mipi_regs *mipi_regs;
|
||||
u64 lane_bps; /* per lane */
|
||||
u32 lanes;
|
||||
u32 format;
|
||||
|
@ -321,5 +323,21 @@ struct rk_mipi_dsi {
|
|||
u16 feedback_div;
|
||||
};
|
||||
|
||||
void rk_mipi_prepare(const struct edid *edid, u32 display_on_mdelay, u32 video_mode_mdelay);
|
||||
struct panel_init_command {
|
||||
u8 cmd;
|
||||
u8 data;
|
||||
};
|
||||
|
||||
struct mipi_panel_data {
|
||||
u8 mipi_num;
|
||||
enum mipi_dsi_pixel_format format;
|
||||
u8 lanes;
|
||||
u32 display_on_udelay;
|
||||
u32 video_mode_udelay;
|
||||
u32 num_init_commands;
|
||||
struct panel_init_command *init_cmd;
|
||||
};
|
||||
|
||||
void rk_mipi_prepare(const struct edid *edid,
|
||||
const struct mipi_panel_data *panel_data);
|
||||
#endif
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
#include <soc/soc.h>
|
||||
#include <timer.h>
|
||||
|
||||
static struct rk_mipi_dsi rk_mipi;
|
||||
static struct rk_mipi_regs *mipi_regs = (void *)MIPI_BASE;
|
||||
static struct rk_mipi_dsi rk_mipi[2] = {
|
||||
{ .mipi_regs = (void *)MIPI0_BASE},
|
||||
{ .mipi_regs = (void *)MIPI1_BASE}
|
||||
};
|
||||
|
||||
/*
|
||||
* The controller should generate 2 frames before
|
||||
|
@ -110,17 +112,20 @@ static void rk_mipi_dsi_phy_write(struct rk_mipi_dsi *dsi,
|
|||
* 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(&dsi->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(&dsi->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(&dsi->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(&dsi->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);
|
||||
write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
|
||||
PHY_TESTCLK | PHY_UNTESTCLR);
|
||||
}
|
||||
|
||||
/* bytes_per_ns - Nanoseconds to byte clock cycles */
|
||||
|
@ -142,7 +147,7 @@ static int rk_mipi_dsi_wait_phy_lock(struct rk_mipi_dsi *dsi)
|
|||
|
||||
stopwatch_init_msecs_expire(&sw, 20);
|
||||
do {
|
||||
val = read32(&mipi_regs->dsi_phy_status);
|
||||
val = read32(&dsi->mipi_regs->dsi_phy_status);
|
||||
if (val & LOCK)
|
||||
return 0;
|
||||
} while (!stopwatch_expired(&sw));
|
||||
|
@ -166,9 +171,9 @@ static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
|
||||
write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLR);
|
||||
write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
|
||||
|
||||
rk_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
|
||||
BYPASS_VCO_RANGE |
|
||||
|
@ -244,8 +249,9 @@ static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
|
|||
rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
|
||||
BIT(5) | bytes_per_ns(dsi, 100));
|
||||
|
||||
write32(&mipi_regs->dsi_phy_rstz, PHY_ENFORCEPLL | PHY_ENABLECLK |
|
||||
PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
|
||||
write32(&dsi->mipi_regs->dsi_phy_rstz,
|
||||
PHY_ENFORCEPLL | PHY_ENABLECLK |
|
||||
PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
|
||||
|
||||
if (rk_mipi_dsi_wait_phy_lock(dsi)) {
|
||||
printk(BIOS_ERR, "failed to wait for phy lock state\n");
|
||||
|
@ -254,7 +260,7 @@ static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
|
|||
|
||||
stopwatch_init_msecs_expire(&sw, 20);
|
||||
do {
|
||||
val = read32(&mipi_regs->dsi_phy_status);
|
||||
val = read32(&dsi->mipi_regs->dsi_phy_status);
|
||||
if (val & STOP_STATE_CLK_LANE)
|
||||
return 0;
|
||||
} while (!stopwatch_expired(&sw));
|
||||
|
@ -281,7 +287,8 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
|||
}
|
||||
|
||||
static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi,
|
||||
const struct edid *edid)
|
||||
const struct edid *edid,
|
||||
const struct mipi_panel_data *panel_data)
|
||||
{
|
||||
u64 pclk, target_bps;
|
||||
u32 max_bps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps * MHz;
|
||||
|
@ -302,7 +309,7 @@ static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi,
|
|||
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;
|
||||
target_bps = pclk / panel_data->lanes * bpp / 8 * 10;
|
||||
if (target_bps >= max_bps) {
|
||||
printk(BIOS_DEBUG, "DPHY clock frequency is out of range\n");
|
||||
return -1;
|
||||
|
@ -381,38 +388,48 @@ static void rk_mipi_dsi_dpi_config(struct rk_mipi_dsi *dsi)
|
|||
break;
|
||||
}
|
||||
|
||||
write32(&mipi_regs->dsi_dpi_vcid, 0);
|
||||
write32(&mipi_regs->dsi_dpi_color_coding, color);
|
||||
write32(&dsi->mipi_regs->dsi_dpi_vcid, 0);
|
||||
write32(&dsi->mipi_regs->dsi_dpi_color_coding, color);
|
||||
|
||||
write32(&mipi_regs->dsi_dpi_cfg_pol, 0);
|
||||
write32(&dsi->mipi_regs->dsi_dpi_cfg_pol, 0);
|
||||
|
||||
write32(&mipi_regs->dsi_dpi_lp_cmd_tim, OUTVACT_LPCMD_TIME(4) |
|
||||
INVACT_LPCMD_TIME(4));
|
||||
write32(&dsi->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);
|
||||
write32(&dsi->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,
|
||||
write32(&dsi->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)
|
||||
static void rk_mipi_dsi_video_packet_config(struct rk_mipi_dsi *dsi,
|
||||
const struct edid *edid,
|
||||
const struct mipi_panel_data *panel_data)
|
||||
{
|
||||
write32(&mipi_regs->dsi_vid_pkt_size, VID_PKT_SIZE(0x300));
|
||||
int pkt_size;
|
||||
|
||||
if (panel_data->mipi_num > 1)
|
||||
pkt_size = VID_PKT_SIZE(edid->mode.ha / 2 + 4);
|
||||
else
|
||||
pkt_size = VID_PKT_SIZE(edid->mode.ha);
|
||||
|
||||
write32(&dsi->mipi_regs->dsi_vid_pkt_size, pkt_size);
|
||||
}
|
||||
|
||||
static void rk_mipi_dsi_command_mode_config(struct rk_mipi_dsi *dsi)
|
||||
{
|
||||
write32(&mipi_regs->dsi_to_cnt_cfg,
|
||||
write32(&dsi->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);
|
||||
write32(&dsi->mipi_regs->dsi_bta_to_cnt, 0xd00);
|
||||
write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
|
||||
write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
|
||||
}
|
||||
|
||||
/* Get lane byte clock cycles. */
|
||||
|
@ -439,12 +456,12 @@ static void rk_mipi_dsi_line_timer_config(struct rk_mipi_dsi *dsi,
|
|||
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);
|
||||
write32(&dsi->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);
|
||||
write32(&dsi->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);
|
||||
write32(&dsi->mipi_regs->dsi_vid_hbp_time, lbcc);
|
||||
}
|
||||
|
||||
static void rk_mipi_dsi_vertical_timing_config(struct rk_mipi_dsi *dsi,
|
||||
|
@ -457,10 +474,10 @@ static void rk_mipi_dsi_vertical_timing_config(struct rk_mipi_dsi *dsi,
|
|||
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);
|
||||
write32(&dsi->mipi_regs->dsi_vid_vactive_lines, vactive);
|
||||
write32(&dsi->mipi_regs->dsi_vid_vsa_lines, vsa);
|
||||
write32(&dsi->mipi_regs->dsi_vid_vfp_lines, vfp);
|
||||
write32(&dsi->mipi_regs->dsi_vid_vbp_lines, vbp);
|
||||
}
|
||||
|
||||
static void rk_mipi_dsi_dphy_timing_config(struct rk_mipi_dsi *dsi)
|
||||
|
@ -469,40 +486,40 @@ 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) |
|
||||
write32(&dsi->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));
|
||||
write32(&dsi->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);
|
||||
read32(&dsi->mipi_regs->dsi_int_st0);
|
||||
read32(&dsi->mipi_regs->dsi_int_st1);
|
||||
write32(&dsi->mipi_regs->dsi_int_msk0, 0);
|
||||
write32(&dsi->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) |
|
||||
write32(&dsi->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);
|
||||
write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
|
||||
if (mode == MIPI_DSI_CMD_MODE) {
|
||||
write32(&mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
|
||||
write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
|
||||
} else {
|
||||
write32(&mipi_regs->dsi_mode_cfg, ENABLE_VIDEO_MODE);
|
||||
write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_VIDEO_MODE);
|
||||
rk_mipi_dsi_video_mode_config(dsi);
|
||||
write32(&mipi_regs->dsi_lpclk_ctrl, PHY_TXREQUESTCLKHS);
|
||||
write32(&dsi->mipi_regs->dsi_lpclk_ctrl, PHY_TXREQUESTCLKHS);
|
||||
}
|
||||
write32(&mipi_regs->dsi_pwr_up, POWERUP);
|
||||
write32(&dsi->mipi_regs->dsi_pwr_up, POWERUP);
|
||||
}
|
||||
|
||||
static void rk_mipi_dsi_init(struct rk_mipi_dsi *dsi)
|
||||
|
@ -515,20 +532,21 @@ static void rk_mipi_dsi_init(struct rk_mipi_dsi *dsi)
|
|||
* which is:
|
||||
* (lane_mbps >> 3) / 20 > esc_clk_division
|
||||
*/
|
||||
u32 esc_clk_division = div_round_up(dsi->lane_bps, 8 * 20 * USECS_PER_SEC);
|
||||
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,
|
||||
write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
|
||||
write32(&dsi->mipi_regs->dsi_phy_rstz,
|
||||
PHY_DISFORCEPLL | PHY_DISABLECLK | PHY_RSTZ | PHY_SHUTDOWNZ);
|
||||
write32(&dsi->mipi_regs->dsi_clk_cfg,
|
||||
TO_CLK_DIVIDSION(10) |
|
||||
TX_ESC_CLK_DIVIDSION(esc_clk_division));
|
||||
}
|
||||
|
||||
static void rk_mipi_message_config(struct rk_mipi_dsi *dsi)
|
||||
{
|
||||
write32(&mipi_regs->dsi_lpclk_ctrl, 0);
|
||||
write32(&mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
|
||||
write32(&dsi->mipi_regs->dsi_lpclk_ctrl, 0);
|
||||
write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
|
||||
}
|
||||
|
||||
static int rk_mipi_dsi_check_cmd_fifo(struct rk_mipi_dsi *dsi)
|
||||
|
@ -538,7 +556,7 @@ static int rk_mipi_dsi_check_cmd_fifo(struct rk_mipi_dsi *dsi)
|
|||
|
||||
stopwatch_init_msecs_expire(&sw, 20);
|
||||
do {
|
||||
val = read32(&mipi_regs->dsi_cmd_pkt_status);
|
||||
val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
|
||||
if (!(val & GEN_CMD_FULL))
|
||||
return 0 ;
|
||||
} while (!stopwatch_expired(&sw));
|
||||
|
@ -557,12 +575,12 @@ static int rk_mipi_dsi_gen_pkt_hdr_write(struct rk_mipi_dsi *dsi, u32 hdr_val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
write32(&mipi_regs->dsi_gen_hdr, hdr_val);
|
||||
write32(&dsi->mipi_regs->dsi_gen_hdr, hdr_val);
|
||||
|
||||
mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
|
||||
stopwatch_init_msecs_expire(&sw, 20);
|
||||
do {
|
||||
val = read32(&mipi_regs->dsi_cmd_pkt_status);
|
||||
val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
|
||||
if ((val & mask) == mask)
|
||||
return 0 ;
|
||||
} while (!stopwatch_expired(&sw));
|
||||
|
@ -582,37 +600,74 @@ static int rk_mipi_dsi_dcs_cmd(struct rk_mipi_dsi *dsi, u8 cmd)
|
|||
return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
|
||||
}
|
||||
|
||||
void rk_mipi_prepare(const struct edid *edid, u32 display_on_mdelay, u32 video_mode_mdelay)
|
||||
static int rk_mipi_dsi_dci_cmd_arg(struct rk_mipi_dsi *dsi, u8 cmd, u8 arg)
|
||||
{
|
||||
rk_mipi.lanes = 4;
|
||||
rk_mipi.format = MIPI_DSI_FMT_RGB888;
|
||||
if (rk_mipi_dsi_get_lane_bps(&rk_mipi, edid) < 0)
|
||||
return;
|
||||
u32 val;
|
||||
u16 data;
|
||||
|
||||
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);
|
||||
if (rk_mipi_dsi_phy_init(&rk_mipi) < 0)
|
||||
return;
|
||||
rk_mipi_dsi_wait_for_two_frames(&rk_mipi, edid);
|
||||
rk_mipi_message_config(dsi);
|
||||
|
||||
rk_mipi_dsi_set_mode(&rk_mipi, MIPI_DSI_CMD_MODE);
|
||||
data = cmd | (arg << 8);
|
||||
val = GEN_HDATA(data) | GEN_HTYPE(MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM);
|
||||
|
||||
if (rk_mipi_dsi_dcs_cmd(&rk_mipi, MIPI_DCS_EXIT_SLEEP_MODE) < 0)
|
||||
return;
|
||||
mdelay(display_on_mdelay);
|
||||
|
||||
if (rk_mipi_dsi_dcs_cmd(&rk_mipi, MIPI_DCS_SET_DISPLAY_ON) < 0)
|
||||
return;
|
||||
mdelay(video_mode_mdelay);
|
||||
|
||||
rk_mipi_dsi_set_mode(&rk_mipi, MIPI_DSI_VID_MODE);
|
||||
return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
|
||||
}
|
||||
|
||||
static void rk_mipi_enable(struct rk_mipi_dsi *dsi,
|
||||
const struct edid *edid,
|
||||
const struct mipi_panel_data *panel_data)
|
||||
{
|
||||
if (rk_mipi_dsi_get_lane_bps(dsi, edid, panel_data) < 0)
|
||||
return;
|
||||
|
||||
rk_mipi_dsi_init(dsi);
|
||||
rk_mipi_dsi_dpi_config(dsi);
|
||||
rk_mipi_dsi_packet_handler_config(dsi);
|
||||
rk_mipi_dsi_video_mode_config(dsi);
|
||||
rk_mipi_dsi_video_packet_config(dsi, edid, panel_data);
|
||||
rk_mipi_dsi_command_mode_config(dsi);
|
||||
rk_mipi_dsi_line_timer_config(dsi, edid);
|
||||
rk_mipi_dsi_vertical_timing_config(dsi, edid);
|
||||
rk_mipi_dsi_dphy_timing_config(dsi);
|
||||
rk_mipi_dsi_dphy_interface_config(dsi);
|
||||
rk_mipi_dsi_clear_err(dsi);
|
||||
if (rk_mipi_dsi_phy_init(dsi) < 0)
|
||||
return;
|
||||
rk_mipi_dsi_wait_for_two_frames(dsi, edid);
|
||||
|
||||
rk_mipi_dsi_set_mode(dsi, MIPI_DSI_CMD_MODE);
|
||||
}
|
||||
|
||||
void rk_mipi_prepare(const struct edid *edid,
|
||||
const struct mipi_panel_data *panel_data)
|
||||
{
|
||||
int i, num;
|
||||
|
||||
for (i = 0; i < panel_data->mipi_num; i++) {
|
||||
rk_mipi[i].lanes = panel_data->lanes / panel_data->mipi_num;
|
||||
rk_mipi[i].format = panel_data->format;
|
||||
rk_mipi_enable(&rk_mipi[i], edid, panel_data);
|
||||
}
|
||||
|
||||
for (num = 0; num < panel_data->num_init_commands; num++) {
|
||||
for (i = 0; i < panel_data->mipi_num; i++)
|
||||
rk_mipi_dsi_dci_cmd_arg(&rk_mipi[i],
|
||||
panel_data->init_cmd[num].cmd,
|
||||
panel_data->init_cmd[num].data);
|
||||
}
|
||||
|
||||
for (i = 0; i < panel_data->mipi_num; i++) {
|
||||
if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
|
||||
MIPI_DCS_EXIT_SLEEP_MODE) < 0)
|
||||
return;
|
||||
}
|
||||
udelay(panel_data->display_on_udelay);
|
||||
for (i = 0; i < panel_data->mipi_num; i++) {
|
||||
if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
|
||||
MIPI_DCS_SET_DISPLAY_ON) < 0)
|
||||
return;
|
||||
}
|
||||
udelay(panel_data->video_mode_udelay);
|
||||
for (i = 0; i < panel_data->mipi_num; i++)
|
||||
rk_mipi_dsi_set_mode(&rk_mipi[i], MIPI_DSI_VID_MODE);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue