diff mbox series

[10/11] drm/msm/dsi: Add support for DSC configuration

Message ID 20210715065203.709914-11-vkoul@kernel.org
State Superseded
Headers show
Series [01/11] drm/msm/dsi: add support for dsc data | expand

Commit Message

Vinod Koul July 15, 2021, 6:52 a.m. UTC
When DSC is enabled, we need to configure DSI registers accordingly and
configure the respective stream compression registers.

Add support to calculate the register setting based on DSC params and
timing information and configure these registers.

Signed-off-by: Vinod Koul <vkoul@kernel.org>

---
 drivers/gpu/drm/msm/dsi/dsi.xml.h  |  10 ++
 drivers/gpu/drm/msm/dsi/dsi_host.c | 142 +++++++++++++++++++++++++++--
 2 files changed, 142 insertions(+), 10 deletions(-)

-- 
2.31.1

Comments

kernel test robot July 19, 2021, 9:26 a.m. UTC | #1
Hi Vinod,

I love your patch! Perhaps something to improve:

[auto build test WARNING on v5.13]
[cannot apply to linus/master v5.14-rc1 next-20210716]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Vinod-Koul/drm-msm-Add-Display-Stream-Compression-Support/20210715-145540
base:    62fb9874f5da54fdb243003b386128037319b219
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/67410f51d0cd25256b7926c30f27071291244ef3
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Vinod-Koul/drm-msm-Add-Display-Stream-Compression-Support/20210715-145540
        git checkout 67410f51d0cd25256b7926c30f27071291244ef3
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/msm/dsi/dsi_host.c: In function 'dsi_timing_setup':
>> drivers/gpu/drm/msm/dsi/dsi_host.c:1022:41: warning: variable 'width' set but not used [-Wunused-but-set-variable]

    1022 |    u32 reg, intf_width, slice_per_intf, width;
         |                                         ^~~~~


vim +/width +1022 drivers/gpu/drm/msm/dsi/dsi_host.c

   964	
   965	static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)
   966	{
   967		struct drm_display_mode *mode = msm_host->mode;
   968		u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */
   969		u32 h_total = mode->htotal;
   970		u32 v_total = mode->vtotal;
   971		u32 hs_end = mode->hsync_end - mode->hsync_start;
   972		u32 vs_end = mode->vsync_end - mode->vsync_start;
   973		u32 ha_start = h_total - mode->hsync_start;
   974		u32 ha_end = ha_start + mode->hdisplay;
   975		u32 va_start = v_total - mode->vsync_start;
   976		u32 va_end = va_start + mode->vdisplay;
   977		u32 hdisplay = mode->hdisplay;
   978		u32 wc;
   979		u32 data;
   980	
   981		DBG("");
   982	
   983		/*
   984		 * For dual DSI mode, the current DRM mode has
   985		 * the complete width of the panel. Since, the complete
   986		 * panel is driven by two DSI controllers, the horizontal
   987		 * timings have to be split between the two dsi controllers.
   988		 * Adjust the DSI host timing values accordingly.
   989		 */
   990		if (is_dual_dsi) {
   991			h_total /= 2;
   992			hs_end /= 2;
   993			ha_start /= 2;
   994			ha_end /= 2;
   995			hdisplay /= 2;
   996		}
   997	
   998		if (msm_host->dsc) {
   999			struct msm_display_dsc_config *dsc = msm_host->dsc;
  1000	
  1001			/* update dsc params with timing params */
  1002			dsi_dsc_update_pic_dim(dsc, mode->hdisplay, mode->vdisplay);
  1003			DBG("Mode Width- %d x Height %d\n", dsc->drm->pic_width, dsc->drm->pic_height);
  1004	
  1005			/* we do the calculations for dsc parameters here so that
  1006			 * panel can use these parameters
  1007			 */
  1008			dsi_populate_dsc_params(dsc);
  1009	
  1010			/* Divide the display by 3 but keep back/font porch and
  1011			 * pulse width same
  1012			 */
  1013			h_total -= hdisplay;
  1014			hdisplay /= 3;
  1015			h_total += hdisplay;
  1016			ha_end = ha_start + hdisplay;
  1017		}
  1018	
  1019		if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
  1020			if (msm_host->dsc) {
  1021				struct msm_display_dsc_config *dsc = msm_host->dsc;
> 1022				u32 reg, intf_width, slice_per_intf, width;

  1023				u32 total_bytes_per_intf;
  1024	
  1025				/* first calculate dsc parameters and then program
  1026				 * compress mode registers
  1027				 */
  1028				intf_width = hdisplay;
  1029				slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width);
  1030	
  1031				/* If slice_count > slice_per_intf, then use 1
  1032				 * This can happen during partial update
  1033				 */
  1034					dsc->drm->slice_count = 1;
  1035	
  1036				dsc->bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * 8, 8);
  1037				total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
  1038	
  1039				dsc->eol_byte_num = total_bytes_per_intf % 3;
  1040				dsc->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
  1041				dsc->bytes_per_pkt = dsc->bytes_in_slice * dsc->drm->slice_count;
  1042				dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
  1043	
  1044				width = dsc->pclk_per_line;
  1045				reg = dsc->bytes_per_pkt << 16;
  1046				reg |= (0x0b << 8);    /* dtype of compressed image */
  1047	
  1048				/* pkt_per_line:
  1049				 * 0 == 1 pkt
  1050				 * 1 == 2 pkt
  1051				 * 2 == 4 pkt
  1052				 * 3 pkt is not supported
  1053				 * above translates to ffs() - 1
  1054				 */
  1055				reg |= (ffs(dsc->pkt_per_line) - 1) << 6;
  1056	
  1057				dsc->eol_byte_num = total_bytes_per_intf % 3;
  1058				reg |= dsc->eol_byte_num << 4;
  1059				reg |= 1;
  1060	
  1061				dsi_write(msm_host,
  1062					  REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg);
  1063			}
  1064	
  1065			dsi_write(msm_host, REG_DSI_ACTIVE_H,
  1066				DSI_ACTIVE_H_START(ha_start) |
  1067				DSI_ACTIVE_H_END(ha_end));
  1068			dsi_write(msm_host, REG_DSI_ACTIVE_V,
  1069				DSI_ACTIVE_V_START(va_start) |
  1070				DSI_ACTIVE_V_END(va_end));
  1071			dsi_write(msm_host, REG_DSI_TOTAL,
  1072				DSI_TOTAL_H_TOTAL(h_total - 1) |
  1073				DSI_TOTAL_V_TOTAL(v_total - 1));
  1074	
  1075			dsi_write(msm_host, REG_DSI_ACTIVE_HSYNC,
  1076				DSI_ACTIVE_HSYNC_START(hs_start) |
  1077				DSI_ACTIVE_HSYNC_END(hs_end));
  1078			dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_HPOS, 0);
  1079			dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_VPOS,
  1080				DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |
  1081				DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
  1082		} else {		/* command mode */
  1083			if (msm_host->dsc) {
  1084				struct msm_display_dsc_config *dsc = msm_host->dsc;
  1085				u32 reg, reg_ctrl, reg_ctrl2;
  1086				u32 slice_per_intf, bytes_in_slice, total_bytes_per_intf;
  1087	
  1088				reg_ctrl = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL);
  1089				reg_ctrl2 = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2);
  1090	
  1091				slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->drm->slice_width);
  1092				bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width *
  1093							      dsc->drm->bits_per_pixel, 8);
  1094				dsc->drm->slice_chunk_size = bytes_in_slice;
  1095				total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
  1096				dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
  1097	
  1098				reg = 0x39 << 8;
  1099				reg |= ffs(dsc->pkt_per_line) << 6;
  1100	
  1101				dsc->eol_byte_num = total_bytes_per_intf % 3;
  1102				reg |= dsc->eol_byte_num << 4;
  1103				reg |= 1;
  1104	
  1105				reg_ctrl |= reg;
  1106				reg_ctrl2 |= bytes_in_slice;
  1107	
  1108				dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg);
  1109				dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
  1110			}
  1111	
  1112			/* image data and 1 byte write_memory_start cmd */
  1113			if (!msm_host->dsc)
  1114				wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
  1115			else
  1116				wc = mode->hdisplay / 2 + 1;
  1117	
  1118			data = DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
  1119			       DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(msm_host->channel) |
  1120				DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(MIPI_DSI_DCS_LONG_WRITE);
  1121	
  1122			dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, data);
  1123	
  1124			data = DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |
  1125				DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay);
  1126			dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL, data);
  1127		}
  1128	}
  1129	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Dmitry Baryshkov July 29, 2021, 10:10 p.m. UTC | #2
On 15/07/2021 09:52, Vinod Koul wrote:
> When DSC is enabled, we need to configure DSI registers accordingly and

> configure the respective stream compression registers.

> 

> Add support to calculate the register setting based on DSC params and

> timing information and configure these registers.

> 

> Signed-off-by: Vinod Koul <vkoul@kernel.org>

> ---

>   drivers/gpu/drm/msm/dsi/dsi.xml.h  |  10 ++

>   drivers/gpu/drm/msm/dsi/dsi_host.c | 142 +++++++++++++++++++++++++++--

>   2 files changed, 142 insertions(+), 10 deletions(-)

> 

> diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h

> index 50eb4d1b8fdd..b8e9e608abfc 100644

> --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h

> +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h

> @@ -2310,4 +2310,14 @@ static inline uint32_t REG_DSI_7nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x00000

>   

>   #define REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE			0x00000260

>   

> +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL			0x0000029c

> +

> +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL2			0x000002a0

> +

> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL			0x000002a4

> +

> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2			0x000002a8

> +

> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL3			0x000002ac

> +

>   #endif /* DSI_XML */



Could you please post the patch to mesa3d to add these registers?

> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c

> index e1e5d91809b5..4e8ab1b1df8b 100644

> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c

> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c

> @@ -942,6 +942,26 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,

>   	dsi_write(msm_host, REG_DSI_CTRL, data);

>   }

>   

> +static int dsi_dsc_update_pic_dim(struct msm_display_dsc_config *dsc,

> +				  int pic_width, int pic_height)

> +{

> +	if (!dsc || !pic_width || !pic_height) {

> +		pr_err("DSI: invalid input: pic_width: %d pic_height: %d\n", pic_width, pic_height);

> +		return -EINVAL;

> +	}

> +

> +	if ((pic_width % dsc->drm->slice_width) || (pic_height % dsc->drm->slice_height)) {

> +		pr_err("DSI: pic_dim %dx%d has to be multiple of slice %dx%d\n",

> +		       pic_width, pic_height, dsc->drm->slice_width, dsc->drm->slice_height);

> +		return -EINVAL;

> +	}

> +

> +	dsc->drm->pic_width = pic_width;

> +	dsc->drm->pic_height = pic_height;

> +

> +	return 0;

> +}

> +

>   static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)

>   {

>   	struct drm_display_mode *mode = msm_host->mode;

> @@ -956,6 +976,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)

>   	u32 va_end = va_start + mode->vdisplay;

>   	u32 hdisplay = mode->hdisplay;

>   	u32 wc;

> +	u32 data;

>   

>   	DBG("");

>   

> @@ -974,7 +995,73 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)

>   		hdisplay /= 2;

>   	}

>   

> +	if (msm_host->dsc) {

> +		struct msm_display_dsc_config *dsc = msm_host->dsc;

> +

> +		/* update dsc params with timing params */

> +		dsi_dsc_update_pic_dim(dsc, mode->hdisplay, mode->vdisplay);

> +		DBG("Mode Width- %d x Height %d\n", dsc->drm->pic_width, dsc->drm->pic_height);

> +

> +		/* we do the calculations for dsc parameters here so that

> +		 * panel can use these parameters

> +		 */

> +		dsi_populate_dsc_params(dsc);

> +

> +		/* Divide the display by 3 but keep back/font porch and

> +		 * pulse width same

> +		 */

> +		h_total -= hdisplay;

> +		hdisplay /= 3;

> +		h_total += hdisplay;

> +		ha_end = ha_start + hdisplay;

> +	}

> +

>   	if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {

> +		if (msm_host->dsc) {

> +			struct msm_display_dsc_config *dsc = msm_host->dsc;

> +			u32 reg, intf_width, slice_per_intf, width;

> +			u32 total_bytes_per_intf;

> +

> +			/* first calculate dsc parameters and then program

> +			 * compress mode registers

> +			 */

> +			intf_width = hdisplay;

> +			slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width);

> +

> +			/* If slice_count > slice_per_intf, then use 1

> +			 * This can happen during partial update

> +			 */

> +				dsc->drm->slice_count = 1;

> +

> +			dsc->bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * 8, 8);

> +			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;

> +

> +			dsc->eol_byte_num = total_bytes_per_intf % 3;

> +			dsc->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);

> +			dsc->bytes_per_pkt = dsc->bytes_in_slice * dsc->drm->slice_count;

> +			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;

> +

> +			width = dsc->pclk_per_line;

> +			reg = dsc->bytes_per_pkt << 16;

> +			reg |= (0x0b << 8);    /* dtype of compressed image */

> +

> +			/* pkt_per_line:

> +			 * 0 == 1 pkt

> +			 * 1 == 2 pkt

> +			 * 2 == 4 pkt

> +			 * 3 pkt is not supported

> +			 * above translates to ffs() - 1

> +			 */

> +			reg |= (ffs(dsc->pkt_per_line) - 1) << 6;

> +

> +			dsc->eol_byte_num = total_bytes_per_intf % 3;

> +			reg |= dsc->eol_byte_num << 4;

> +			reg |= 1;

> +

> +			dsi_write(msm_host,

> +				  REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg);

> +		}

> +

>   		dsi_write(msm_host, REG_DSI_ACTIVE_H,

>   			DSI_ACTIVE_H_START(ha_start) |

>   			DSI_ACTIVE_H_END(ha_end));

> @@ -993,19 +1080,50 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)

>   			DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |

>   			DSI_ACTIVE_VSYNC_VPOS_END(vs_end));

>   	} else {		/* command mode */

> +		if (msm_host->dsc) {

> +			struct msm_display_dsc_config *dsc = msm_host->dsc;

> +			u32 reg, reg_ctrl, reg_ctrl2;

> +			u32 slice_per_intf, bytes_in_slice, total_bytes_per_intf;

> +

> +			reg_ctrl = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL);

> +			reg_ctrl2 = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2);

> +

> +			slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->drm->slice_width);

> +			bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width *

> +						      dsc->drm->bits_per_pixel, 8);

> +			dsc->drm->slice_chunk_size = bytes_in_slice;

> +			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;

> +			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;

> +

> +			reg = 0x39 << 8;

> +			reg |= ffs(dsc->pkt_per_line) << 6;

> +

> +			dsc->eol_byte_num = total_bytes_per_intf % 3;

> +			reg |= dsc->eol_byte_num << 4;

> +			reg |= 1;

> +

> +			reg_ctrl |= reg;

> +			reg_ctrl2 |= bytes_in_slice;

> +

> +			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg);

> +			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);

> +		}

> +

>   		/* image data and 1 byte write_memory_start cmd */

> -		wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;

> +		if (!msm_host->dsc)

> +			wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;

> +		else

> +			wc = mode->hdisplay / 2 + 1;

>   

> -		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,

> -			DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |

> -			DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(

> -					msm_host->channel) |

> -			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(

> -					MIPI_DSI_DCS_LONG_WRITE));

> +		data = DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |

> +		       DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(msm_host->channel) |

> +			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(MIPI_DSI_DCS_LONG_WRITE);

>   

> -		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL,

> -			DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |

> -			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay));

> +		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, data);

> +

> +		data = DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |

> +			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay);

> +		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL, data);


Could you please separate this cleanup away.

>   	}

>   }

>   

> @@ -2074,6 +2192,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,

>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);

>   	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;

>   	struct platform_device *pdev = msm_host->pdev;

> +	struct msm_drm_private *priv;

>   	int ret;

>   

>   	msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);

> @@ -2093,6 +2212,9 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,

>   	}

>   

>   	msm_host->dev = dev;

> +	priv = dev->dev_private;

> +	priv->dsc = msm_host->dsc;


I'd prefer not to push dsc config into msm_drm_private and to get it as 
necessary using msm_dsi function calls.

> +

>   	ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);

>   	if (ret) {

>   		pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);

> 



-- 
With best wishes
Dmitry
Abhinav Kumar Aug. 3, 2021, 1:16 a.m. UTC | #3
On 2021-07-14 23:52, Vinod Koul wrote:
> When DSC is enabled, we need to configure DSI registers accordingly and
> configure the respective stream compression registers.
> 
> Add support to calculate the register setting based on DSC params and
> timing information and configure these registers.
> 
> Signed-off-by: Vinod Koul <vkoul@kernel.org>

same comments as dmitry on this one: 
https://patchwork.freedesktop.org/patch/444082/?series=90413&rev=2
nothing more to add.

> ---
>  drivers/gpu/drm/msm/dsi/dsi.xml.h  |  10 ++
>  drivers/gpu/drm/msm/dsi/dsi_host.c | 142 +++++++++++++++++++++++++++--
>  2 files changed, 142 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h
> b/drivers/gpu/drm/msm/dsi/dsi.xml.h
> index 50eb4d1b8fdd..b8e9e608abfc 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h
> @@ -2310,4 +2310,14 @@ static inline uint32_t
> REG_DSI_7nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x00000
> 
>  #define REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE			0x00000260
> 
> +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL			0x0000029c
> +
> +#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL2			0x000002a0
> +
> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL			0x000002a4
> +
> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2			0x000002a8
> +
> +#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL3			0x000002ac
> +
>  #endif /* DSI_XML */
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c
> b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index e1e5d91809b5..4e8ab1b1df8b 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -942,6 +942,26 @@ static void dsi_ctrl_config(struct msm_dsi_host
> *msm_host, bool enable,
>  	dsi_write(msm_host, REG_DSI_CTRL, data);
>  }
> 
> +static int dsi_dsc_update_pic_dim(struct msm_display_dsc_config *dsc,
> +				  int pic_width, int pic_height)
> +{
> +	if (!dsc || !pic_width || !pic_height) {
> +		pr_err("DSI: invalid input: pic_width: %d pic_height: %d\n",
> pic_width, pic_height);
> +		return -EINVAL;
> +	}
> +
> +	if ((pic_width % dsc->drm->slice_width) || (pic_height %
> dsc->drm->slice_height)) {
> +		pr_err("DSI: pic_dim %dx%d has to be multiple of slice %dx%d\n",
> +		       pic_width, pic_height, dsc->drm->slice_width, 
> dsc->drm->slice_height);
> +		return -EINVAL;
> +	}
> +
> +	dsc->drm->pic_width = pic_width;
> +	dsc->drm->pic_height = pic_height;
> +
> +	return 0;
> +}
> +
>  static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool 
> is_dual_dsi)
>  {
>  	struct drm_display_mode *mode = msm_host->mode;
> @@ -956,6 +976,7 @@ static void dsi_timing_setup(struct msm_dsi_host
> *msm_host, bool is_dual_dsi)
>  	u32 va_end = va_start + mode->vdisplay;
>  	u32 hdisplay = mode->hdisplay;
>  	u32 wc;
> +	u32 data;
> 
>  	DBG("");
> 
> @@ -974,7 +995,73 @@ static void dsi_timing_setup(struct msm_dsi_host
> *msm_host, bool is_dual_dsi)
>  		hdisplay /= 2;
>  	}
> 
> +	if (msm_host->dsc) {
> +		struct msm_display_dsc_config *dsc = msm_host->dsc;
> +
> +		/* update dsc params with timing params */
> +		dsi_dsc_update_pic_dim(dsc, mode->hdisplay, mode->vdisplay);
> +		DBG("Mode Width- %d x Height %d\n", dsc->drm->pic_width,
> dsc->drm->pic_height);
> +
> +		/* we do the calculations for dsc parameters here so that
> +		 * panel can use these parameters
> +		 */
> +		dsi_populate_dsc_params(dsc);
> +
> +		/* Divide the display by 3 but keep back/font porch and
> +		 * pulse width same
> +		 */
> +		h_total -= hdisplay;
> +		hdisplay /= 3;
> +		h_total += hdisplay;
> +		ha_end = ha_start + hdisplay;
> +	}
> +
>  	if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
> +		if (msm_host->dsc) {
> +			struct msm_display_dsc_config *dsc = msm_host->dsc;
> +			u32 reg, intf_width, slice_per_intf, width;
> +			u32 total_bytes_per_intf;
> +
> +			/* first calculate dsc parameters and then program
> +			 * compress mode registers
> +			 */
> +			intf_width = hdisplay;
> +			slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width);
> +
> +			/* If slice_count > slice_per_intf, then use 1
> +			 * This can happen during partial update
> +			 */
> +				dsc->drm->slice_count = 1;
> +
> +			dsc->bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * 8, 8);
> +			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
> +
> +			dsc->eol_byte_num = total_bytes_per_intf % 3;
> +			dsc->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
> +			dsc->bytes_per_pkt = dsc->bytes_in_slice * dsc->drm->slice_count;
> +			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
> +
> +			width = dsc->pclk_per_line;
> +			reg = dsc->bytes_per_pkt << 16;
> +			reg |= (0x0b << 8);    /* dtype of compressed image */
> +
> +			/* pkt_per_line:
> +			 * 0 == 1 pkt
> +			 * 1 == 2 pkt
> +			 * 2 == 4 pkt
> +			 * 3 pkt is not supported
> +			 * above translates to ffs() - 1
> +			 */
> +			reg |= (ffs(dsc->pkt_per_line) - 1) << 6;
> +
> +			dsc->eol_byte_num = total_bytes_per_intf % 3;
> +			reg |= dsc->eol_byte_num << 4;
> +			reg |= 1;
> +
> +			dsi_write(msm_host,
> +				  REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg);
> +		}
> +
>  		dsi_write(msm_host, REG_DSI_ACTIVE_H,
>  			DSI_ACTIVE_H_START(ha_start) |
>  			DSI_ACTIVE_H_END(ha_end));
> @@ -993,19 +1080,50 @@ static void dsi_timing_setup(struct
> msm_dsi_host *msm_host, bool is_dual_dsi)
>  			DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |
>  			DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
>  	} else {		/* command mode */
> +		if (msm_host->dsc) {
> +			struct msm_display_dsc_config *dsc = msm_host->dsc;
> +			u32 reg, reg_ctrl, reg_ctrl2;
> +			u32 slice_per_intf, bytes_in_slice, total_bytes_per_intf;
> +
> +			reg_ctrl = dsi_read(msm_host, 
> REG_DSI_COMMAND_COMPRESSION_MODE_CTRL);
> +			reg_ctrl2 = dsi_read(msm_host, 
> REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2);
> +
> +			slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->drm->slice_width);
> +			bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width *
> +						      dsc->drm->bits_per_pixel, 8);
> +			dsc->drm->slice_chunk_size = bytes_in_slice;
> +			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
> +			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
> +
> +			reg = 0x39 << 8;
> +			reg |= ffs(dsc->pkt_per_line) << 6;
> +
> +			dsc->eol_byte_num = total_bytes_per_intf % 3;
> +			reg |= dsc->eol_byte_num << 4;
> +			reg |= 1;
> +
> +			reg_ctrl |= reg;
> +			reg_ctrl2 |= bytes_in_slice;
> +
> +			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg);
> +			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, 
> reg_ctrl2);
> +		}
> +
>  		/* image data and 1 byte write_memory_start cmd */
> -		wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
> +		if (!msm_host->dsc)
> +			wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
> +		else
> +			wc = mode->hdisplay / 2 + 1;
> 
> -		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,
> -			DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
> -			DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(
> -					msm_host->channel) |
> -			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(
> -					MIPI_DSI_DCS_LONG_WRITE));
> +		data = DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
> +		       DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(msm_host->channel) |
> +			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(MIPI_DSI_DCS_LONG_WRITE);
> 
> -		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL,
> -			DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |
> -			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay));
> +		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, data);
> +
> +		data = DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |
> +			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay);
> +		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL, data);
>  	}
>  }
> 
> @@ -2074,6 +2192,7 @@ int msm_dsi_host_modeset_init(struct 
> mipi_dsi_host *host,
>  	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>  	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
>  	struct platform_device *pdev = msm_host->pdev;
> +	struct msm_drm_private *priv;
>  	int ret;
> 
>  	msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
> @@ -2093,6 +2212,9 @@ int msm_dsi_host_modeset_init(struct 
> mipi_dsi_host *host,
>  	}
> 
>  	msm_host->dev = dev;
> +	priv = dev->dev_private;
> +	priv->dsc = msm_host->dsc;
> +
>  	ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
>  	if (ret) {
>  		pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);
diff mbox series

Patch

diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h
index 50eb4d1b8fdd..b8e9e608abfc 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.xml.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h
@@ -2310,4 +2310,14 @@  static inline uint32_t REG_DSI_7nm_PHY_LN_TX_DCTRL(uint32_t i0) { return 0x00000
 
 #define REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE			0x00000260
 
+#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL			0x0000029c
+
+#define REG_DSI_VIDEO_COMPRESSION_MODE_CTRL2			0x000002a0
+
+#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL			0x000002a4
+
+#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2			0x000002a8
+
+#define REG_DSI_COMMAND_COMPRESSION_MODE_CTRL3			0x000002ac
+
 #endif /* DSI_XML */
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index e1e5d91809b5..4e8ab1b1df8b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -942,6 +942,26 @@  static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable,
 	dsi_write(msm_host, REG_DSI_CTRL, data);
 }
 
+static int dsi_dsc_update_pic_dim(struct msm_display_dsc_config *dsc,
+				  int pic_width, int pic_height)
+{
+	if (!dsc || !pic_width || !pic_height) {
+		pr_err("DSI: invalid input: pic_width: %d pic_height: %d\n", pic_width, pic_height);
+		return -EINVAL;
+	}
+
+	if ((pic_width % dsc->drm->slice_width) || (pic_height % dsc->drm->slice_height)) {
+		pr_err("DSI: pic_dim %dx%d has to be multiple of slice %dx%d\n",
+		       pic_width, pic_height, dsc->drm->slice_width, dsc->drm->slice_height);
+		return -EINVAL;
+	}
+
+	dsc->drm->pic_width = pic_width;
+	dsc->drm->pic_height = pic_height;
+
+	return 0;
+}
+
 static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)
 {
 	struct drm_display_mode *mode = msm_host->mode;
@@ -956,6 +976,7 @@  static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)
 	u32 va_end = va_start + mode->vdisplay;
 	u32 hdisplay = mode->hdisplay;
 	u32 wc;
+	u32 data;
 
 	DBG("");
 
@@ -974,7 +995,73 @@  static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)
 		hdisplay /= 2;
 	}
 
+	if (msm_host->dsc) {
+		struct msm_display_dsc_config *dsc = msm_host->dsc;
+
+		/* update dsc params with timing params */
+		dsi_dsc_update_pic_dim(dsc, mode->hdisplay, mode->vdisplay);
+		DBG("Mode Width- %d x Height %d\n", dsc->drm->pic_width, dsc->drm->pic_height);
+
+		/* we do the calculations for dsc parameters here so that
+		 * panel can use these parameters
+		 */
+		dsi_populate_dsc_params(dsc);
+
+		/* Divide the display by 3 but keep back/font porch and
+		 * pulse width same
+		 */
+		h_total -= hdisplay;
+		hdisplay /= 3;
+		h_total += hdisplay;
+		ha_end = ha_start + hdisplay;
+	}
+
 	if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		if (msm_host->dsc) {
+			struct msm_display_dsc_config *dsc = msm_host->dsc;
+			u32 reg, intf_width, slice_per_intf, width;
+			u32 total_bytes_per_intf;
+
+			/* first calculate dsc parameters and then program
+			 * compress mode registers
+			 */
+			intf_width = hdisplay;
+			slice_per_intf = DIV_ROUND_UP(intf_width, dsc->drm->slice_width);
+
+			/* If slice_count > slice_per_intf, then use 1
+			 * This can happen during partial update
+			 */
+				dsc->drm->slice_count = 1;
+
+			dsc->bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width * 8, 8);
+			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
+
+			dsc->eol_byte_num = total_bytes_per_intf % 3;
+			dsc->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
+			dsc->bytes_per_pkt = dsc->bytes_in_slice * dsc->drm->slice_count;
+			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
+
+			width = dsc->pclk_per_line;
+			reg = dsc->bytes_per_pkt << 16;
+			reg |= (0x0b << 8);    /* dtype of compressed image */
+
+			/* pkt_per_line:
+			 * 0 == 1 pkt
+			 * 1 == 2 pkt
+			 * 2 == 4 pkt
+			 * 3 pkt is not supported
+			 * above translates to ffs() - 1
+			 */
+			reg |= (ffs(dsc->pkt_per_line) - 1) << 6;
+
+			dsc->eol_byte_num = total_bytes_per_intf % 3;
+			reg |= dsc->eol_byte_num << 4;
+			reg |= 1;
+
+			dsi_write(msm_host,
+				  REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, reg);
+		}
+
 		dsi_write(msm_host, REG_DSI_ACTIVE_H,
 			DSI_ACTIVE_H_START(ha_start) |
 			DSI_ACTIVE_H_END(ha_end));
@@ -993,19 +1080,50 @@  static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi)
 			DSI_ACTIVE_VSYNC_VPOS_START(vs_start) |
 			DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
 	} else {		/* command mode */
+		if (msm_host->dsc) {
+			struct msm_display_dsc_config *dsc = msm_host->dsc;
+			u32 reg, reg_ctrl, reg_ctrl2;
+			u32 slice_per_intf, bytes_in_slice, total_bytes_per_intf;
+
+			reg_ctrl = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL);
+			reg_ctrl2 = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2);
+
+			slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->drm->slice_width);
+			bytes_in_slice = DIV_ROUND_UP(dsc->drm->slice_width *
+						      dsc->drm->bits_per_pixel, 8);
+			dsc->drm->slice_chunk_size = bytes_in_slice;
+			total_bytes_per_intf = dsc->bytes_in_slice * slice_per_intf;
+			dsc->pkt_per_line = slice_per_intf / dsc->drm->slice_count;
+
+			reg = 0x39 << 8;
+			reg |= ffs(dsc->pkt_per_line) << 6;
+
+			dsc->eol_byte_num = total_bytes_per_intf % 3;
+			reg |= dsc->eol_byte_num << 4;
+			reg |= 1;
+
+			reg_ctrl |= reg;
+			reg_ctrl2 |= bytes_in_slice;
+
+			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, reg);
+			dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+		}
+
 		/* image data and 1 byte write_memory_start cmd */
-		wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
+		if (!msm_host->dsc)
+			wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
+		else
+			wc = mode->hdisplay / 2 + 1;
 
-		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,
-			DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
-			DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(
-					msm_host->channel) |
-			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(
-					MIPI_DSI_DCS_LONG_WRITE));
+		data = DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
+		       DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL(msm_host->channel) |
+			DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE(MIPI_DSI_DCS_LONG_WRITE);
 
-		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL,
-			DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |
-			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay));
+		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, data);
+
+		data = DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(hdisplay) |
+			DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(mode->vdisplay);
+		dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL, data);
 	}
 }
 
@@ -2074,6 +2192,7 @@  int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
 	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
 	struct platform_device *pdev = msm_host->pdev;
+	struct msm_drm_private *priv;
 	int ret;
 
 	msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
@@ -2093,6 +2212,9 @@  int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
 	}
 
 	msm_host->dev = dev;
+	priv = dev->dev_private;
+	priv->dsc = msm_host->dsc;
+
 	ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
 	if (ret) {
 		pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);