summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dsi/dsi_host.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dsi/dsi_host.c')
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c136
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);