// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2020 Rockchip Electronics Co., Ltd * * Author: Wyon Bi */ #include #include #include #include #include #include #include #include "rockchip_display.h" #include "rockchip_bridge.h" #include "rk618.h" /* host registers */ #define HOSTREG(x) ((x) + 0x1000) #define DSI_VERSION HOSTREG(0x0000) #define DSI_PWR_UP HOSTREG(0x0004) #define SHUTDOWNZ BIT(0) #define POWER_UP BIT(0) #define RESET 0 #define DSI_CLKMGR_CFG HOSTREG(0x0008) #define TO_CLK_DIVIDSION(x) UPDATE(x, 15, 8) #define TX_ESC_CLK_DIVIDSION(x) UPDATE(x, 7, 0) #define DSI_DPI_CFG HOSTREG(0x000c) #define EN18_LOOSELY BIT(10) #define COLORM_ACTIVE_LOW BIT(9) #define SHUTD_ACTIVE_LOW BIT(8) #define HSYNC_ACTIVE_LOW BIT(7) #define VSYNC_ACTIVE_LOW BIT(6) #define DATAEN_ACTIVE_LOW BIT(5) #define DPI_COLOR_CODING(x) UPDATE(x, 4, 2) #define DPI_VID(x) UPDATE(x, 1, 0) #define DSI_PCKHDL_CFG HOSTREG(0x0018) #define GEN_VID_RX(x) UPDATE(x, 6, 5) #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 DSI_VID_MODE_CFG HOSTREG(0x001c) #define LPCMDEN BIT(12) #define FRAME_BTA_ACK BIT(11) #define EN_NULL_PKT BIT(10) #define EN_MULTI_PKT BIT(9) #define EN_LP_HFP BIT(8) #define EN_LP_HBP BIT(7) #define EN_LP_VACT BIT(6) #define EN_LP_VFP BIT(5) #define EN_LP_VBP BIT(4) #define EN_LP_VSA BIT(3) #define VID_MODE_TYPE(x) UPDATE(x, 2, 1) #define EN_VIDEO_MODE BIT(0) #define DSI_VID_PKT_CFG HOSTREG(0x0020) #define NULL_PKT_SIZE(x) UPDATE(x, 30, 21) #define NUM_CHUNKS(x) UPDATE(x, 20, 11) #define VID_PKT_SIZE(x) UPDATE(x, 10, 0) #define DSI_CMD_MODE_CFG HOSTREG(0x0024) #define TEAR_FX_EN BIT(14) #define ACK_RQST_EN BIT(13) #define DCS_LW_TX BIT(12) #define GEN_LW_TX BIT(11) #define MAX_RD_PKT_SIZE BIT(10) #define DCS_SR_0P_TX BIT(9) #define DCS_SW_1P_TX BIT(8) #define DCS_SW_0P_TX BIT(7) #define GEN_SR_2P_TX BIT(6) #define GEN_SR_1P_TX BIT(5) #define GEN_SR_0P_TX BIT(4) #define GEN_SW_2P_TX BIT(3) #define GEN_SW_1P_TX BIT(2) #define GEN_SW_0P_TX BIT(1) #define EN_CMD_MODE BIT(0) #define DSI_TMR_LINE_CFG HOSTREG(0x0028) #define HLINE_TIME(x) UPDATE(x, 31, 18) #define HBP_TIME(x) UPDATE(x, 17, 9) #define HSA_TIME(x) UPDATE(x, 8, 0) #define DSI_VTIMING_CFG HOSTREG(0x002c) #define V_ACTIVE_LINES(x) UPDATE(x, 26, 16) #define VFP_LINES(x) UPDATE(x, 15, 10) #define VBP_LINES(x) UPDATE(x, 9, 4) #define VSA_LINES(x) UPDATE(x, 3, 0) #define DSI_PHY_TMR_CFG HOSTREG(0x0030) #define PHY_HS2LP_TIME(x) UPDATE(x, 31, 24) #define PHY_LP2HS_TIME(x) UPDATE(x, 23, 16) #define MAX_RD_TIME(x) UPDATE(x, 14, 0) #define DSI_GEN_HDR HOSTREG(0x0034) #define DSI_GEN_PLD_DATA HOSTREG(0x0038) #define DSI_GEN_PKT_STATUS HOSTREG(0x003c) #define GEN_RD_CMD_BUSY BIT(6) #define GEN_PLD_R_FULL BIT(5) #define GEN_PLD_R_EMPTY BIT(4) #define GEN_PLD_W_FULL BIT(3) #define GEN_PLD_W_EMPTY BIT(2) #define GEN_CMD_FULL BIT(1) #define GEN_CMD_EMPTY BIT(0) #define DSI_TO_CNT_CFG HOSTREG(0x0040) #define LPRX_TO_CNT(x) UPDATE(x, 31, 16) #define HSTX_TO_CNT(x) UPDATE(x, 15, 0) #define DSI_INT_ST0 HOSTREG(0x0044) #define DSI_INT_ST1 HOSTREG(0x0048) #define DSI_INT_MSK0 HOSTREG(0x004c) #define DSI_INT_MSK1 HOSTREG(0x0050) #define DSI_PHY_RSTZ HOSTREG(0x0054) #define PHY_ENABLECLK BIT(2) #define DSI_PHY_IF_CFG HOSTREG(0x0058) #define PHY_STOP_WAIT_TIME(x) UPDATE(x, 9, 2) #define N_LANES(x) UPDATE(x, 1, 0) #define DSI_PHY_IF_CTRL HOSTREG(0x005c) #define PHY_TX_TRIGGERS(x) UPDATE(x, 8, 5) #define PHY_TXEXITULPSLAN BIT(4) #define PHY_TXREQULPSLAN BIT(3) #define PHY_TXEXITULPSCLK BIT(2) #define PHY_RXREQULPSCLK BIT(1) #define PHY_TXREQUESCLKHS BIT(0) #define DSI_PHY_STATUS HOSTREG(0x0060) #define ULPSACTIVENOT3LANE BIT(12) #define PHYSTOPSTATE3LANE BIT(11) #define ULPSACTIVENOT2LANE BIT(10) #define PHYSTOPSTATE2LANE BIT(9) #define ULPSACTIVENOT1LANE BIT(8) #define PHYSTOPSTATE1LANE BIT(7) #define RXULPSESC0LANE BIT(6) #define ULPSACTIVENOT0LANE BIT(5) #define PHYSTOPSTATE0LANE BIT(4) #define PHYULPSACTIVENOTCLK BIT(3) #define PHYSTOPSTATECLKLANE BIT(2) #define PHYSTOPSTATELANE (PHYSTOPSTATE0LANE | PHYSTOPSTATECLKLANE) #define PHYDIRECTION BIT(1) #define PHYLOCK BIT(0) #define DSI_LP_CMD_TIM HOSTREG(0x0070) #define OUTVACT_LPCMD_TIME(x) UPDATE(x, 15, 8) #define INVACT_LPCMD_TIME(x) UPDATE(x, 7, 0) #define DSI_MAX_REGISTER DSI_LP_CMD_TIM /* phy registers */ #define PHYREG(x) ((x) + 0x0c00) #define MIPI_PHY_REG0 PHYREG(0x0000) #define LANE_EN_MASK GENMASK(6, 2) #define LANE_EN_CK BIT(6) #define MIPI_PHY_REG1 PHYREG(0x0004) #define REG_DA_PPFC BIT(4) #define REG_DA_SYNCRST BIT(2) #define REG_DA_LDOPD BIT(1) #define REG_DA_PLLPD BIT(0) #define MIPI_PHY_REG3 PHYREG(0x000c) #define REG_FBDIV_HI_MASK GENMASK(5, 5) #define REG_FBDIV_HI(x) UPDATE(x, 5, 5) #define REG_PREDIV_MASK GENMASK(4, 0) #define REG_PREDIV(x) UPDATE(x, 4, 0) #define MIPI_PHY_REG4 PHYREG(0x0010) #define REG_FBDIV_LO_MASK GENMASK(7, 0) #define REG_FBDIV_LO(x) UPDATE(x, 7, 0) #define MIPI_PHY_REG5 PHYREG(0x0014) #define MIPI_PHY_REG6 PHYREG(0x0018) #define MIPI_PHY_REG7 PHYREG(0x001c) #define MIPI_PHY_REG9 PHYREG(0x0024) #define MIPI_PHY_REG20 PHYREG(0x0080) #define REG_DIG_RSTN BIT(0) #define MIPI_PHY_MAX_REGISTER PHYREG(0x0348) #define THS_SETTLE_OFFSET 0x00 #define THS_SETTLE_MASK GENMASK(3, 0) #define THS_SETTLE(x) UPDATE(x, 3, 0) #define TLPX_OFFSET 0x14 #define TLPX_MASK GENMASK(5, 0) #define TLPX(x) UPDATE(x, 5, 0) #define THS_PREPARE_OFFSET 0x18 #define THS_PREPARE_MASK GENMASK(6, 0) #define THS_PREPARE(x) UPDATE(x, 6, 0) #define THS_ZERO_OFFSET 0x1c #define THS_ZERO_MASK GENMASK(5, 0) #define THS_ZERO(x) UPDATE(x, 5, 0) #define THS_TRAIL_OFFSET 0x20 #define THS_TRAIL_MASK GENMASK(6, 0) #define THS_TRAIL(x) UPDATE(x, 6, 0) #define THS_EXIT_OFFSET 0x24 #define THS_EXIT_MASK GENMASK(4, 0) #define THS_EXIT(x) UPDATE(x, 4, 0) #define TCLK_POST_OFFSET 0x28 #define TCLK_POST_MASK GENMASK(3, 0) #define TCLK_POST(x) UPDATE(x, 3, 0) #define TWAKUP_HI_OFFSET 0x30 #define TWAKUP_HI_MASK GENMASK(1, 0) #define TWAKUP_HI(x) UPDATE(x, 1, 0) #define TWAKUP_LO_OFFSET 0x34 #define TWAKUP_LO_MASK GENMASK(7, 0) #define TWAKUP_LO(x) UPDATE(x, 7, 0) #define TCLK_PRE_OFFSET 0x38 #define TCLK_PRE_MASK GENMASK(3, 0) #define TCLK_PRE(x) UPDATE(x, 3, 0) #define TTA_GO_OFFSET 0x40 #define TTA_GO_MASK GENMASK(5, 0) #define TTA_GO(x) UPDATE(x, 5, 0) #define TTA_SURE_OFFSET 0x44 #define TTA_SURE_MASK GENMASK(5, 0) #define TTA_SURE(x) UPDATE(x, 5, 0) #define TTA_WAIT_OFFSET 0x48 #define TTA_WAIT_MASK GENMASK(5, 0) #define TTA_WAIT(x) UPDATE(x, 5, 0) #define USEC_PER_SEC 1000000L #define USEC_PER_MSEC 1000L #define PSEC_PER_NSEC 1000L #define PSEC_PER_SEC 1000000000000LL struct mipi_dphy { u8 prediv; u16 fbdiv; unsigned int rate; }; struct rk618_dsi { struct udevice *dev; struct rk618 *parent; struct mipi_dphy phy; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format; unsigned long mode_flags; struct drm_display_mode mode; }; enum { NON_BURST_MODE_SYNC_PULSE, NON_BURST_MODE_SYNC_EVENT, BURST_MODE, }; enum { PIXEL_COLOR_CODING_16BIT_1, PIXEL_COLOR_CODING_16BIT_2, PIXEL_COLOR_CODING_16BIT_3, PIXEL_COLOR_CODING_18BIT_1, PIXEL_COLOR_CODING_18BIT_2, PIXEL_COLOR_CODING_24BIT, }; #define dsi_read_poll_timeout(dsi, addr, val, cond, sleep_us, timeout_us) \ ({ \ unsigned long timeout = timer_get_us() + (timeout_us); \ for (;;) { \ (val) = dsi_read(dsi, addr); \ if (cond) \ break; \ if ((timeout_us) && time_after(timer_get_us(), timeout)) { \ (val) = dsi_read(dsi, addr); \ break; \ } \ if (sleep_us) \ udelay(sleep_us); \ } \ (cond) ? 0 : -ETIMEDOUT; \ }) static inline int dsi_write(struct rk618_dsi *dsi, u32 reg, u32 val) { return rk618_i2c_write(dsi->parent, reg, val); } static inline u32 dsi_read(struct rk618_dsi *dsi, u32 reg) { u32 val; rk618_i2c_read(dsi->parent, reg, &val); return val; } static inline void dsi_update_bits(struct rk618_dsi *dsi, u32 reg, u32 mask, u32 val) { u32 orig, tmp; orig = dsi_read(dsi, reg); tmp = orig & ~mask; tmp |= val & mask; dsi_write(dsi, reg, tmp); } static inline bool is_clk_lane(u32 offset) { if (offset == 0x100) return true; return false; } static void rk618_dsi_set_hs_clk(struct rk618_dsi *dsi) { const struct drm_display_mode *mode = &dsi->mode; struct mipi_dphy *phy = &dsi->phy; u32 fout, fref, prediv, fbdiv; u32 min_delta = UINT_MAX; unsigned int value; value = dev_read_u32_default(dsi->dev, "rockchip,lane-rate", 0); if (value > 0) { fout = value * USEC_PER_SEC; } else { int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); unsigned int lanes = dsi->lanes; u64 bandwidth; bandwidth = (u64)mode->clock * 1000 * bpp; do_div(bandwidth, lanes); /* take 1 / 0.9, since mbps must big than bandwidth of RGB */ bandwidth *= 10; do_div(bandwidth, 9); do_div(bandwidth, USEC_PER_SEC); bandwidth *= USEC_PER_SEC; fout = bandwidth; } if (fout > 1000000000UL) fout = 1000000000UL; fref = clk_get_rate(&dsi->parent->clkin); for (prediv = 1; prediv <= 12; prediv++) { u64 tmp; u32 delta; if (fref % prediv) continue; tmp = (u64)fout * prediv; do_div(tmp, fref); fbdiv = tmp; if (fbdiv < 12 || fbdiv > 511) continue; if (fbdiv == 15) continue; tmp = (u64)fbdiv * fref; do_div(tmp, prediv); delta = abs(fout - tmp); if (!delta) { phy->rate = tmp; phy->prediv = prediv; phy->fbdiv = fbdiv; break; } else if (delta < min_delta) { phy->rate = tmp; phy->prediv = prediv; phy->fbdiv = fbdiv; min_delta = delta; } } } static void rk618_dsi_phy_power_off(struct rk618_dsi *dsi) { dsi_update_bits(dsi, MIPI_PHY_REG0, LANE_EN_MASK, 0); dsi_update_bits(dsi, MIPI_PHY_REG1, REG_DA_LDOPD | REG_DA_PLLPD, REG_DA_LDOPD | REG_DA_PLLPD); } static void rk618_dsi_phy_power_on(struct rk618_dsi *dsi, u32 txclkesc) { struct mipi_dphy *phy = &dsi->phy; u32 offset, value, index; const struct { unsigned int rate; u8 ths_settle; u8 ths_zero; u8 ths_trail; } timing_table[] = { { 110000000, 0x00, 0x03, 0x0c}, { 150000000, 0x01, 0x04, 0x0d}, { 200000000, 0x02, 0x04, 0x11}, { 250000000, 0x03, 0x05, 0x14}, { 300000000, 0x04, 0x06, 0x18}, { 400000000, 0x05, 0x07, 0x1d}, { 500000000, 0x06, 0x08, 0x23}, { 600000000, 0x07, 0x0a, 0x29}, { 700000000, 0x08, 0x0b, 0x31}, { 800000000, 0x09, 0x0c, 0x34}, {1000000000, 0x0a, 0x0f, 0x40}, }; u32 Ttxbyteclkhs, UI, Ttxddrclkhs, Ttxclkesc; u32 Tlpx, Ths_exit, Tclk_post, Tclk_pre, Ths_prepare; u32 Tta_go, Tta_sure, Tta_wait; Ttxbyteclkhs = div_u64(PSEC_PER_SEC, phy->rate / 8); UI = Ttxddrclkhs = div_u64(PSEC_PER_SEC, phy->rate); Ttxclkesc = div_u64(PSEC_PER_SEC, txclkesc); dsi_update_bits(dsi, MIPI_PHY_REG3, REG_FBDIV_HI_MASK | REG_PREDIV_MASK, REG_FBDIV_HI(phy->fbdiv >> 8) | REG_PREDIV(phy->prediv)); dsi_update_bits(dsi, MIPI_PHY_REG4, REG_FBDIV_LO_MASK, REG_FBDIV_LO(phy->fbdiv)); dsi_update_bits(dsi, MIPI_PHY_REG1, REG_DA_LDOPD | REG_DA_PLLPD, 0); dsi_update_bits(dsi, MIPI_PHY_REG0, LANE_EN_MASK, LANE_EN_CK | GENMASK(dsi->lanes - 1 + 2, 2)); dsi_update_bits(dsi, MIPI_PHY_REG1, REG_DA_SYNCRST, REG_DA_SYNCRST); udelay(1); dsi_update_bits(dsi, MIPI_PHY_REG1, REG_DA_SYNCRST, 0); dsi_update_bits(dsi, MIPI_PHY_REG20, REG_DIG_RSTN, 0); udelay(1); dsi_update_bits(dsi, MIPI_PHY_REG20, REG_DIG_RSTN, REG_DIG_RSTN); /* XXX */ dsi_write(dsi, MIPI_PHY_REG6, 0x11); dsi_write(dsi, MIPI_PHY_REG7, 0x11); dsi_write(dsi, MIPI_PHY_REG9, 0xcc); if (phy->rate < 800000000) dsi_update_bits(dsi, MIPI_PHY_REG1, REG_DA_PPFC, REG_DA_PPFC); else dsi_write(dsi, MIPI_PHY_REG5, 0x30); for (index = 0; index < ARRAY_SIZE(timing_table); index++) if (phy->rate <= timing_table[index].rate) break; if (index == ARRAY_SIZE(timing_table)) --index; for (offset = 0x100; offset <= 0x300; offset += 0x80) { dsi_update_bits(dsi, PHYREG(offset + THS_SETTLE_OFFSET), THS_SETTLE_MASK, THS_SETTLE(timing_table[index].ths_settle)); /* * The value of counter for HS Tlpx Time * Tlpx = Tpin_txbyteclkhs * value */ Tlpx = 60 * PSEC_PER_NSEC; value = DIV_ROUND_UP(Tlpx, Ttxbyteclkhs); Tlpx = Ttxbyteclkhs * value; dsi_update_bits(dsi, PHYREG(offset + TLPX_OFFSET), TLPX_MASK, TLPX(value)); /* * The value of counter for HS Ths-prepare * For clock lane, Ths-prepare(38ns~95ns) * For data lane, Ths-prepare(40ns+4UI~85ns+6UI) * Ths-prepare = Ttxddrclkhs * value */ if (is_clk_lane(offset)) Ths_prepare = 65 * PSEC_PER_NSEC; else Ths_prepare = 65 * PSEC_PER_NSEC + 4 * UI; value = DIV_ROUND_UP(Ths_prepare, Ttxddrclkhs); dsi_update_bits(dsi, PHYREG(offset + THS_PREPARE_OFFSET), THS_PREPARE_MASK, THS_PREPARE(value)); dsi_update_bits(dsi, PHYREG(offset + THS_ZERO_OFFSET), THS_ZERO_MASK, THS_ZERO(timing_table[index].ths_zero)); dsi_update_bits(dsi, PHYREG(offset + THS_TRAIL_OFFSET), THS_TRAIL_MASK, THS_TRAIL(timing_table[index].ths_trail)); /* * The value of counter for HS Ths-exit * Ths-exit = Tpin_txbyteclkhs * value */ Ths_exit = 120 * PSEC_PER_NSEC; value = DIV_ROUND_UP(Ths_exit, Ttxbyteclkhs); dsi_update_bits(dsi, PHYREG(offset + THS_EXIT_OFFSET), THS_EXIT_MASK, THS_EXIT(value)); /* * The value of counter for HS Tclk-post * Tclk-post = Ttxbyteclkhs * value */ Tclk_post = 70 * PSEC_PER_NSEC + 52 * UI; value = DIV_ROUND_UP(Tclk_post, Ttxbyteclkhs); dsi_update_bits(dsi, PHYREG(offset + TCLK_POST_OFFSET), TCLK_POST_MASK, TCLK_POST(value)); /* * The value of counter for HS Twakup * Twakup for ulpm, * Twakup = Tpin_sys_clk * value */ dsi_update_bits(dsi, PHYREG(offset + TWAKUP_HI_OFFSET), TWAKUP_HI_MASK, TWAKUP_HI(0x3)); dsi_update_bits(dsi, PHYREG(offset + TWAKUP_LO_OFFSET), TWAKUP_LO_MASK, TWAKUP_LO(0xff)); /* * The value of counter for HS Tclk-pre * Tclk-pre for clock lane * Tclk-pre = Tpin_txbyteclkhs * value */ Tclk_pre = 8 * UI; value = DIV_ROUND_UP(Tclk_pre, Ttxbyteclkhs); dsi_update_bits(dsi, PHYREG(offset + TCLK_PRE_OFFSET), TCLK_PRE_MASK, TCLK_PRE(value)); /* * The value of counter for HS Tta-go * Tta-go for turnaround * Tta-go = Ttxclkesc * value */ Tta_go = 4 * Tlpx; value = DIV_ROUND_UP(Tta_go, Ttxclkesc); dsi_update_bits(dsi, PHYREG(offset + TTA_GO_OFFSET), TTA_GO_MASK, TTA_GO(value)); /* * The value of counter for HS Tta-sure * Tta-sure for turnaround * Tta-sure = Ttxclkesc * value */ Tta_sure = 2 * Tlpx; value = DIV_ROUND_UP(Tta_sure, Ttxclkesc); dsi_update_bits(dsi, PHYREG(offset + TTA_SURE_OFFSET), TTA_SURE_MASK, TTA_SURE(value)); /* * The value of counter for HS Tta-wait * Tta-wait for turnaround * Interval from receiving ppi turnaround request to * sending esc request. * Tta-wait = Ttxclkesc * value */ Tta_wait = 5 * Tlpx; value = DIV_ROUND_UP(Tta_wait, Ttxclkesc); dsi_update_bits(dsi, PHYREG(offset + TTA_WAIT_OFFSET), TTA_WAIT_MASK, TTA_WAIT(value)); } } static int rk618_dsi_pre_enable(struct rk618_dsi *dsi) { struct drm_display_mode *mode = &dsi->mode; u32 esc_clk_div, txclkesc; u32 lanebyteclk, dpipclk; u32 hsw, hbp, vsw, vfp, vbp; u32 hsa_time, hbp_time, hline_time; u32 value; int ret; rk618_dsi_set_hs_clk(dsi); dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, RESET); /* Configuration of the internal clock dividers */ esc_clk_div = DIV_ROUND_UP(dsi->phy.rate >> 3, 20000000); txclkesc = dsi->phy.rate >> 3 / esc_clk_div; value = TO_CLK_DIVIDSION(10) | TX_ESC_CLK_DIVIDSION(esc_clk_div); dsi_write(dsi, DSI_CLKMGR_CFG, value); /* The DPI interface configuration */ value = DPI_VID(dsi->channel); if (mode->flags & DRM_MODE_FLAG_NVSYNC) value |= VSYNC_ACTIVE_LOW; if (mode->flags & DRM_MODE_FLAG_NHSYNC) value |= HSYNC_ACTIVE_LOW; switch (dsi->format) { case MIPI_DSI_FMT_RGB666: value |= DPI_COLOR_CODING(PIXEL_COLOR_CODING_18BIT_2); break; case MIPI_DSI_FMT_RGB666_PACKED: value |= DPI_COLOR_CODING(PIXEL_COLOR_CODING_18BIT_1); value |= EN18_LOOSELY; break; case MIPI_DSI_FMT_RGB565: value |= DPI_COLOR_CODING(PIXEL_COLOR_CODING_16BIT_1); break; case MIPI_DSI_FMT_RGB888: default: value |= DPI_COLOR_CODING(PIXEL_COLOR_CODING_24BIT); break; } dsi_write(dsi, DSI_DPI_CFG, value); /* Packet handler configuration */ value = GEN_VID_RX(dsi->channel) | EN_CRC_RX | EN_ECC_RX | EN_BTA; if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) value |= EN_EOTP_TX; dsi_write(dsi, DSI_PCKHDL_CFG, value); /* Video mode configuration */ value = EN_LP_VACT | EN_LP_VBP | EN_LP_VFP | EN_LP_VSA; if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)) value |= EN_LP_HFP; if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)) value |= EN_LP_HBP; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) value |= VID_MODE_TYPE(BURST_MODE); else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) value |= VID_MODE_TYPE(NON_BURST_MODE_SYNC_PULSE); else value |= VID_MODE_TYPE(NON_BURST_MODE_SYNC_EVENT); dsi_write(dsi, DSI_VID_MODE_CFG, value); /* Video packet configuration */ dsi_write(dsi, DSI_VID_PKT_CFG, VID_PKT_SIZE(mode->hdisplay)); /* Timeout timers configuration */ dsi_write(dsi, DSI_TO_CNT_CFG, LPRX_TO_CNT(1000) | HSTX_TO_CNT(1000)); hsw = mode->hsync_end - mode->hsync_start; hbp = mode->htotal - mode->hsync_end; vsw = mode->vsync_end - mode->vsync_start; vfp = mode->vsync_start - mode->vdisplay; vbp = mode->vtotal - mode->vsync_end; /* Line timing configuration */ lanebyteclk = (dsi->phy.rate >> 3) / USEC_PER_SEC; dpipclk = mode->clock / USEC_PER_MSEC; hline_time = DIV_ROUND_UP(mode->htotal * lanebyteclk, dpipclk); hbp_time = DIV_ROUND_UP(hbp * lanebyteclk, dpipclk); hsa_time = DIV_ROUND_UP(hsw * lanebyteclk, dpipclk); dsi_write(dsi, DSI_TMR_LINE_CFG, HLINE_TIME(hline_time) | HBP_TIME(hbp_time) | HSA_TIME(hsa_time)); /* Vertical timing configuration */ dsi_write(dsi, DSI_VTIMING_CFG, V_ACTIVE_LINES(mode->vdisplay) | VFP_LINES(vfp) | VBP_LINES(vbp) | VSA_LINES(vsw)); /* D-PHY interface configuration */ value = N_LANES(dsi->lanes - 1) | PHY_STOP_WAIT_TIME(0x20); dsi_write(dsi, DSI_PHY_IF_CFG, value); /* D-PHY timing configuration */ value = PHY_HS2LP_TIME(20) | PHY_LP2HS_TIME(16) | MAX_RD_TIME(10000); dsi_write(dsi, DSI_PHY_TMR_CFG, value); /* enables the D-PHY Clock Lane Module */ dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_ENABLECLK, PHY_ENABLECLK); dsi_update_bits(dsi, DSI_VID_MODE_CFG, EN_VIDEO_MODE, 0); dsi_update_bits(dsi, DSI_CMD_MODE_CFG, EN_CMD_MODE, EN_CMD_MODE); rk618_dsi_phy_power_on(dsi, txclkesc); /* wait for the PHY to acquire lock */ ret = dsi_read_poll_timeout(dsi, DSI_PHY_STATUS, value, value & PHYLOCK, 50, 1000); if (ret) { dev_err(dsi->dev, "PHY is not locked\n"); return ret; } /* wait for the lane go to the stop state */ ret = dsi_read_poll_timeout(dsi, DSI_PHY_STATUS, value, value & PHYSTOPSTATELANE, 50, 1000); if (ret) { dev_err(dsi->dev, "lane module is not in stop state\n"); return ret; } dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, POWER_UP); return 0; } static void rk618_dsi_enable(struct rk618_dsi *dsi) { /* controls the D-PHY PPI txrequestclkhs signal */ dsi_update_bits(dsi, DSI_PHY_IF_CTRL, PHY_TXREQUESCLKHS, PHY_TXREQUESCLKHS); /* enables the DPI Video mode transmission */ dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, RESET); dsi_update_bits(dsi, DSI_CMD_MODE_CFG, EN_CMD_MODE, 0); dsi_update_bits(dsi, DSI_VID_MODE_CFG, EN_VIDEO_MODE, EN_VIDEO_MODE); dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, POWER_UP); printf("final DSI-Link bandwidth: %lu x %d Mbps\n", dsi->phy.rate / USEC_PER_SEC, dsi->lanes); } static void rk618_dsi_disable(struct rk618_dsi *dsi) { /* enables the Command mode protocol for transmissions */ dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, RESET); dsi_update_bits(dsi, DSI_PHY_IF_CTRL, PHY_TXREQUESCLKHS, 0); dsi_update_bits(dsi, DSI_VID_MODE_CFG, EN_VIDEO_MODE, 0); dsi_update_bits(dsi, DSI_CMD_MODE_CFG, EN_CMD_MODE, EN_CMD_MODE); dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, POWER_UP); } static void rk618_dsi_post_disable(struct rk618_dsi *dsi) { dsi_update_bits(dsi, DSI_PWR_UP, SHUTDOWNZ, RESET); dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_ENABLECLK, 0); rk618_dsi_phy_power_off(dsi); } static void rk618_dsi_bridge_pre_enable(struct rockchip_bridge *bridge) { struct rk618_dsi *dsi = dev_get_priv(bridge->dev); rk618_dsi_pre_enable(dsi); } static void rk618_dsi_bridge_enable(struct rockchip_bridge *bridge) { struct rk618_dsi *dsi = dev_get_priv(bridge->dev); rk618_dsi_enable(dsi); } static void rk618_dsi_bridge_post_disable(struct rockchip_bridge *bridge) { struct rk618_dsi *dsi = dev_get_priv(bridge->dev); rk618_dsi_post_disable(dsi); } static void rk618_dsi_bridge_disable(struct rockchip_bridge *bridge) { struct rk618_dsi *dsi = dev_get_priv(bridge->dev); rk618_dsi_disable(dsi); } static void rk618_dsi_bridge_mode_set(struct rockchip_bridge *bridge, const struct drm_display_mode *mode) { struct rk618_dsi *dsi = dev_get_priv(bridge->dev); memcpy(&dsi->mode, mode, sizeof(*mode)); } static const struct rockchip_bridge_funcs rk618_dsi_bridge_funcs = { .enable = rk618_dsi_bridge_enable, .disable = rk618_dsi_bridge_disable, .pre_enable = rk618_dsi_bridge_pre_enable, .post_disable = rk618_dsi_bridge_post_disable, .mode_set = rk618_dsi_bridge_mode_set, }; static ssize_t rk618_dsi_transfer(struct rk618_dsi *dsi, const struct mipi_dsi_msg *msg) { struct mipi_dsi_packet packet; u32 value, mask; int ret; if (msg->flags & MIPI_DSI_MSG_USE_LPM) dsi_update_bits(dsi, DSI_PHY_IF_CTRL, PHY_TXREQUESCLKHS, 0); else dsi_update_bits(dsi, DSI_PHY_IF_CTRL, PHY_TXREQUESCLKHS, PHY_TXREQUESCLKHS); switch (msg->type) { case MIPI_DSI_DCS_SHORT_WRITE: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, DCS_SW_0P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? DCS_SW_0P_TX : 0); break; case MIPI_DSI_DCS_SHORT_WRITE_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, DCS_SW_1P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? DCS_SW_1P_TX : 0); break; case MIPI_DSI_DCS_LONG_WRITE: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, DCS_LW_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? DCS_LW_TX : 0); break; case MIPI_DSI_DCS_READ: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, DCS_SR_0P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? DCS_SR_0P_TX : 0); break; case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, MAX_RD_PKT_SIZE, msg->flags & MIPI_DSI_MSG_USE_LPM ? MAX_RD_PKT_SIZE : 0); break; case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SW_0P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SW_0P_TX : 0); break; case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SW_1P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SW_1P_TX : 0); break; case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SW_2P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SW_2P_TX : 0); break; case MIPI_DSI_GENERIC_LONG_WRITE: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_LW_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_LW_TX : 0); break; case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SR_0P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SR_0P_TX : 0); break; case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SR_1P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SR_1P_TX : 0); break; case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: dsi_update_bits(dsi, DSI_CMD_MODE_CFG, GEN_SR_2P_TX, msg->flags & MIPI_DSI_MSG_USE_LPM ? GEN_SR_2P_TX : 0); break; default: return -EINVAL; } /* create a packet to the DSI protocol */ ret = mipi_dsi_create_packet(&packet, msg); if (ret) { dev_err(dsi->dev, "failed to create packet: %d\n", ret); return ret; } /* Send payload */ while (packet.payload_length >= 4) { mask = GEN_PLD_W_FULL; ret = dsi_read_poll_timeout(dsi, DSI_GEN_PKT_STATUS, value, !(value & mask), 50, 1000); if (ret) { dev_err(dsi->dev, "Write payload FIFO is full\n"); return ret; } value = get_unaligned_le32(packet.payload); dsi_write(dsi, DSI_GEN_PLD_DATA, value); packet.payload += 4; packet.payload_length -= 4; } value = 0; switch (packet.payload_length) { case 3: value |= packet.payload[2] << 16; /* Fall through */ case 2: value |= packet.payload[1] << 8; /* Fall through */ case 1: value |= packet.payload[0]; dsi_write(dsi, DSI_GEN_PLD_DATA, value); break; } mask = GEN_CMD_FULL; ret = dsi_read_poll_timeout(dsi, DSI_GEN_PKT_STATUS, value, !(value & mask), 50, 1000); if (ret) { dev_err(dsi->dev, "Command FIFO is full\n"); return ret; } /* Send packet header */ value = get_unaligned_le32(packet.header); dsi_write(dsi, DSI_GEN_HDR, value); mask = GEN_PLD_W_EMPTY | GEN_CMD_EMPTY; ret = dsi_read_poll_timeout(dsi, DSI_GEN_PKT_STATUS, value, (value & mask) == mask, 50, 1000); if (ret) { dev_err(dsi->dev, "Write payload FIFO is not empty\n"); return ret; } if (msg->rx_len) { u8 *payload = msg->rx_buf; u16 length; mask = GEN_RD_CMD_BUSY; ret = dsi_read_poll_timeout(dsi, DSI_GEN_PKT_STATUS, value, !(value & mask), 50, 1000); if (ret) { dev_err(dsi->dev, "entire response is not stored in the FIFO\n"); return ret; } /* Receive payload */ for (length = msg->rx_len; length; length -= 4) { mask = GEN_PLD_R_EMPTY; ret = dsi_read_poll_timeout(dsi, DSI_GEN_PKT_STATUS, value, !(value & mask), 50, 1000); if (ret) { dev_err(dsi->dev, "Read payload FIFO is empty\n"); return ret; } value = dsi_read(dsi, DSI_GEN_PLD_DATA); switch (length) { case 3: payload[2] = (value >> 16) & 0xff; /* Fall through */ case 2: payload[1] = (value >> 8) & 0xff; /* Fall through */ case 1: payload[0] = value & 0xff; return length; } payload[0] = (value >> 0) & 0xff; payload[1] = (value >> 8) & 0xff; payload[2] = (value >> 16) & 0xff; payload[3] = (value >> 24) & 0xff; payload += 4; } } return packet.payload_length; } static int rk618_dsi_probe(struct udevice *dev) { struct rk618_dsi *dsi = dev_get_priv(dev); struct rockchip_bridge *bridge = (struct rockchip_bridge *)dev_get_driver_data(dev); int ret; dsi->dev = dev; dsi->parent = dev_get_priv(dev->parent); ret = device_probe(dev->parent); if (ret) return ret; bridge->dev = dev; /* Mask all interrupts */ dsi_write(dsi, DSI_INT_MSK0, 0xffffffff); dsi_write(dsi, DSI_INT_MSK1, 0xffffffff); return 0; } static struct rockchip_bridge rk618_dsi_driver_data = { .funcs = &rk618_dsi_bridge_funcs, }; static const struct udevice_id rk618_dsi_ids[] = { { .compatible = "rockchip,rk618-dsi", .data = (ulong)&rk618_dsi_driver_data, }, {} }; static ssize_t rk618_dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { struct rk618_dsi *dsi = dev_get_priv(host->dev); return rk618_dsi_transfer(dsi, msg); } static int rk618_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct rk618_dsi *dsi = dev_get_priv(host->dev); if (device->lanes < 1 || device->lanes > 4) return -EINVAL; dsi->lanes = device->lanes; dsi->channel = device->channel; dsi->format = device->format; dsi->mode_flags = device->mode_flags; return 0; } static const struct mipi_dsi_host_ops rk618_dsi_host_ops = { .attach = rk618_dsi_host_attach, .transfer = rk618_dsi_host_transfer, }; static int rk618_dsi_bind(struct udevice *dev) { struct mipi_dsi_host *host = dev_get_platdata(dev); host->dev = dev; host->ops = &rk618_dsi_host_ops; return dm_scan_fdt_dev(dev); } static int rk618_dsi_child_post_bind(struct udevice *dev) { struct mipi_dsi_host *host = dev_get_platdata(dev->parent); struct mipi_dsi_device *device = dev_get_parent_platdata(dev); char name[20]; sprintf(name, "%s.%d", host->dev->name, device->channel); device_set_name(dev, name); device->dev = dev; device->host = host; device->lanes = dev_read_u32_default(dev, "dsi,lanes", 4); device->format = dev_read_u32_default(dev, "dsi,format", MIPI_DSI_FMT_RGB888); device->mode_flags = dev_read_u32_default(dev, "dsi,flags", MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_HBP | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET); device->channel = dev_read_u32_default(dev, "reg", 0); return 0; } static int rk618_dsi_child_pre_probe(struct udevice *dev) { struct mipi_dsi_device *device = dev_get_parent_platdata(dev); int ret; ret = mipi_dsi_attach(device); if (ret) { dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); return ret; } return 0; } U_BOOT_DRIVER(rk618_dsi) = { .name = "rk618_dsi", .id = UCLASS_VIDEO_BRIDGE, .of_match = rk618_dsi_ids, .probe = rk618_dsi_probe, .bind = rk618_dsi_bind, .priv_auto_alloc_size = sizeof(struct rk618_dsi), .per_child_platdata_auto_alloc_size = sizeof(struct mipi_dsi_device), .platdata_auto_alloc_size = sizeof(struct mipi_dsi_host), .child_post_bind = rk618_dsi_child_post_bind, .child_pre_probe = rk618_dsi_child_pre_probe, };