X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Frockchip%2Fdw-mipi-dsi.c;h=38e4811be728ed1a954020c17bcec59db704d1e0;hb=0a95d11068a459d35607f6af6e2b2d5ce9052cb8;hp=f8f8f29fb7c336d8fffe1a74bddbad66e01854f6;hpb=927b5a2bd7e0ca06412cd3536e48b2a89bff0dfc;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index f8f8f29fb7c3..38e4811be728 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -12,7 +12,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -28,9 +31,17 @@ #define DRIVER_NAME "dw-mipi-dsi" -#define GRF_SOC_CON6 0x025c -#define DSI0_SEL_VOP_LIT (1 << 6) -#define DSI1_SEL_VOP_LIT (1 << 9) +#define RK3288_GRF_SOC_CON6 0x025c +#define RK3288_DSI0_SEL_VOP_LIT BIT(6) +#define RK3288_DSI1_SEL_VOP_LIT BIT(9) + +#define RK3399_GRF_SOC_CON19 0x6250 +#define RK3399_DSI0_SEL_VOP_LIT BIT(0) +#define RK3399_DSI1_SEL_VOP_LIT BIT(4) + +/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */ +#define RK3399_GRF_SOC_CON22 0x6258 +#define RK3399_GRF_DSI_MODE 0xffff0000 #define DSI_VERSION 0x00 #define DSI_PWR_UP 0x04 @@ -82,13 +93,16 @@ #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 0x2 -#define VID_MODE_TYPE_MASK 0x3 +#define VID_MODE_TYPE_BURST_SYNC_PULSES 0x0 +#define VID_MODE_TYPE_BURST_SYNC_EVENTS 0x1 +#define VID_MODE_TYPE_BURST 0x2 #define DSI_VID_PKT_SIZE 0x3c #define VID_PKT_SIZE(p) (((p) & 0x3fff) << 0) #define VID_PKT_MAX_SIZE 0x3fff +#define DSI_VID_NUM_CHUMKS 0x40 +#define DSI_VID_NULL_PKT_SIZE 0x44 #define DSI_VID_HSA_TIME 0x48 #define DSI_VID_HBP_TIME 0x4c #define DSI_VID_HLINE_TIME 0x50 @@ -147,7 +161,6 @@ #define LPRX_TO_CNT(p) ((p) & 0xffff) #define DSI_BTA_TO_CNT 0x8c - #define DSI_LPCLK_CTRL 0x94 #define AUTO_CLKLANE_CTRL BIT(1) #define PHY_TXREQUESTCLKHS BIT(0) @@ -263,7 +276,14 @@ enum { }; struct dw_mipi_dsi_plat_data { + u32 dsi0_en_bit; + u32 dsi1_en_bit; + u32 grf_switch_reg; + u32 grf_dsi0_mode; + u32 grf_dsi0_mode_reg; unsigned int max_data_lanes; + u32 max_bit_rate_per_lane; + bool has_vop_sel; enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); }; @@ -272,13 +292,16 @@ struct dw_mipi_dsi { struct drm_encoder encoder; struct drm_connector connector; struct mipi_dsi_host dsi_host; + struct phy *phy; struct drm_panel *panel; struct device *dev; struct regmap *grf_regmap; + struct reset_control *rst; void __iomem *base; struct clk *pllref_clk; struct clk *pclk; + struct clk *phy_cfg_clk; unsigned int lane_mbps; /* per lane */ u32 channel; @@ -286,7 +309,7 @@ struct dw_mipi_dsi { u32 format; u16 input_div; u16 feedback_div; - struct drm_display_mode *mode; + struct drm_display_mode mode; const struct dw_mipi_dsi_plat_data *pdata; }; @@ -334,7 +357,7 @@ static void dw_mipi_dsi_wait_for_two_frames(struct dw_mipi_dsi *dsi) { int refresh, two_frames; - refresh = drm_mode_vrefresh(dsi->mode); + refresh = drm_mode_vrefresh(&dsi->mode); two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; msleep(two_frames); } @@ -400,6 +423,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) dsi_write(dsi, DSI_PWR_UP, POWERUP); + if (!IS_ERR(dsi->phy_cfg_clk)) { + ret = clk_prepare_enable(dsi->phy_cfg_clk); + if (ret) { + dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n"); + return ret; + } + } + dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE | VCO_RANGE_CON_SEL(vco) | VCO_IN_CAP_CON_LOW | @@ -433,7 +464,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) BANDGAP_SEL(BANDGAP_96_10)); dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | 0xf); - dw_mipi_dsi_phy_write(dsi, 0x71, THS_PRE_PROGRAM_EN | 0x55); + dw_mipi_dsi_phy_write(dsi, 0x71, THS_PRE_PROGRAM_EN | 0x2d); dw_mipi_dsi_phy_write(dsi, 0x72, THS_ZERO_PROGRAM_EN | 0xa); dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | @@ -444,17 +475,19 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) { dev_err(dsi->dev, "failed to wait for phy lock state\n"); - return ret; + goto phy_init_end; } ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS, val, val & STOP_STATE_CLK_LANE, 1000, PHY_STATUS_TIMEOUT_US); - if (ret < 0) { + if (ret < 0) dev_err(dsi->dev, "failed to wait for phy clk lane stop state\n"); - return ret; - } + +phy_init_end: + if (!IS_ERR(dsi->phy_cfg_clk)) + clk_disable_unprepare(dsi->phy_cfg_clk); return ret; } @@ -474,7 +507,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) return bpp; } - mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC); + mpclk = DIV_ROUND_UP(dsi->mode.clock, MSEC_PER_SEC); if (mpclk) { /* take 1 / 0.9, since mbps must big than bandwidth of RGB */ tmp = mpclk * (bpp / dsi->lanes) * 10 / 9; @@ -516,8 +549,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, return -EINVAL; } - if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) || - !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) { + if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) { dev_err(dsi->dev, "device mode is unsupported\n"); return -EINVAL; } @@ -526,10 +558,12 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->channel = device->channel; dsi->format = device->format; dsi->panel = of_drm_find_panel(device->dev.of_node); - if (dsi->panel) - return drm_panel_attach(dsi->panel, &dsi->connector); + if (!dsi->panel) { + DRM_ERROR("failed to find panel\n"); + return -ENODEV; + } - return -EINVAL; + return 0; } static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, @@ -537,18 +571,22 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, { struct dw_mipi_dsi *dsi = host_to_dsi(host); - drm_panel_detach(dsi->panel); + if (dsi->panel) + drm_panel_detach(dsi->panel); + dsi->panel = NULL; return 0; } static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) { int ret; + int sts = 0; ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, - val, !(val & GEN_CMD_FULL), 1000, + sts, !(sts & GEN_CMD_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { dev_err(dsi->dev, "failed to get available command FIFO\n"); return ret; @@ -557,8 +595,9 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) dsi_write(dsi, DSI_GEN_HDR, val); ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, - val, val & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY), + sts, sts & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY), 1000, CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { dev_err(dsi->dev, "failed to write command FIFO\n"); return ret; @@ -567,8 +606,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) return 0; } -static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, - const struct mipi_dsi_msg *msg) +static int dw_mipi_dsi_short_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) { const u16 *tx_buf = msg->tx_buf; u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type); @@ -582,13 +621,14 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi, return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val); } -static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, - const struct mipi_dsi_msg *msg) +static int dw_mipi_dsi_long_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) { const u32 *tx_buf = msg->tx_buf; int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret; u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); u32 remainder = 0; + u32 sts = 0; if (msg->tx_len < 3) { dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", @@ -608,7 +648,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi, } ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, - val, !(val & GEN_PLD_W_FULL), 1000, + sts, !(sts & GEN_PLD_W_FULL), 1000, CMD_PKT_STATUS_TIMEOUT_US); if (ret < 0) { dev_err(dsi->dev, @@ -629,11 +669,15 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, switch (msg->type) { case MIPI_DSI_DCS_SHORT_WRITE: case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: - ret = dw_mipi_dsi_dcs_short_write(dsi, msg); + ret = dw_mipi_dsi_short_write(dsi, msg); break; case MIPI_DSI_DCS_LONG_WRITE: - ret = dw_mipi_dsi_dcs_long_write(dsi, msg); + case MIPI_DSI_GENERIC_LONG_WRITE: + ret = dw_mipi_dsi_long_write(dsi, msg); break; default: dev_err(dsi->dev, "unsupported message type\n"); @@ -653,7 +697,7 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) { u32 val; - val = VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER; + val = VID_MODE_TYPE_BURST | ENABLE_LOW_POWER; dsi_write(dsi, DSI_VID_MODE_CFG, val); } @@ -748,8 +792,8 @@ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; - frac = lbcc % dsi->mode->clock; - lbcc = lbcc / dsi->mode->clock; + frac = lbcc % dsi->mode.clock; + lbcc = lbcc / dsi->mode.clock; if (frac) lbcc++; @@ -759,7 +803,7 @@ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi) { u32 htotal, hsa, hbp, lbcc; - struct drm_display_mode *mode = dsi->mode; + struct drm_display_mode *mode = &dsi->mode; htotal = mode->htotal; hsa = mode->hsync_end - mode->hsync_start; @@ -778,7 +822,7 @@ static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi) { u32 vactive, vsa, vfp, vbp; - struct drm_display_mode *mode = dsi->mode; + struct drm_display_mode *mode = &dsi->mode; vactive = mode->vdisplay; vsa = mode->vsync_end - mode->vsync_start; @@ -793,8 +837,8 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) - | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x14) + | PHY_LP2HS_TIME(0x10) | MAX_RD_TIME(10000)); dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) | PHY_CLKLP2HS_TIME(0x40)); @@ -819,34 +863,8 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - int ret; - - dsi->mode = adjusted_mode; - - ret = dw_mipi_dsi_get_lane_bps(dsi); - if (ret < 0) - return; - - if (clk_prepare_enable(dsi->pclk)) { - dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__); - return; - } - - dw_mipi_dsi_init(dsi); - dw_mipi_dsi_dpi_config(dsi, mode); - dw_mipi_dsi_packet_handler_config(dsi); - dw_mipi_dsi_video_mode_config(dsi); - dw_mipi_dsi_video_packet_config(dsi, mode); - dw_mipi_dsi_command_mode_config(dsi); - dw_mipi_dsi_line_timer_config(dsi); - dw_mipi_dsi_vertical_timing_config(dsi); - dw_mipi_dsi_dphy_timing_config(dsi); - dw_mipi_dsi_dphy_interface_config(dsi); - dw_mipi_dsi_clear_err(dsi); - if (drm_panel_prepare(dsi->panel)) - dev_err(dsi->dev, "failed to prepare panel\n"); - clk_disable_unprepare(dsi->pclk); + drm_mode_copy(&dsi->mode, adjusted_mode); } static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) @@ -872,6 +890,8 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); dw_mipi_dsi_disable(dsi); + phy_power_off(dsi->phy); + pm_runtime_put(dsi->dev); clk_disable_unprepare(dsi->pclk); } @@ -882,11 +902,12 @@ static bool dw_mipi_dsi_encoder_mode_fixup(struct drm_encoder *encoder, return true; } -static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - int mux = rockchip_drm_encoder_get_mux_id(dsi->dev->of_node, encoder); - u32 interface_pix_fmt; + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata; + int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder); + int ret; u32 val; if (clk_prepare_enable(dsi->pclk)) { @@ -894,7 +915,51 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) return; } - dw_mipi_dsi_phy_init(dsi); + if (dsi->rst) { + /* MIPI DSI APB software reset request. */ + reset_control_assert(dsi->rst); + udelay(10); + reset_control_deassert(dsi->rst); + udelay(10); + } + + pm_runtime_get_sync(dsi->dev); + + phy_power_on(dsi->phy); + + if (dsi->phy) { + /* + * If using the third party PHY, we get the lane + * rate information from PHY. + */ + dsi->lane_mbps = phy_get_bus_width(dsi->phy); + } else { + ret = dw_mipi_dsi_get_lane_bps(dsi); + if (ret < 0) + return; + } + + dw_mipi_dsi_init(dsi); + dw_mipi_dsi_dpi_config(dsi, &dsi->mode); + dw_mipi_dsi_packet_handler_config(dsi); + dw_mipi_dsi_video_mode_config(dsi); + dw_mipi_dsi_video_packet_config(dsi, &dsi->mode); + dw_mipi_dsi_command_mode_config(dsi); + dw_mipi_dsi_line_timer_config(dsi); + dw_mipi_dsi_vertical_timing_config(dsi); + dw_mipi_dsi_dphy_timing_config(dsi); + dw_mipi_dsi_dphy_interface_config(dsi); + dw_mipi_dsi_clear_err(dsi); + if (drm_panel_prepare(dsi->panel)) + dev_err(dsi->dev, "failed to prepare panel\n"); + + if (pdata->grf_dsi0_mode_reg) + regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg, + pdata->grf_dsi0_mode); + + if (!dsi->phy) + dw_mipi_dsi_phy_init(dsi); + dw_mipi_dsi_wait_for_two_frames(dsi); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); @@ -902,39 +967,57 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) clk_disable_unprepare(dsi->pclk); + if (!pdata->has_vop_sel) + return; + + if (mux) + val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16); + else + val = pdata->dsi0_en_bit << 16; + + regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); + dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); +} + +static int +dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); + struct drm_connector *connector = conn_state->connector; + struct drm_display_info *info = &connector->display_info; + switch (dsi->format) { case MIPI_DSI_FMT_RGB888: - interface_pix_fmt = ROCKCHIP_OUT_MODE_P888; + s->output_mode = ROCKCHIP_OUT_MODE_P888; break; case MIPI_DSI_FMT_RGB666: - interface_pix_fmt = ROCKCHIP_OUT_MODE_P666; + s->output_mode = ROCKCHIP_OUT_MODE_P666; break; case MIPI_DSI_FMT_RGB565: - interface_pix_fmt = ROCKCHIP_OUT_MODE_P565; + s->output_mode = ROCKCHIP_OUT_MODE_P565; break; default: WARN_ON(1); - return; + return -EINVAL; } - rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_DSI, - interface_pix_fmt); + s->output_type = DRM_MODE_CONNECTOR_DSI; + if (info->num_bus_formats) + s->bus_format = info->bus_formats[0]; - if (mux) - val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16); - else - val = DSI0_SEL_VOP_LIT << 16; - - regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val); - dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); + return 0; } static struct drm_encoder_helper_funcs dw_mipi_dsi_encoder_helper_funcs = { .mode_fixup = dw_mipi_dsi_encoder_mode_fixup, - .commit = dw_mipi_dsi_encoder_commit, .mode_set = dw_mipi_dsi_encoder_mode_set, + .enable = dw_mipi_dsi_encoder_enable, .disable = dw_mipi_dsi_encoder_disable, + .atomic_check = dw_mipi_dsi_encoder_atomic_check, }; static struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = { @@ -970,7 +1053,20 @@ static struct drm_encoder *dw_mipi_dsi_connector_best_encoder( return &dsi->encoder; } +static int dw_mipi_loader_protect(struct drm_connector *connector, bool on) +{ + struct dw_mipi_dsi *dsi = con_to_dsi(connector); + + if (on) + pm_runtime_get_sync(dsi->dev); + else + pm_runtime_put(dsi->dev); + + return 0; +} + static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = { + .loader_protect = dw_mipi_loader_protect, .get_modes = dw_mipi_dsi_connector_get_modes, .mode_valid = dw_mipi_dsi_mode_valid, .best_encoder = dw_mipi_dsi_connector_best_encoder, @@ -1033,6 +1129,10 @@ static int dw_mipi_dsi_register(struct drm_device *drm, &dw_mipi_dsi_atomic_connector_funcs, DRM_MODE_CONNECTOR_DSI); + drm_panel_attach(dsi->panel, &dsi->connector); + + dsi->connector.port = dev->of_node; + drm_mode_connector_attach_encoder(connector, encoder); return 0; @@ -1051,36 +1151,41 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi) return 0; } -static enum drm_mode_status rk3288_mipi_dsi_mode_valid( - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* - * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG - * register is 11-bit. - */ - if (mode->hdisplay > 0x7ff) - return MODE_BAD_HVALUE; - - /* - * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG - * register is 11-bit. - */ - if (mode->vdisplay > 0x7ff) - return MODE_BAD_VVALUE; +static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { + .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT, + .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT, + .grf_switch_reg = RK3288_GRF_SOC_CON6, + .max_data_lanes = 4, + .max_bit_rate_per_lane = 1500000000, + .has_vop_sel = true, +}; - return MODE_OK; -} +static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { + .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT, + .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT, + .grf_switch_reg = RK3399_GRF_SOC_CON19, + .grf_dsi0_mode = RK3399_GRF_DSI_MODE, + .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, + .max_data_lanes = 4, + .max_bit_rate_per_lane = 1500000000, + .has_vop_sel = true, +}; -static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { +static struct dw_mipi_dsi_plat_data rk3368_mipi_dsi_drv_data = { .max_data_lanes = 4, - .mode_valid = rk3288_mipi_dsi_mode_valid, + .max_bit_rate_per_lane = 1000000000, }; static const struct of_device_id dw_mipi_dsi_dt_ids[] = { { .compatible = "rockchip,rk3288-mipi-dsi", .data = &rk3288_mipi_dsi_drv_data, + },{ + .compatible = "rockchip,rk3399-mipi-dsi", + .data = &rk3399_mipi_dsi_drv_data, + }, { + .compatible = "rockchip,rk3368-mipi-dsi", + .data = &rk3368_mipi_dsi_drv_data, }, { /* sentinel */ } }; @@ -1089,26 +1194,26 @@ MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids); static int dw_mipi_dsi_bind(struct device *dev, struct device *master, void *data) { - const struct of_device_id *of_id = - of_match_device(dw_mipi_dsi_dt_ids, dev); - const struct dw_mipi_dsi_plat_data *pdata = of_id->data; struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; - struct dw_mipi_dsi *dsi; + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); struct resource *res; int ret; - dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); - if (!dsi) - return -ENOMEM; - - dsi->dev = dev; - dsi->pdata = pdata; + if (!dsi->panel) + return -EPROBE_DEFER; ret = rockchip_mipi_parse_dt(dsi); if (ret) return ret; + dsi->phy = devm_phy_optional_get(dev, "mipi_dphy"); + if (IS_ERR(dsi->phy)) { + ret = PTR_ERR(dsi->phy); + dev_err(dev, "failed to get mipi dphy: %d\n", ret); + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -1117,13 +1222,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, if (IS_ERR(dsi->base)) return PTR_ERR(dsi->base); - dsi->pllref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(dsi->pllref_clk)) { - ret = PTR_ERR(dsi->pllref_clk); - dev_err(dev, "Unable to get pll reference clock: %d\n", ret); - return ret; - } - dsi->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dsi->pclk)) { ret = PTR_ERR(dsi->pclk); @@ -1131,12 +1229,32 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, return ret; } + /* optional */ + dsi->pllref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(dsi->pllref_clk)) { + dev_info(dev, "No PHY reference clock specified\n"); + dsi->pllref_clk = NULL; + } + + /* optional */ + dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); + if (IS_ERR(dsi->phy_cfg_clk)) { + dev_info(dev, "No PHY APB clock specified\n"); + dsi->phy_cfg_clk = NULL; + } + ret = clk_prepare_enable(dsi->pllref_clk); if (ret) { dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); return ret; } + dsi->rst = devm_reset_control_get_optional(dev, "apb"); + if (IS_ERR(dsi->rst)) { + dev_info(dev, "no reset control specified\n"); + dsi->rst = NULL; + } + ret = dw_mipi_dsi_register(drm, dsi); if (ret) { dev_err(dev, "Failed to register mipi_dsi: %d\n", ret); @@ -1145,9 +1263,9 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, dev_set_drvdata(dev, dsi); - dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; - dsi->dsi_host.dev = dev; - return mipi_dsi_host_register(&dsi->dsi_host); + pm_runtime_enable(dev); + + return 0; err_pllref: clk_disable_unprepare(dsi->pllref_clk); @@ -1159,7 +1277,7 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master, { struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); - mipi_dsi_host_unregister(&dsi->dsi_host); + pm_runtime_disable(dev); clk_disable_unprepare(dsi->pllref_clk); } @@ -1170,11 +1288,40 @@ static const struct component_ops dw_mipi_dsi_ops = { static int dw_mipi_dsi_probe(struct platform_device *pdev) { - return component_add(&pdev->dev, &dw_mipi_dsi_ops); + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = + of_match_device(dw_mipi_dsi_dt_ids, dev); + const struct dw_mipi_dsi_plat_data *pdata = of_id->data; + struct dw_mipi_dsi *dsi; + int ret; + + dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return -ENOMEM; + + dsi->dev = dev; + dsi->pdata = pdata; + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; + dsi->dsi_host.dev = &pdev->dev; + + ret = mipi_dsi_host_register(&dsi->dsi_host); + if (ret) + return ret; + + platform_set_drvdata(pdev, dsi); + ret = component_add(&pdev->dev, &dw_mipi_dsi_ops); + if (ret) + mipi_dsi_host_unregister(&dsi->dsi_host); + + return ret; } static int dw_mipi_dsi_remove(struct platform_device *pdev) { + struct dw_mipi_dsi *dsi = dev_get_drvdata(&pdev->dev); + + if (dsi) + mipi_dsi_host_unregister(&dsi->dsi_host); component_del(&pdev->dev, &dw_mipi_dsi_ops); return 0; }