diff --git a/src/mainboard/google/gru/devicetree.scarlet.cb b/src/mainboard/google/gru/devicetree.scarlet.cb index f1129a4980..c4417c594c 100644 --- a/src/mainboard/google/gru/devicetree.scarlet.cb +++ b/src/mainboard/google/gru/devicetree.scarlet.cb @@ -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 diff --git a/src/mainboard/google/gru/mainboard.c b/src/mainboard/google/gru/mainboard.c index 076cfa1d15..296d9ad56a 100644 --- a/src/mainboard/google/gru/mainboard.c +++ b/src/mainboard/google/gru/mainboard.c @@ -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; diff --git a/src/soc/rockchip/common/include/soc/vop.h b/src/soc/rockchip/common/include/soc/vop.h index c5c542583d..69d11845c0 100644 --- a/src/soc/rockchip/common/include/soc/vop.h +++ b/src/soc/rockchip/common/include/soc/vop.h @@ -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) diff --git a/src/soc/rockchip/common/vop.c b/src/soc/rockchip/common/vop.c index 70d59bd6a8..463159182a 100644 --- a/src/soc/rockchip/common/vop.c +++ b/src/soc/rockchip/common/vop.c @@ -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: diff --git a/src/soc/rockchip/rk3399/chip.h b/src/soc/rockchip/rk3399/chip.h index 4b2ccc5b52..b4b3e75605 100644 --- a/src/soc/rockchip/rk3399/chip.h +++ b/src/soc/rockchip/rk3399/chip.h @@ -20,24 +20,8 @@ #include /* 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__ */ diff --git a/src/soc/rockchip/rk3399/display.c b/src/soc/rockchip/rk3399/display.c index 379e1bfec8..cc265b2edb 100644 --- a/src/soc/rockchip/rk3399/display.c +++ b/src/soc/rockchip/rk3399/display.c @@ -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 */ diff --git a/src/soc/rockchip/rk3399/include/soc/addressmap.h b/src/soc/rockchip/rk3399/include/soc/addressmap.h index 7a365adb86..5dca6bb84e 100644 --- a/src/soc/rockchip/rk3399/include/soc/addressmap.h +++ b/src/soc/rockchip/rk3399/include/soc/addressmap.h @@ -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 */ diff --git a/src/soc/rockchip/rk3399/include/soc/display.h b/src/soc/rockchip/rk3399/include/soc/display.h index c10f1b9f04..bf90f651a6 100644 --- a/src/soc/rockchip/rk3399/include/soc/display.h +++ b/src/soc/rockchip/rk3399/include/soc/display.h @@ -16,9 +16,12 @@ #ifndef __SOC_ROCKCHIP_RK3399_DISPLAY_H__ #define __SOC_ROCKCHIP_RK3399_DISPLAY_H__ +#include +#include + #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 diff --git a/src/soc/rockchip/rk3399/include/soc/mipi.h b/src/soc/rockchip/rk3399/include/soc/mipi.h index 09285cf51c..933ea89bd4 100644 --- a/src/soc/rockchip/rk3399/include/soc/mipi.h +++ b/src/soc/rockchip/rk3399/include/soc/mipi.h @@ -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 diff --git a/src/soc/rockchip/rk3399/mipi.c b/src/soc/rockchip/rk3399/mipi.c index 3f1ddb3664..825eb72366 100644 --- a/src/soc/rockchip/rk3399/mipi.c +++ b/src/soc/rockchip/rk3399/mipi.c @@ -30,8 +30,10 @@ #include #include -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); }