diff options
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/dsi_host.c')
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_host.c | 136 |
1 files changed, 69 insertions, 67 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index deeecdfd6c4e..007311c21fda 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -7,7 +7,6 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/mfd/syscon.h> #include <linux/of.h> @@ -55,7 +54,7 @@ static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) * scratch register which we never touch) */ - ver = msm_readl(base + REG_DSI_VERSION); + ver = readl(base + REG_DSI_VERSION); if (ver) { /* older dsi host, there is no register shift */ ver = FIELD(ver, DSI_VERSION_MAJOR); @@ -73,12 +72,12 @@ static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) * registers are shifted down, read DSI_VERSION again with * the shifted offset */ - ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION); + ver = readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION); ver = FIELD(ver, DSI_VERSION_MAJOR); if (ver == MSM_DSI_VER_MAJOR_6G) { /* 6G version */ *major = ver; - *minor = msm_readl(base + REG_DSI_6G_HW_VERSION); + *minor = readl(base + REG_DSI_6G_HW_VERSION); return 0; } else { return -EINVAL; @@ -130,9 +129,6 @@ struct msm_dsi_host { unsigned long src_clk_rate; - struct gpio_desc *disp_en_gpio; - struct gpio_desc *te_gpio; - const struct msm_dsi_cfg_handler *cfg_hnd; struct completion dma_comp; @@ -183,24 +179,14 @@ struct msm_dsi_host { int irq; }; -static u32 dsi_get_bpp(const enum mipi_dsi_pixel_format fmt) -{ - switch (fmt) { - case MIPI_DSI_FMT_RGB565: return 16; - case MIPI_DSI_FMT_RGB666_PACKED: return 18; - case MIPI_DSI_FMT_RGB666: - case MIPI_DSI_FMT_RGB888: - default: return 24; - } -} static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg) { - return msm_readl(msm_host->ctrl_base + reg); + return readl(msm_host->ctrl_base + reg); } static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data) { - msm_writel(data, msm_host->ctrl_base + reg); + writel(data, msm_host->ctrl_base + reg); } static const struct msm_dsi_cfg_handler *dsi_get_config( @@ -366,8 +352,8 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) { int ret; - DBG("Set clk rates: pclk=%d, byteclk=%lu", - msm_host->mode->clock, msm_host->byte_clk_rate); + DBG("Set clk rates: pclk=%lu, byteclk=%lu", + msm_host->pixel_clk_rate, msm_host->byte_clk_rate); ret = dev_pm_opp_set_rate(&msm_host->pdev->dev, msm_host->byte_clk_rate); @@ -440,9 +426,9 @@ int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) { int ret; - DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", - msm_host->mode->clock, msm_host->byte_clk_rate, - msm_host->esc_clk_rate, msm_host->src_clk_rate); + DBG("Set clk rates: pclk=%lu, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu", + msm_host->pixel_clk_rate, msm_host->byte_clk_rate, + msm_host->esc_clk_rate, msm_host->src_clk_rate); ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); if (ret) { @@ -529,6 +515,25 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } +/** + * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case + * @mode: The selected mode for the DSI output + * @dsc: DRM DSC configuration for this DSI output + * + * Adjust the pclk rate by calculating a new hdisplay proportional to + * the compression ratio such that: + * new_hdisplay = old_hdisplay * compressed_bpp / uncompressed_bpp + * + * Porches do not need to be adjusted: + * - For VIDEO mode they are not compressed by DSC and are passed as is. + * - For CMD mode there are no actual porches. Instead these fields + * currently represent the overhead to the image data transfer. As such, they + * are calculated for the final mode parameters (after the compression) and + * are not to be adjusted too. + * + * FIXME: Reconsider this if/when CMD mode handling is rewritten to use + * transfer time and data overhead as a starting point of the calculations. + */ static unsigned long dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode, const struct drm_dsc_config *dsc) { @@ -537,7 +542,7 @@ static unsigned long dsi_adjust_pclk_for_compression(const struct drm_display_mo int new_htotal = mode->htotal - mode->hdisplay + new_hdisplay; - return new_htotal * mode->vtotal * drm_mode_vrefresh(mode); + return mult_frac(mode->clock * 1000u, new_htotal, mode->htotal); } static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, @@ -545,7 +550,7 @@ static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, { unsigned long pclk_rate; - pclk_rate = mode->clock * 1000; + pclk_rate = mode->clock * 1000u; if (dsc) pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc); @@ -567,7 +572,7 @@ unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_d { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); u8 lanes = msm_host->lanes; - u32 bpp = dsi_get_bpp(msm_host->format); + u32 bpp = mipi_dsi_pixel_format_to_bpp(msm_host->format); unsigned long pclk_rate = dsi_get_pclk_rate(mode, msm_host->dsc, is_bonded_dsi); unsigned long pclk_bpp; @@ -610,7 +615,7 @@ int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi) int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi) { - u32 bpp = dsi_get_bpp(msm_host->format); + u32 bpp = mipi_dsi_pixel_format_to_bpp(msm_host->format); unsigned int esc_mhz, esc_div; unsigned long byte_mhz; @@ -745,6 +750,8 @@ static void dsi_ctrl_enable(struct msm_dsi_host *msm_host, data |= DSI_VID_CFG0_TRAFFIC_MODE(dsi_get_traffic_mode(flags)); data |= DSI_VID_CFG0_DST_FORMAT(dsi_get_vid_fmt(mipi_fmt)); data |= DSI_VID_CFG0_VIRT_CHANNEL(msm_host->channel); + if (msm_dsi_host_is_wide_bus_enabled(&msm_host->base)) + data |= DSI_VID_CFG0_DATABUS_WIDEN; dsi_write(msm_host, REG_DSI_VID_CFG0, data); /* Do not swap RGB colors */ @@ -769,7 +776,6 @@ static void dsi_ctrl_enable(struct msm_dsi_host *msm_host, if (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_3) data |= DSI_CMD_MODE_MDP_CTRL2_BURST_MODE; - /* TODO: Allow for video-mode support once tested/fixed */ if (msm_dsi_host_is_wide_bus_enabled(&msm_host->base)) data |= DSI_CMD_MODE_MDP_CTRL2_DATABUS_WIDEN; @@ -847,6 +853,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod u32 slice_per_intf, total_bytes_per_intf; u32 pkt_per_line; u32 eol_byte_num; + u32 bytes_per_pkt; /* first calculate dsc parameters and then program * compress mode registers @@ -854,6 +861,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod slice_per_intf = msm_dsc_get_slices_per_intf(dsc, hdisplay); total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; + bytes_per_pkt = dsc->slice_chunk_size; /* * slice_per_pkt; */ eol_byte_num = total_bytes_per_intf % 3; @@ -873,7 +881,11 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod /* DSI_VIDEO_COMPRESSION_MODE & DSI_COMMAND_COMPRESSION_MODE * registers have similar offsets, so for below common code use * DSI_VIDEO_COMPRESSION_MODE_XXXX for setting bits + * + * pkt_per_line is log2 encoded, >>1 works for supported values (1,2,4) */ + if (pkt_per_line > 4) + drm_warn_once(msm_host->dev, "pkt_per_line too big"); reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_PKT_PER_LINE(pkt_per_line >> 1); reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_EOL_BYTE_NUM(eol_byte_num); reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_EN; @@ -891,6 +903,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); } else { + reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_WC(bytes_per_pkt); dsi_write(msm_host, REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg); } } @@ -951,8 +964,18 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) if (ret) return; - /* Divide the display by 3 but keep back/font porch and - * pulse width same + /* + * DPU sends 3 bytes per pclk cycle to DSI. If widebus is + * enabled, bus width is extended to 6 bytes. + * + * Calculate the number of pclks needed to transmit one line of + * the compressed data. + + * The back/font porch and pulse width are kept intact. For + * VIDEO mode they represent timing parameters rather than + * actual data transfer, see the documentation for + * dsi_adjust_pclk_for_compression(). For CMD mode they are + * unused anyway. */ h_total -= hdisplay; if (wide_bus_enabled && !(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)) @@ -993,7 +1016,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) /* image data and 1 byte write_memory_start cmd */ if (!msm_host->dsc) - wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1; + wc = hdisplay * mipi_dsi_pixel_format_to_bpp(msm_host->format) / 8 + 1; else /* * When DSC is enabled, WC = slice_chunk_size * slice_per_pkt + 1. @@ -1413,7 +1436,7 @@ static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host, { int len, ret; int bllp_len = msm_host->mode->hdisplay * - dsi_get_bpp(msm_host->format) / 8; + mipi_dsi_pixel_format_to_bpp(msm_host->format) / 8; len = dsi_cmd_dma_add(msm_host, msg); if (len < 0) { @@ -1594,28 +1617,6 @@ static irqreturn_t dsi_host_irq(int irq, void *ptr) return IRQ_HANDLED; } -static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host, - struct device *panel_device) -{ - msm_host->disp_en_gpio = devm_gpiod_get_optional(panel_device, - "disp-enable", - GPIOD_OUT_LOW); - if (IS_ERR(msm_host->disp_en_gpio)) { - DBG("cannot get disp-enable-gpios %ld", - PTR_ERR(msm_host->disp_en_gpio)); - return PTR_ERR(msm_host->disp_en_gpio); - } - - msm_host->te_gpio = devm_gpiod_get_optional(panel_device, "disp-te", - GPIOD_IN); - if (IS_ERR(msm_host->te_gpio)) { - DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio)); - return PTR_ERR(msm_host->te_gpio); - } - - return 0; -} - static int dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi) { @@ -1632,11 +1633,6 @@ static int dsi_host_attach(struct mipi_dsi_host *host, if (dsi->dsc) msm_host->dsc = dsi->dsc; - /* Some gpios defined in panel DT need to be controlled by host */ - ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev); - if (ret) - return ret; - ret = dsi_dev_attach(msm_host->pdev); if (ret) return ret; @@ -1798,9 +1794,11 @@ static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) { + struct msm_dsi *msm_dsi = platform_get_drvdata(msm_host->pdev); struct device *dev = &msm_host->pdev->dev; struct device_node *np = dev->of_node; struct device_node *endpoint; + const char *te_source; int ret = 0; /* @@ -1823,7 +1821,17 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) goto err; } - if (of_property_read_bool(np, "syscon-sfpb")) { + ret = of_property_read_string(endpoint, "qcom,te-source", &te_source); + if (ret && ret != -EINVAL) { + DRM_DEV_ERROR(dev, "%s: invalid TE source configuration %d\n", + __func__, ret); + goto err; + } + if (!ret) + msm_dsi->te_source = devm_kstrdup(dev, te_source, GFP_KERNEL); + ret = 0; + + if (of_property_present(np, "syscon-sfpb")) { msm_host->sfpb = syscon_regmap_lookup_by_phandle(np, "syscon-sfpb"); if (IS_ERR(msm_host->sfpb)) { @@ -2403,9 +2411,6 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, dsi_sw_reset(msm_host); dsi_ctrl_enable(msm_host, phy_shared_timings, phy); - if (msm_host->disp_en_gpio) - gpiod_set_value(msm_host->disp_en_gpio, 1); - msm_host->power_on = true; mutex_unlock(&msm_host->dev_mutex); @@ -2435,9 +2440,6 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host) dsi_ctrl_disable(msm_host); - if (msm_host->disp_en_gpio) - gpiod_set_value(msm_host->disp_en_gpio, 0); - pinctrl_pm_select_sleep_state(&msm_host->pdev->dev); cfg_hnd->ops->link_clk_disable(msm_host); |