aboutsummaryrefslogtreecommitdiff
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.c190
1 files changed, 70 insertions, 120 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 7fbf391c024f..18fa30e1e858 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -21,6 +21,7 @@
#include <video/mipi_display.h>
+#include <drm/display/drm_dsc_helper.h>
#include <drm/drm_of.h>
#include "dsi.h"
@@ -33,7 +34,7 @@
#define DSI_RESET_TOGGLE_DELAY_MS 20
-static int dsi_populate_dsc_params(struct drm_dsc_config *dsc);
+static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc);
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
{
@@ -121,6 +122,7 @@ struct msm_dsi_host {
struct clk *byte_intf_clk;
unsigned long byte_clk_rate;
+ unsigned long byte_intf_clk_rate;
unsigned long pixel_clk_rate;
unsigned long esc_clk_rate;
@@ -397,7 +399,6 @@ int msm_dsi_runtime_resume(struct device *dev)
int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
{
- unsigned long byte_intf_rate;
int ret;
DBG("Set clk rates: pclk=%d, byteclk=%lu",
@@ -417,13 +418,7 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
}
if (msm_host->byte_intf_clk) {
- /* For CPHY, byte_intf_clk is same as byte_clk */
- if (msm_host->cphy_mode)
- byte_intf_rate = msm_host->byte_clk_rate;
- else
- byte_intf_rate = msm_host->byte_clk_rate / 2;
-
- ret = clk_set_rate(msm_host->byte_intf_clk, byte_intf_rate);
+ ret = clk_set_rate(msm_host->byte_intf_clk, msm_host->byte_intf_clk_rate);
if (ret) {
pr_err("%s: Failed to set rate byte intf clk, %d\n",
__func__, ret);
@@ -569,9 +564,8 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host)
clk_disable_unprepare(msm_host->byte_clk);
}
-static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, bool is_bonded_dsi)
{
- struct drm_display_mode *mode = msm_host->mode;
unsigned long pclk_rate;
pclk_rate = mode->clock * 1000;
@@ -588,11 +582,13 @@ static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bo
return pclk_rate;
}
-static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi,
+ const struct drm_display_mode *mode)
{
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
u8 lanes = msm_host->lanes;
u32 bpp = dsi_get_bpp(msm_host->format);
- unsigned long pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi);
+ unsigned long pclk_rate = dsi_get_pclk_rate(mode, is_bonded_dsi);
u64 pclk_bpp = (u64)pclk_rate * bpp;
if (lanes == 0) {
@@ -606,8 +602,14 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
else
do_div(pclk_bpp, (8 * lanes));
- msm_host->pixel_clk_rate = pclk_rate;
- msm_host->byte_clk_rate = pclk_bpp;
+ return pclk_bpp;
+}
+
+static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+{
+ msm_host->pixel_clk_rate = dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi);
+ msm_host->byte_clk_rate = dsi_byte_clk_get_rate(&msm_host->base, is_bonded_dsi,
+ msm_host->mode);
DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate,
msm_host->byte_clk_rate);
@@ -635,7 +637,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
dsi_calc_pclk(msm_host, is_bonded_dsi);
- pclk_bpp = (u64)dsi_get_pclk_rate(msm_host, is_bonded_dsi) * bpp;
+ pclk_bpp = (u64)dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi) * bpp;
do_div(pclk_bpp, 8);
msm_host->src_clk_rate = pclk_bpp;
@@ -842,31 +844,25 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay)
{
struct drm_dsc_config *dsc = msm_host->dsc;
- u32 reg, intf_width, reg_ctrl, reg_ctrl2;
+ u32 reg, reg_ctrl, reg_ctrl2;
u32 slice_per_intf, total_bytes_per_intf;
u32 pkt_per_line;
- u32 bytes_in_slice;
u32 eol_byte_num;
/* first calculate dsc parameters and then program
* compress mode registers
*/
- intf_width = hdisplay;
- slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width);
+ slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width);
- /* If slice_per_pkt is greater than slice_per_intf
+ /*
+ * If slice_count is greater than slice_per_intf
* then default to 1. This can happen during partial
* update.
*/
- if (slice_per_intf > dsc->slice_count)
+ if (dsc->slice_count > slice_per_intf)
dsc->slice_count = 1;
- slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width);
- bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bits_per_pixel, 8);
-
- dsc->slice_chunk_size = bytes_in_slice;
-
- total_bytes_per_intf = bytes_in_slice * slice_per_intf;
+ total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf;
eol_byte_num = total_bytes_per_intf % 3;
pkt_per_line = slice_per_intf / dsc->slice_count;
@@ -892,7 +888,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod
reg_ctrl |= reg;
reg_ctrl2 &= ~DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH__MASK;
- reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(bytes_in_slice);
+ reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(dsc->slice_chunk_size);
dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
@@ -915,6 +911,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
u32 va_end = va_start + mode->vdisplay;
u32 hdisplay = mode->hdisplay;
u32 wc;
+ int ret;
DBG("");
@@ -950,7 +947,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
/* we do the calculations for dsc parameters here so that
* panel can use these parameters
*/
- dsi_populate_dsc_params(dsc);
+ ret = dsi_populate_dsc_params(msm_host, dsc);
+ if (ret)
+ return;
/* Divide the display by 3 but keep back/font porch and
* pulse width same
@@ -990,7 +989,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
if (!msm_host->dsc)
wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
else
- wc = mode->hdisplay / 2 + 1;
+ wc = msm_host->dsc->slice_chunk_size * msm_host->dsc->slice_count + 1;
dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,
DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
@@ -1754,18 +1753,20 @@ static char bpg_offset[DSC_NUM_BUF_RANGES] = {
2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12
};
-static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
-{
- int mux_words_size;
- int groups_per_line, groups_total;
- int min_rate_buffer_size;
- int hrd_delay;
- int pre_num_extra_mux_bits, num_extra_mux_bits;
- int slice_bits;
- int target_bpp_x16;
- int data;
- int final_value, final_scale;
+static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc)
+{
int i;
+ u16 bpp = dsc->bits_per_pixel >> 4;
+
+ if (dsc->bits_per_pixel & 0xf) {
+ DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support fractional bits_per_pixel\n");
+ return -EINVAL;
+ }
+
+ if (dsc->bits_per_component != 8) {
+ DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support bits_per_component != 8 yet\n");
+ return -EOPNOTSUPP;
+ }
dsc->rc_model_size = 8192;
dsc->first_line_bpg_offset = 12;
@@ -1783,16 +1784,21 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
dsc->rc_range_params[i].range_min_qp = min_qp[i];
dsc->rc_range_params[i].range_max_qp = max_qp[i];
- dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i];
+ /*
+ * Range BPG Offset contains two's-complement signed values that fill
+ * 8 bits, yet the registers and DCS PPS field are only 6 bits wide.
+ */
+ dsc->rc_range_params[i].range_bpg_offset = bpg_offset[i] & DSC_RANGE_BPG_OFFSET_MASK;
}
- dsc->initial_offset = 6144; /* Not bpp 12 */
- if (dsc->bits_per_pixel != 8)
+ dsc->initial_offset = 6144; /* Not bpp 12 */
+ if (bpp != 8)
dsc->initial_offset = 2048; /* bpp = 12 */
- mux_words_size = 48; /* bpc == 8/10 */
- if (dsc->bits_per_component == 12)
- mux_words_size = 64;
+ if (dsc->bits_per_component <= 10)
+ dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+ else
+ dsc->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
dsc->initial_xmit_delay = 512;
dsc->initial_scale_value = 32;
@@ -1804,63 +1810,8 @@ static int dsi_populate_dsc_params(struct drm_dsc_config *dsc)
dsc->flatness_max_qp = 12;
dsc->rc_quant_incr_limit0 = 11;
dsc->rc_quant_incr_limit1 = 11;
- dsc->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
-
- /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of
- * params are calculated
- */
- groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3);
- dsc->slice_chunk_size = dsc->slice_width * dsc->bits_per_pixel / 8;
- if ((dsc->slice_width * dsc->bits_per_pixel) % 8)
- dsc->slice_chunk_size++;
-
- /* rbs-min */
- min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset +
- dsc->initial_xmit_delay * dsc->bits_per_pixel +
- groups_per_line * dsc->first_line_bpg_offset;
- hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->bits_per_pixel);
-
- dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
-
- dsc->initial_scale_value = 8 * dsc->rc_model_size /
- (dsc->rc_model_size - dsc->initial_offset);
-
- slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height;
-
- groups_total = groups_per_line * dsc->slice_height;
-
- data = dsc->first_line_bpg_offset * 2048;
-
- dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
-
- pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->bits_per_component + 4) - 2);
-
- num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
- ((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
-
- data = 2048 * (dsc->rc_model_size - dsc->initial_offset + num_extra_mux_bits);
- dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
-
- /* bpp * 16 + 0.5 */
- data = dsc->bits_per_pixel * 16;
- data *= 2;
- data++;
- data /= 2;
- target_bpp_x16 = data;
-
- data = (dsc->initial_xmit_delay * target_bpp_x16) / 16;
- final_value = dsc->rc_model_size - data + num_extra_mux_bits;
- dsc->final_offset = final_value;
-
- final_scale = 8 * dsc->rc_model_size / (dsc->rc_model_size - final_value);
-
- data = (final_scale - 9) * (dsc->nfl_bpg_offset + dsc->slice_bpg_offset);
- dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
-
- dsc->scale_decrement_interval = groups_per_line / (dsc->initial_scale_value - 8);
-
- return 0;
+ return drm_dsc_compute_rc_parameters(dsc);
}
static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
@@ -1934,8 +1885,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
if (!msm_host) {
- ret = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
msm_host->pdev = pdev;
@@ -1944,31 +1894,28 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
ret = dsi_host_parse_dt(msm_host);
if (ret) {
pr_err("%s: failed to parse dt\n", __func__);
- goto fail;
+ return ret;
}
msm_host->ctrl_base = msm_ioremap_size(pdev, "dsi_ctrl", &msm_host->ctrl_size);
if (IS_ERR(msm_host->ctrl_base)) {
pr_err("%s: unable to map Dsi ctrl base\n", __func__);
- ret = PTR_ERR(msm_host->ctrl_base);
- goto fail;
+ return PTR_ERR(msm_host->ctrl_base);
}
pm_runtime_enable(&pdev->dev);
msm_host->cfg_hnd = dsi_get_config(msm_host);
if (!msm_host->cfg_hnd) {
- ret = -EINVAL;
pr_err("%s: get config failed\n", __func__);
- goto fail;
+ return -EINVAL;
}
cfg = msm_host->cfg_hnd->cfg;
msm_host->id = dsi_host_get_id(msm_host);
if (msm_host->id < 0) {
- ret = msm_host->id;
pr_err("%s: unable to identify DSI host index\n", __func__);
- goto fail;
+ return msm_host->id;
}
/* fixup base address by io offset */
@@ -1978,19 +1925,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
cfg->regulator_data,
&msm_host->supplies);
if (ret)
- goto fail;
+ return ret;
ret = dsi_clk_init(msm_host);
if (ret) {
pr_err("%s: unable to initialize dsi clks\n", __func__);
- goto fail;
+ return ret;
}
msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL);
if (!msm_host->rx_buf) {
- ret = -ENOMEM;
pr_err("%s: alloc rx temp buf failed\n", __func__);
- goto fail;
+ return -ENOMEM;
}
ret = devm_pm_opp_set_clkname(&pdev->dev, "byte");
@@ -2028,15 +1974,15 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
/* setup workqueue */
msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
+ if (!msm_host->workqueue)
+ return -ENOMEM;
+
INIT_WORK(&msm_host->err_work, dsi_err_worker);
msm_dsi->id = msm_host->id;
DBG("Dsi Host %d initialized", msm_host->id);
return 0;
-
-fail:
- return ret;
}
void msm_dsi_host_destroy(struct mipi_dsi_host *host)
@@ -2442,6 +2388,10 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
goto unlock_ret;
}
+ msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate;
+ if (phy_shared_timings->byte_intf_clk_div_2)
+ msm_host->byte_intf_clk_rate /= 2;
+
msm_dsi_sfpb_config(msm_host, true);
ret = regulator_bulk_enable(msm_host->cfg_hnd->cfg->num_regulators,