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=aac04532bcd695b784536479c4216ade72300167;hpb=d0879670cfce7b98bb7e8b94b669f04dfd96d415;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 aac04532bcd6..38e4811be728 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -91,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 @@ -277,6 +282,8 @@ struct dw_mipi_dsi_plat_data { 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); }; @@ -285,23 +292,24 @@ 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; - int dpms_mode; unsigned int lane_mbps; /* per lane */ u32 channel; u32 lanes; 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; }; @@ -349,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); } @@ -456,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 | @@ -499,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; @@ -541,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; } @@ -553,11 +560,9 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->panel = of_drm_find_panel(device->dev.of_node); if (!dsi->panel) { DRM_ERROR("failed to find panel\n"); - return -EPROBE_DEFER; + return -ENODEV; } - drm_panel_attach(dsi->panel, &dsi->connector); - return 0; } @@ -569,16 +574,19 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, 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; @@ -587,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; @@ -597,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); @@ -612,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", @@ -638,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, @@ -659,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"); @@ -683,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); } @@ -778,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++; @@ -789,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; @@ -808,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; @@ -823,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)); @@ -849,48 +863,14 @@ 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; - - if (dsi->dpms_mode == DRM_MODE_DPMS_ON) - return; - - 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; - } - - pm_runtime_get_sync(dsi->dev); - - 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) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); - if (dsi->dpms_mode != DRM_MODE_DPMS_ON) - return; - drm_panel_disable(dsi->panel); if (clk_prepare_enable(dsi->pclk)) { @@ -910,9 +890,9 @@ 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); - dsi->dpms_mode = DRM_MODE_DPMS_OFF; } static bool dw_mipi_dsi_encoder_mode_fixup(struct drm_encoder *encoder, @@ -922,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); 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)) { @@ -934,11 +915,51 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) return; } + 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); - dw_mipi_dsi_phy_init(dsi); + 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); @@ -946,6 +967,9 @@ 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 @@ -953,7 +977,6 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder) regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); - dsi->dpms_mode = DRM_MODE_DPMS_ON; } static int @@ -963,6 +986,8 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, { 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: @@ -980,6 +1005,8 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, } s->output_type = DRM_MODE_CONNECTOR_DSI; + if (info->num_bus_formats) + s->bus_format = info->bus_formats[0]; return 0; } @@ -987,8 +1014,8 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder, 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, }; @@ -1026,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, @@ -1089,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; @@ -1112,6 +1156,8 @@ static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { .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, }; static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { @@ -1121,6 +1167,13 @@ static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .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 rk3368_mipi_dsi_drv_data = { + .max_data_lanes = 4, + .max_bit_rate_per_lane = 1000000000, }; static const struct of_device_id dw_mipi_dsi_dt_ids[] = { @@ -1130,6 +1183,9 @@ static const struct of_device_id dw_mipi_dsi_dt_ids[] = { },{ .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_mipi_dsi_drv_data, + }, { + .compatible = "rockchip,rk3368-mipi-dsi", + .data = &rk3368_mipi_dsi_drv_data, }, { /* sentinel */ } }; @@ -1138,27 +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; - dsi->dpms_mode = DRM_MODE_DPMS_OFF; + 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; @@ -1167,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); @@ -1181,9 +1229,19 @@ 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_dbg(dev, "have not phy_cfg_clk\n"); + 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) { @@ -1191,6 +1249,12 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, 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); @@ -1201,9 +1265,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, pm_runtime_enable(dev); - dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; - dsi->dsi_host.dev = dev; - return mipi_dsi_host_register(&dsi->dsi_host); + return 0; err_pllref: clk_disable_unprepare(dsi->pllref_clk); @@ -1215,7 +1277,6 @@ 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); } @@ -1227,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; }