[PATCH] backlight: pwm_bl: Avoid open coded arithmetic in memory allocation

2022-02-04 Thread Christophe JAILLET
kmalloc_array()/kcalloc() should be used to avoid potential overflow when
a multiplication is needed to compute the size of the requested memory.

So turn a kzalloc()+explicit size computation into an equivalent kcalloc().

Signed-off-by: Christophe JAILLET 
---
 drivers/video/backlight/pwm_bl.c | 9 -
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 8d8959a70e44..c0523a0269ee 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -263,9 +263,8 @@ static int pwm_backlight_parse_dt(struct device *dev,
 
/* read brightness levels from DT property */
if (num_levels > 0) {
-   size_t size = sizeof(*data->levels) * num_levels;
-
-   data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
+   data->levels = devm_kcalloc(dev, num_levels,
+   sizeof(*data->levels), GFP_KERNEL);
if (!data->levels)
return -ENOMEM;
 
@@ -320,8 +319,8 @@ static int pwm_backlight_parse_dt(struct device *dev,
 * Create a new table of brightness levels with all the
 * interpolated steps.
 */
-   size = sizeof(*table) * num_levels;
-   table = devm_kzalloc(dev, size, GFP_KERNEL);
+   table = devm_kcalloc(dev, num_levels, sizeof(*table),
+GFP_KERNEL);
if (!table)
return -ENOMEM;
/*
-- 
2.32.0



Re: [PATCH] iommu/vt-d: Remove comment reference to iommu_dev_has_feature

2022-02-04 Thread Lu Baolu

On 2/2/22 10:37 AM, Akeem G Abodunrin wrote:

iommu_dev_has_feature() api has been removed by the commit 262948f8ba573
("iommu: Delete iommu_dev_has_feature()") - So this patch removes comment
about the api to avoid any confusion.

Signed-off-by: Akeem G Abodunrin 
Cc: Lu Baolu 


It's not a change for iommu/vt-d, but for iommu core.

Please add Joerg in the to list.

Best regards,
baolu


---
  include/linux/iommu.h | 3 +--
  1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index de0c57a567c8..bea054f2bd4d 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -153,8 +153,7 @@ struct iommu_resv_region {
   * supported, this feature must be enabled before and
   * disabled after %IOMMU_DEV_FEAT_SVA.
   *
- * Device drivers query whether a feature is supported using
- * iommu_dev_has_feature(), and enable it using iommu_dev_enable_feature().
+ * Device drivers enable the feature via iommu_dev_enable_feature().
   */
  enum iommu_dev_features {
IOMMU_DEV_FEAT_AUX,


Re: [BUG] gpu: drm: radeon: two possible deadlocks involving locking and waiting

2022-02-04 Thread Jia-Ju Bai

Hi Christian,

Thanks for the reply :)

On 2022/2/1 15:56, Christian König wrote:

Hi Jia-Ju,

interesting that you have found those issues with an automated tool.

And yes that is a well design flaw within the radeon driver which can 
happen on hardware faults, e.g. when radeon_ring_backup() needs to be 
called.


In fact, my tool finds dozens of similar possible deadlocks caused by 
wait_event_timeout() in radeon_fence_wait_seq_timeout().

There are three other examples in Linux 5.16:

#BUG 1
radeon_dpm_change_power_state_locked()
  mutex_lock(&rdev->ring_lock); --> Line 1133 (Lock A)
  radeon_fence_wait_empty()
    radeon_fence_wait_seq_timeout()
      wait_event_timeout(rdev->fence_queue, ...) --> Line 504 (Wait X)

radeon_fence_driver_fini()
  mutex_lock(&rdev->ring_lock); --> Line 917 (Lock A)
  wake_up_all(&rdev->fence_queue); --> Line 927 (Wake X)

#BUG 2
radeon_set_pm_profile()
  mutex_lock(&rdev->pm.mutex); --> Line 382 (Lock A)
  radeon_pm_set_clocks()
    radeon_fence_wait_empty()
  radeon_fence_wait_seq_timeout()
        wait_event_timeout(rdev->fence_queue, ...) --> Line 504 (Wait X)

radeon_dynpm_idle_work_handler()
  mutex_lock(&rdev->pm.mutex); --> Line 1861 (Lock A)
  radeon_fence_count_emitted()
    radeon_fence_process()
  wake_up_all(&rdev->fence_queue); --> Line 323 (Wake X)

#BUG 3
radeon_pm_fini_old()
  mutex_lock(&rdev->pm.mutex); --> Line 1642 (Lock A)
  radeon_pm_set_clocks()
    radeon_fence_wait_empty()
  radeon_fence_wait_seq_timeout()
        wait_event_timeout(rdev->fence_queue, ...) --> Line 504 (Wait X)

radeon_dynpm_idle_work_handler()
  mutex_lock(&rdev->pm.mutex); --> Line 1861 (Lock A)
  radeon_fence_count_emitted()
    radeon_fence_process()
  wake_up_all(&rdev->fence_queue); --> Line 323 (Wake X)

Thus, to fix these possible deadlocks, we could moditify the code 
related to radeon_fence_wait_seq_timeout().
But I am not quite familar with the radeon driver, so I am not sure how 
to moditify the code properly.




But that happens so rarely and the driver is not developed further 
that we decided to not address this any more.


Ah, okay.



Regards,
Christian.

Am 01.02.22 um 08:40 schrieb Jia-Ju Bai:

Hello,

My static analysis tool reports a possible deadlock in the radeon 
driver in Linux 5.16:


#BUG 1
radeon_dpm_change_power_state_locked()
  mutex_lock(&rdev->ring_lock); --> Line 1133 (Lock A)
  radeon_fence_wait_empty()
    radeon_fence_wait_seq_timeout()
      wait_event_timeout(rdev->fence_queue, ...) --> Line 504 (Wait X)

radeon_ring_backup()
  mutex_lock(&rdev->ring_lock); --> Line 289(Lock A)
  radeon_fence_count_emitted()
    radeon_fence_process()
  wake_up_all(&rdev->fence_queue); --> Line 323 (Wake X)

When radeon_dpm_change_power_state_locked() is executed, "Wait X" is 
performed by holding "Lock A". If radeon_ring_backup() is executed at 
this time, "Wake X" cannot be performed to wake up "Wait X" in 
radeon_dpm_change_power_state_locked(), because "Lock A" has been 
already hold by radeon_dpm_change_power_state_locked(), causing a 
possible deadlock.
I find that "Wait X" is performed with a timeout 
MAX_SCHEDULE_TIMEOUT, to relieve the possible deadlock; but I think 
this timeout can cause inefficient execution.


#BUG 2
radeon_ring_lock()
  mutex_lock(&rdev->ring_lock); --> Line 147 (Lock A)
  radeon_ring_alloc()
    radeon_fence_wait_next()
  radeon_fence_wait_seq_timeout()
        wait_event_timeout(rdev->fence_queue, ...) --> Line 504 (Wait X)

radeon_ring_backup()
  mutex_lock(&rdev->ring_lock); --> Line 289(Lock A)
  radeon_fence_count_emitted()
    radeon_fence_process()
  wake_up_all(&rdev->fence_queue); --> Line 323 (Wake X)

When radeon_ring_lock() is executed, "Wait X" is performed by holding 
"Lock A". If radeon_ring_backup() is executed at this time, "Wake X" 
cannot be performed to wake up "Wait X" in radeon_ring_lock(), 
because "Lock A" has been already hold by radeon_ring_lock(), causing 
a possible deadlock.
I find that "Wait X" is performed with a timeout 
MAX_SCHEDULE_TIMEOUT, to relieve the possible deadlock; but I think 
this timeout can cause inefficient execution.


I am not quite sure whether these possible problems are real and how 
to fix them if they are real.

Any feedback would be appreciated, thanks :)


Best wishes,
Jia-Ju Bai







Re: [PATCH] drm/dp: Remove common Post Cursor2 register handling

2022-02-04 Thread Kees Cook
Ping,

This is a OOB read fix. Can someone please pick this up?

-Kees

On Wed, Jan 05, 2022 at 09:35:07AM -0800, Kees Cook wrote:
> The link_status array was not large enough to read the Adjust Request
> Post Cursor2 register, so remove the common helper function to avoid
> an OOB read, found with a -Warray-bounds build:
> 
> drivers/gpu/drm/drm_dp_helper.c: In function 
> 'drm_dp_get_adjust_request_post_cursor':
> drivers/gpu/drm/drm_dp_helper.c:59:27: error: array subscript 10 is outside 
> array bounds of 'const u8[6]' {aka 'const unsigned char[6]'} 
> [-Werror=array-bounds]
>59 | return link_status[r - DP_LANE0_1_STATUS];
>   |~~~^~~
> drivers/gpu/drm/drm_dp_helper.c:147:51: note: while referencing 'link_status'
>   147 | u8 drm_dp_get_adjust_request_post_cursor(const u8 
> link_status[DP_LINK_STATUS_SIZE],
>   |  
> ~^~~~
> 
> Replace the only user of the helper with an open-coded fetch and decode,
> similar to drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c.
> 
> Fixes: 79465e0ffeb9 ("drm/dp: Add helper to get post-cursor adjustments")
> Cc: Maarten Lankhorst 
> Cc: Maxime Ripard 
> Cc: Thomas Zimmermann 
> Cc: David Airlie 
> Cc: Daniel Vetter 
> Cc: dri-devel@lists.freedesktop.org
> Signed-off-by: Kees Cook 
> ---
> This is the alternative to:
> https://lore.kernel.org/lkml/20211203084354.3105253-1-keesc...@chromium.org/
> ---
>  drivers/gpu/drm/drm_dp_helper.c | 10 --
>  drivers/gpu/drm/tegra/dp.c  | 11 ++-
>  include/drm/drm_dp_helper.h |  2 --
>  3 files changed, 10 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
> index 23f9073bc473..c9528aa62c9c 100644
> --- a/drivers/gpu/drm/drm_dp_helper.c
> +++ b/drivers/gpu/drm/drm_dp_helper.c
> @@ -144,16 +144,6 @@ u8 drm_dp_get_adjust_tx_ffe_preset(const u8 
> link_status[DP_LINK_STATUS_SIZE],
>  }
>  EXPORT_SYMBOL(drm_dp_get_adjust_tx_ffe_preset);
>  
> -u8 drm_dp_get_adjust_request_post_cursor(const u8 
> link_status[DP_LINK_STATUS_SIZE],
> -  unsigned int lane)
> -{
> - unsigned int offset = DP_ADJUST_REQUEST_POST_CURSOR2;
> - u8 value = dp_link_status(link_status, offset);
> -
> - return (value >> (lane << 1)) & 0x3;
> -}
> -EXPORT_SYMBOL(drm_dp_get_adjust_request_post_cursor);
> -
>  static int __8b10b_clock_recovery_delay_us(const struct drm_dp_aux *aux, u8 
> rd_interval)
>  {
>   if (rd_interval > 4)
> diff --git a/drivers/gpu/drm/tegra/dp.c b/drivers/gpu/drm/tegra/dp.c
> index 70dfb7d1dec5..f5535eb04c6b 100644
> --- a/drivers/gpu/drm/tegra/dp.c
> +++ b/drivers/gpu/drm/tegra/dp.c
> @@ -549,6 +549,15 @@ static void drm_dp_link_get_adjustments(struct 
> drm_dp_link *link,
>  {
>   struct drm_dp_link_train_set *adjust = &link->train.adjust;
>   unsigned int i;
> + u8 post_cursor;
> + int err;
> +
> + err = drm_dp_dpcd_read(link->aux, DP_ADJUST_REQUEST_POST_CURSOR2,
> +&post_cursor, sizeof(post_cursor));
> + if (err < 0) {
> + DRM_ERROR("failed to read post_cursor2: %d\n", err);
> + post_cursor = 0;
> + }
>  
>   for (i = 0; i < link->lanes; i++) {
>   adjust->voltage_swing[i] =
> @@ -560,7 +569,7 @@ static void drm_dp_link_get_adjustments(struct 
> drm_dp_link *link,
>   DP_TRAIN_PRE_EMPHASIS_SHIFT;
>  
>   adjust->post_cursor[i] =
> - drm_dp_get_adjust_request_post_cursor(status, i);
> + (post_cursor >> (i << 1)) & 0x3;
>   }
>  }
>  
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index 472dac376284..fdf3cf6ccc02 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -1528,8 +1528,6 @@ u8 drm_dp_get_adjust_request_pre_emphasis(const u8 
> link_status[DP_LINK_STATUS_SI
> int lane);
>  u8 drm_dp_get_adjust_tx_ffe_preset(const u8 link_status[DP_LINK_STATUS_SIZE],
>  int lane);
> -u8 drm_dp_get_adjust_request_post_cursor(const u8 
> link_status[DP_LINK_STATUS_SIZE],
> -  unsigned int lane);
>  
>  #define DP_BRANCH_OUI_HEADER_SIZE0xc
>  #define DP_RECEIVER_CAP_SIZE 0xf
> -- 
> 2.30.2
> 

-- 
Kees Cook


Re: [PATCH v2] drm/dp: Fix off-by-one in register cache size

2022-02-04 Thread Kees Cook
Ping. This is a OOB read fix. Can something send this to Linus please?

-Kees

On Wed, Jan 05, 2022 at 09:33:10AM -0800, Kees Cook wrote:
> The pcon_dsc_dpcd array holds 13 registers (0x92 through 0x9E). Fix the
> math to calculate the max size. Found from a -Warray-bounds build:
> 
> drivers/gpu/drm/drm_dp_helper.c: In function 'drm_dp_pcon_dsc_bpp_incr':
> drivers/gpu/drm/drm_dp_helper.c:3130:28: error: array subscript 12 is outside 
> array bounds of 'const u8[12]' {aka 'const unsigned char[12]'} 
> [-Werror=array-bounds]
>  3130 | buf = pcon_dsc_dpcd[DP_PCON_DSC_BPP_INCR - 
> DP_PCON_DSC_ENCODER];
>   |   
> ~^~~~
> drivers/gpu/drm/drm_dp_helper.c:3126:39: note: while referencing 
> 'pcon_dsc_dpcd'
>  3126 | int drm_dp_pcon_dsc_bpp_incr(const u8 
> pcon_dsc_dpcd[DP_PCON_DSC_ENCODER_CAP_SIZE])
>   |  
> ~^~~
> 
> Cc: Maarten Lankhorst 
> Cc: Maxime Ripard 
> Cc: Thomas Zimmermann 
> Cc: David Airlie 
> Cc: Daniel Vetter 
> Cc: dri-devel@lists.freedesktop.org
> Fixes: e2e16da398d9 ("drm/dp_helper: Add support for Configuring DSC for 
> HDMI2.1 Pcon")
> Cc: sta...@vger.kernel.org
> Reviewed-by: Gustavo A. R. Silva 
> Link: https://lore.kernel.org/lkml/20211214001849.GA62559@embeddedor/
> Signed-off-by: Kees Cook 
> ---
> v1: 
> https://lore.kernel.org/lkml/20211203084333.3105038-1-keesc...@chromium.org/
> v2:
>  - add reviewed-by
>  - add cc:stable
> ---
>  include/drm/drm_dp_helper.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index 30359e434c3f..472dac376284 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -456,7 +456,7 @@ struct drm_panel;
>  #define DP_FEC_CAPABILITY_1  0x091   /* 2.0 */
>  
>  /* DP-HDMI2.1 PCON DSC ENCODER SUPPORT */
> -#define DP_PCON_DSC_ENCODER_CAP_SIZE0xC  /* 0x9E - 0x92 */
> +#define DP_PCON_DSC_ENCODER_CAP_SIZE0xD  /* 0x92 through 0x9E */
>  #define DP_PCON_DSC_ENCODER 0x092
>  # define DP_PCON_DSC_ENCODER_SUPPORTED  (1 << 0)
>  # define DP_PCON_DSC_PPS_ENC_OVERRIDE   (1 << 1)
> -- 
> 2.30.2
> 

-- 
Kees Cook


Re: [PATCH v6 3/4] drm/bridge: anx7625: Support reading edid through aux channel

2022-02-04 Thread kernel test robot
Hi Hsin-Yi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[cannot apply to robh/for-next drm-intel/for-linux-next v5.17-rc2]
[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/Hsin-Yi-Wang/drm-bridge-anx7625-send-DPCD-command-to-downstream/20220203-221108
base:   git://anongit.freedesktop.org/drm/drm drm-next
config: arm64-randconfig-c023-20220130 
(https://download.01.org/0day-ci/archive/20220205/202202050942.c6c0md0r-...@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 11.2.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/45f3728b61c8cb8d53d13d88c33c4f58630dcea6
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review 
Hsin-Yi-Wang/drm-bridge-anx7625-send-DPCD-command-to-downstream/20220203-221108
git checkout 45f3728b61c8cb8d53d13d88c33c4f58630dcea6
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross 
O=build_dir ARCH=arm64 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot 

All errors (new ones prefixed by >>):

   aarch64-linux-ld: Unexpected GOT/PLT entries detected!
   aarch64-linux-ld: Unexpected run-time procedure linkages detected!
   aarch64-linux-ld: ID map text too big or misaligned
   aarch64-linux-ld: drivers/gpu/drm/bridge/analogix/anx7625.o: in function 
`anx7625_bridge_detach':
>> anx7625.c:(.text+0x5e0): undefined reference to `drm_dp_aux_unregister'
   aarch64-linux-ld: drivers/gpu/drm/bridge/analogix/anx7625.o: in function 
`anx7625_bridge_attach':
>> anx7625.c:(.text+0x674): undefined reference to `drm_dp_aux_register'
   aarch64-linux-ld: drivers/gpu/drm/bridge/analogix/anx7625.o: in function 
`anx7625_i2c_probe':
>> anx7625.c:(.text+0x1b48): undefined reference to `drm_dp_aux_init'

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org


Re: [PATCH v4 2/2] drm/msm/dp: rewrite dss_module_power to use bulk clock functions

2022-02-04 Thread Jessica Zhang




On 1/31/2022 1:05 PM, Dmitry Baryshkov wrote:

In order to simplify DP code, drop hand-coded loops over clock arrays,
replacing them with clk_bulk_* functions.

Signed-off-by: Dmitry Baryshkov 


Tested-by: Jessica Zhang  # RB3 (sdm845) and 
RB5  (qrb5165)


Reviewed-by: Jessica Zhang 


---
  drivers/gpu/drm/msm/Makefile |   1 -
  drivers/gpu/drm/msm/dp/dp_clk_util.c | 120 ---
  drivers/gpu/drm/msm/dp/dp_clk_util.h |  38 -
  drivers/gpu/drm/msm/dp/dp_ctrl.c |  19 ++---
  drivers/gpu/drm/msm/dp/dp_parser.c   |  21 -
  drivers/gpu/drm/msm/dp/dp_parser.h   |  17 +++-
  drivers/gpu/drm/msm/dp/dp_power.c|  91 
  7 files changed, 100 insertions(+), 207 deletions(-)
  delete mode 100644 drivers/gpu/drm/msm/dp/dp_clk_util.c
  delete mode 100644 drivers/gpu/drm/msm/dp/dp_clk_util.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index a44abf0a7660..ecf01f9989ed 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -101,7 +101,6 @@ msm-$(CONFIG_DRM_MSM_GPU_STATE) += 
adreno/a6xx_gpu_state.o
  
  msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \

dp/dp_catalog.o \
-   dp/dp_clk_util.o \
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_clk_util.c 
b/drivers/gpu/drm/msm/dp/dp_clk_util.c
deleted file mode 100644
index 44a4fc59ff31..
--- a/drivers/gpu/drm/msm/dp/dp_clk_util.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
- * All rights reserved.
- */
-
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-#include "dp_clk_util.h"
-
-void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
-{
-   int i;
-
-   for (i = num_clk - 1; i >= 0; i--) {
-   if (clk_arry[i].clk)
-   clk_put(clk_arry[i].clk);
-   clk_arry[i].clk = NULL;
-   }
-}
-
-int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
-{
-   int i, rc = 0;
-
-   for (i = 0; i < num_clk; i++) {
-   clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
-   rc = PTR_ERR_OR_ZERO(clk_arry[i].clk);
-   if (rc) {
-   DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
-   __builtin_return_address(0), __func__,
-   clk_arry[i].clk_name, rc);
-   goto error;
-   }
-   }
-
-   return rc;
-
-error:
-   for (i--; i >= 0; i--) {
-   if (clk_arry[i].clk)
-   clk_put(clk_arry[i].clk);
-   clk_arry[i].clk = NULL;
-   }
-
-   return rc;
-}
-
-int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
-{
-   int i, rc = 0;
-
-   for (i = 0; i < num_clk; i++) {
-   if (clk_arry[i].clk) {
-   if (clk_arry[i].type != DSS_CLK_AHB) {
-   DEV_DBG("%pS->%s: '%s' rate %ld\n",
-   __builtin_return_address(0), __func__,
-   clk_arry[i].clk_name,
-   clk_arry[i].rate);
-   rc = clk_set_rate(clk_arry[i].clk,
-   clk_arry[i].rate);
-   if (rc) {
-   DEV_ERR("%pS->%s: %s failed. rc=%d\n",
-   __builtin_return_address(0),
-   __func__,
-   clk_arry[i].clk_name, rc);
-   break;
-   }
-   }
-   } else {
-   DEV_ERR("%pS->%s: '%s' is not available\n",
-   __builtin_return_address(0), __func__,
-   clk_arry[i].clk_name);
-   rc = -EPERM;
-   break;
-   }
-   }
-
-   return rc;
-}
-
-int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
-{
-   int i, rc = 0;
-
-   if (enable) {
-   for (i = 0; i < num_clk; i++) {
-   DEV_DBG("%pS->%s: enable '%s'\n",
-   __builtin_return_address(0), __func__,
-   clk_arry[i].clk_name);
-   rc = clk_prepare_enable(clk_arry[i].clk);
-   if (rc)
-   DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
-   __builtin_return_address(0),
-   __func__,
-   clk_arry[i].clk_name, rc);
-
-   if (rc && i) {
-  

Re: [Freedreno] [PATCH v4 1/2] drm/msm/dpu: simplify clocks handling

2022-02-04 Thread Jessica Zhang




On 1/31/2022 1:05 PM, Dmitry Baryshkov wrote:

DPU driver contains code to parse clock items from device tree into
special data struct and then enable/disable/set rate for the clocks
using that data struct. However the DPU driver itself uses only parsing
and enabling/disabling part (the rate setting is used by DP driver).

Move this implementation to the DP driver (which actually uses rate
setting) and replace hand-coded enable/disable/get loops in the DPU
with the respective clk_bulk operations. Put operation is removed
completely because, it is handled using devres instead.

DP implementation is unchanged for now.

Signed-off-by: Dmitry Baryshkov 


Tested-by: Jessica Zhang  # RB3 (sdm845) and 
RB5  (qrb5165)


Reviewed-by: Jessica Zhang 


---
  drivers/gpu/drm/msm/Makefile  |  2 +-
  drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 24 ++-
  drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h |  6 +-
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   | 46 +++--
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h   |  4 +-
  drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c  | 26 +++
  .../dpu1/dpu_io_util.c => dp/dp_clk_util.c}   | 69 +--
  .../dpu1/dpu_io_util.h => dp/dp_clk_util.h}   |  8 +--
  drivers/gpu/drm/msm/dp/dp_parser.h|  2 +-
  9 files changed, 37 insertions(+), 150 deletions(-)
  rename drivers/gpu/drm/msm/{disp/dpu1/dpu_io_util.c => dp/dp_clk_util.c} (61%)
  rename drivers/gpu/drm/msm/{disp/dpu1/dpu_io_util.h => dp/dp_clk_util.h} (85%)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 03ab55c37beb..a44abf0a7660 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -66,7 +66,6 @@ msm-y := \
disp/dpu1/dpu_hw_top.o \
disp/dpu1/dpu_hw_util.o \
disp/dpu1/dpu_hw_vbif.o \
-   disp/dpu1/dpu_io_util.o \
disp/dpu1/dpu_kms.o \
disp/dpu1/dpu_mdss.o \
disp/dpu1/dpu_plane.o \
@@ -102,6 +101,7 @@ msm-$(CONFIG_DRM_MSM_GPU_STATE) += 
adreno/a6xx_gpu_state.o
  
  msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \

dp/dp_catalog.o \
+   dp/dp_clk_util.o \
dp/dp_ctrl.o \
dp/dp_display.o \
dp/dp_drm.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
index 60fe06018581..4d184122d63e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
@@ -284,17 +284,6 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
}
  }
  
-static int _dpu_core_perf_set_core_clk_rate(struct dpu_kms *kms, u64 rate)

-{
-   struct dss_clk *core_clk = kms->perf.core_clk;
-
-   if (core_clk->max_rate && (rate > core_clk->max_rate))
-   rate = core_clk->max_rate;
-
-   core_clk->rate = rate;
-   return dev_pm_opp_set_rate(&kms->pdev->dev, core_clk->rate);
-}
-
  static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms)
  {
u64 clk_rate = kms->perf.perf_tune.min_core_clk;
@@ -306,7 +295,7 @@ static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms 
*kms)
dpu_cstate = to_dpu_crtc_state(crtc->state);
clk_rate = max(dpu_cstate->new_perf.core_clk_rate,
clk_rate);
-   clk_rate = clk_round_rate(kms->perf.core_clk->clk,
+   clk_rate = clk_round_rate(kms->perf.core_clk,
clk_rate);
}
}
@@ -405,10 +394,11 @@ int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
  
  		trace_dpu_core_perf_update_clk(kms->dev, stop_req, clk_rate);
  
-		ret = _dpu_core_perf_set_core_clk_rate(kms, clk_rate);

+   if (clk_rate > kms->perf.max_core_clk_rate)
+   clk_rate = kms->perf.max_core_clk_rate;
+   ret = dev_pm_opp_set_rate(&kms->pdev->dev, clk_rate);
if (ret) {
-   DPU_ERROR("failed to set %s clock rate %llu\n",
-   kms->perf.core_clk->clk_name, clk_rate);
+   DPU_ERROR("failed to set core clock rate %llu\n", 
clk_rate);
return ret;
}
  
@@ -529,13 +519,13 @@ void dpu_core_perf_destroy(struct dpu_core_perf *perf)

  int dpu_core_perf_init(struct dpu_core_perf *perf,
struct drm_device *dev,
struct dpu_mdss_cfg *catalog,
-   struct dss_clk *core_clk)
+   struct clk *core_clk)
  {
perf->dev = dev;
perf->catalog = catalog;
perf->core_clk = core_clk;
  
-	perf->max_core_clk_rate = core_clk->max_rate;

+   perf->max_core_clk_rate = clk_get_rate(core_clk);
if (!perf->max_core_clk_rate) {
DPU_DEBUG("optional max core clk rate, use default\n");
perf->max_core_clk_rate = DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE;
diff --git a/driver

[PATCH v2 3/3] drm/panel-edp: Allow querying the detected panel via debugfs

2022-02-04 Thread Douglas Anderson
Recently we added generic "edp-panel"s probed by EDID. To support
panels in this way we look at the panel ID in the EDID and look up the
panel in a table that has power sequence timings. If we find a panel
that's not in the table we will still attempt to use it but we'll use
conservative timings. While it's likely that these conservative
timings will work for most nearly all panels, the performance of
turning the panel off and on suffers.

We'd like to be able to reliably detect the case that we're using the
hardcoded timings without relying on parsing dmesg. This allows us to
implement tests that ensure that no devices get shipped that are
relying on the conservative timings.

Let's add a new debugfs entry to panel devices. It will have one of:
* UNKNOWN - We tried to detect a panel but it wasn't in our table.
* HARDCODED - We're not using generic "edp-panel" probed by EDID.
* A panel name - This is the name of the panel from our table.

Signed-off-by: Douglas Anderson 
---

Changes in v2:
- Now using debugfs, not sysfs

 drivers/gpu/drm/panel/panel-edp.c | 37 ++-
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index a394a15dc3fb..0fda1eb7b690 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -21,6 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -222,6 +223,8 @@ struct panel_edp {
struct gpio_desc *enable_gpio;
struct gpio_desc *hpd_gpio;
 
+   const struct edp_panel_entry *detected_panel;
+
struct edid *edid;
 
struct drm_display_mode override_mode;
@@ -606,6 +609,28 @@ static int panel_edp_get_timings(struct drm_panel *panel,
return p->desc->num_timings;
 }
 
+static int detected_panel_show(struct seq_file *s, void *data)
+{
+   struct drm_panel *panel = s->private;
+   struct panel_edp *p = to_panel_edp(panel);
+
+   if (IS_ERR(p->detected_panel))
+   seq_puts(s, "UNKNOWN\n");
+   else if (!p->detected_panel)
+   seq_puts(s, "HARDCODED\n");
+   else
+   seq_printf(s, "%s\n", p->detected_panel->name);
+
+   return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(detected_panel);
+
+static void panel_edp_debugfs_init(struct drm_panel *panel, struct dentry 
*root)
+{
+   debugfs_create_file("detected_panel", 0600, root, panel, 
&detected_panel_fops);
+}
+
 static const struct drm_panel_funcs panel_edp_funcs = {
.disable = panel_edp_disable,
.unprepare = panel_edp_unprepare,
@@ -613,6 +638,7 @@ static const struct drm_panel_funcs panel_edp_funcs = {
.enable = panel_edp_enable,
.get_modes = panel_edp_get_modes,
.get_timings = panel_edp_get_timings,
+   .debugfs_init = panel_edp_debugfs_init,
 };
 
 #define PANEL_EDP_BOUNDS_CHECK(to_check, bounds, field) \
@@ -666,7 +692,6 @@ static const struct edp_panel_entry *find_edp_panel(u32 
panel_id);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
-   const struct edp_panel_entry *edp_panel;
struct panel_desc *desc;
u32 panel_id;
char vend[4];
@@ -705,14 +730,14 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
}
drm_edid_decode_panel_id(panel_id, vend, &product_id);
 
-   edp_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id);
 
/*
 * We're using non-optimized timings and want it really obvious that
 * someone needs to add an entry to the table, so we'll do a WARN_ON
 * splat.
 */
-   if (WARN_ON(!edp_panel)) {
+   if (WARN_ON(!panel->detected_panel)) {
dev_warn(dev,
 "Unknown panel %s %#06x, using conservative timings\n",
 vend, product_id);
@@ -734,12 +759,14 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
 */
desc->delay.unprepare = 2000;
desc->delay.enable = 200;
+
+   panel->detected_panel = ERR_PTR(-EINVAL);
} else {
dev_info(dev, "Detected %s %s (%#06x)\n",
-vend, edp_panel->name, product_id);
+vend, panel->detected_panel->name, product_id);
 
/* Update the delay; everything else comes from EDID */
-   desc->delay = *edp_panel->delay;
+   desc->delay = *panel->detected_panel->delay;
}
 
ret = 0;
-- 
2.35.0.263.gb82422642f-goog



[PATCH v2 2/3] drm: Plumb debugfs_init through to panels

2022-02-04 Thread Douglas Anderson
We'd like panels to be able to add things to debugfs underneath the
connector's directory. Let's plumb it through. A panel will be able to
put things in a "panel" directory under the connector's
directory. Note that debugfs is not ABI and so it's always possible
that the location that the panel gets for its debugfs could change in
the future.

NOTE: this currently only works if you're using a modern
architecture. Specifically the plumbing relies on _both_
drm_bridge_connector and drm_panel_bridge. If you're not using one or
both of these things then things won't be plumbed through.

As a side effect of this change, drm_bridges can also get callbacks to
put stuff underneath the connector's debugfs directory. At the moment
all bridges in the chain have their debugfs_init() called with the
connector's root directory.

Signed-off-by: Douglas Anderson 
---

Changes in v2:
- ("drm: Plumb debugfs_init through to panels") new for v2.

 drivers/gpu/drm/bridge/panel.c | 12 
 drivers/gpu/drm/drm_bridge_connector.c | 15 +++
 drivers/gpu/drm/drm_debugfs.c  |  3 +++
 include/drm/drm_bridge.h   |  7 +++
 include/drm/drm_connector.h|  7 +++
 include/drm/drm_panel.h|  8 
 6 files changed, 52 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index b32295abd9e7..5be057575183 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -138,6 +138,17 @@ static int panel_bridge_get_modes(struct drm_bridge 
*bridge,
return drm_panel_get_modes(panel_bridge->panel, connector);
 }
 
+static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
+ struct dentry *root)
+{
+   struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_panel *panel = panel_bridge->panel;
+
+   root = debugfs_create_dir("panel", root);
+   if (panel->funcs->debugfs_init)
+   panel->funcs->debugfs_init(panel, root);
+}
+
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
@@ -150,6 +161,7 @@ static const struct drm_bridge_funcs 
panel_bridge_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
+   .debugfs_init = panel_bridge_debugfs_init,
 };
 
 /**
diff --git a/drivers/gpu/drm/drm_bridge_connector.c 
b/drivers/gpu/drm/drm_bridge_connector.c
index 791379816837..60923cdfe8e1 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -216,6 +216,20 @@ static void drm_bridge_connector_destroy(struct 
drm_connector *connector)
kfree(bridge_connector);
 }
 
+static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
+ struct dentry *root)
+{
+   struct drm_bridge_connector *bridge_connector =
+   to_drm_bridge_connector(connector);
+   struct drm_encoder *encoder = bridge_connector->encoder;
+   struct drm_bridge *bridge;
+
+   list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) {
+   if (bridge->funcs->debugfs_init)
+   bridge->funcs->debugfs_init(bridge, root);
+   }
+}
+
 static const struct drm_connector_funcs drm_bridge_connector_funcs = {
.reset = drm_atomic_helper_connector_reset,
.detect = drm_bridge_connector_detect,
@@ -223,6 +237,7 @@ static const struct drm_connector_funcs 
drm_bridge_connector_funcs = {
.destroy = drm_bridge_connector_destroy,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+   .debugfs_init = drm_bridge_connector_debugfs_init,
 };
 
 /* 
-
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index b0a826489488..7f1b82dbaebb 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -436,6 +436,9 @@ void drm_debugfs_connector_add(struct drm_connector 
*connector)
/* vrr range */
debugfs_create_file("vrr_range", S_IRUGO, root, connector,
&vrr_range_fops);
+
+   if (connector->funcs->debugfs_init)
+   connector->funcs->debugfs_init(connector, root);
 }
 
 void drm_debugfs_connector_remove(struct drm_connector *connector)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 061d87313fac..f27b4060faa2 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -649,6 +649,13 @@ struct drm_bridge_funcs {
 * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->o

[PATCH v2 1/3] drm/bridge: ti-sn65dsi86: Use drm_bridge_connector

2022-02-04 Thread Douglas Anderson
The ti-sn65dsi86 driver shouldn't hand-roll its own bridge
connector. It should use the normal drm_bridge_connector. Let's switch
to do that, removing all of the custom code.

NOTE: this still _doesn't_ implement DRM_BRIDGE_ATTACH_NO_CONNECTOR
support for ti-sn65dsi86 and that would still be a useful thing to do
in the future. It was attempted in the past [1] but put on the back
burner. However, unless we instantly change ti-sn65dsi86 fully from
not supporting DRM_BRIDGE_ATTACH_NO_CONNECTOR at all to _only_
supporting DRM_BRIDGE_ATTACH_NO_CONNECTOR then we'll still need a bit
of time when we support both. This is a better way to support the old
way where the driver hand rolls things itself.

A new notes about the implementation here:
* When using the drm_bridge_connector the connector should be created
  after all the bridges, so we change the ordering a bit.
* I'm reasonably certain that we don't need to do anything to "free"
  the new drm_bridge_connector. If drm_bridge_connector_init() returns
  success then we know drm_connector_init() was called with the
  `drm_bridge_connector_funcs`. The `drm_bridge_connector_funcs` has a
  .destroy() that does all the cleanup. drm_connector_init() calls
  __drm_mode_object_add() with a drm_connector_free() that will call
  the .destroy().
* I'm also reasonably certain that I don't need to "undo" the
  drm_bridge_attach() if drm_bridge_connector_init() fails. The
  "detach" function is private and other similar code doesn't try to
  undo the drm_bridge_attach() in error cases. There's also a comment
  indicating the lack of balance at the top of drm_bridge_attach().

[1] https://lore.kernel.org/r/20210920225801.227211-4-robdcl...@gmail.com

Signed-off-by: Douglas Anderson 
---

Changes in v2:
- ("ti-sn65dsi86: Use drm_bridge_connector") new for v2.

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 72 ++-
 1 file changed, 14 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c 
b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index ba136a188be7..38616aab12ac 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -174,7 +175,7 @@ struct ti_sn65dsi86 {
struct regmap   *regmap;
struct drm_dp_aux   aux;
struct drm_bridge   bridge;
-   struct drm_connectorconnector;
+   struct drm_connector*connector;
struct device_node  *host_node;
struct mipi_dsi_device  *dsi;
struct clk  *refclk;
@@ -646,54 +647,6 @@ static struct auxiliary_driver ti_sn_aux_driver = {
.id_table = ti_sn_aux_id_table,
 };
 
-/* 
-
- * DRM Connector Operations
- */
-
-static struct ti_sn65dsi86 *
-connector_to_ti_sn65dsi86(struct drm_connector *connector)
-{
-   return container_of(connector, struct ti_sn65dsi86, connector);
-}
-
-static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector)
-{
-   struct ti_sn65dsi86 *pdata = connector_to_ti_sn65dsi86(connector);
-
-   return drm_bridge_get_modes(pdata->next_bridge, connector);
-}
-
-static struct drm_connector_helper_funcs ti_sn_bridge_connector_helper_funcs = 
{
-   .get_modes = ti_sn_bridge_connector_get_modes,
-};
-
-static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = {
-   .fill_modes = drm_helper_probe_single_connector_modes,
-   .destroy = drm_connector_cleanup,
-   .reset = drm_atomic_helper_connector_reset,
-   .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static int ti_sn_bridge_connector_init(struct ti_sn65dsi86 *pdata)
-{
-   int ret;
-
-   ret = drm_connector_init(pdata->bridge.dev, &pdata->connector,
-&ti_sn_bridge_connector_funcs,
-DRM_MODE_CONNECTOR_eDP);
-   if (ret) {
-   DRM_ERROR("Failed to initialize connector with drm\n");
-   return ret;
-   }
-
-   drm_connector_helper_add(&pdata->connector,
-&ti_sn_bridge_connector_helper_funcs);
-   drm_connector_attach_encoder(&pdata->connector, pdata->bridge.encoder);
-
-   return 0;
-}
-
 
/*--
  * DRM Bridge
  */
@@ -757,10 +710,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge,
return ret;
}
 
-   ret = ti_sn_bridge_connector_init(pdata);
-   if (ret < 0)
-   goto err_conn_init;
-
/* We never want the next bridge to *also* create a connector: */
flags |= DRM_BRIDGE_ATTACH_NO_CONNECTOR;
 
@@ -768,13 +717,20 @@ static int

[PATCH v2 0/3] drm/panel-edp: Debugfs for panel-edp

2022-02-04 Thread Douglas Anderson
The main goal of this series is the final patch in the series: to
allow test code to reliably find out if we ended up hitting the
"fallback" case of the generic edp-panel driver where we don't
recognize a panel and choose to use super conservative timing.

Version 1 of the patch actually landed but was quickly reverted since
it was pointed out that it should have been done in debugfs, not
sysfs.

As discussed on IRC [1], we want this support to be under the
"connector" directory of debugfs but there was no existing way to do
that. Thus patch #2 in the series was born to try to plumb this
through. It was asserted that it would be OK to rely on a fairly
modern display pipeline for this plumbing and perhaps fail to populate
the debugfs file if we're using older/deprecated pipelines.

Patch #1 in the series was born because the bridge chip I was using
was still using an older/deprecated pipeline. While this doesn't get
us fully to a modern pipeline for ti-sn65dsi86 (it still doesn't move
to "NO_CONNECTOR") it hopefully moves us in the right direction.

This was tested on sc7180-trogdor devices with _both_ the ti-sn65dsi86
and the parade-ps8640 bridge chips (since some devices have one, some
the other). The parade-ps8640 already uses supports "NO_CONNECTOR",
luckily.

[1] 
https://people.freedesktop.org/~cbrill/dri-log/?channel=dri-devel&date=2022-02-02

Changes in v2:
- ("ti-sn65dsi86: Use drm_bridge_connector") new for v2.
- ("drm: Plumb debugfs_init through to panels") new for v2.
- Now using debugfs, not sysfs

Douglas Anderson (3):
  drm/bridge: ti-sn65dsi86: Use drm_bridge_connector
  drm: Plumb debugfs_init through to panels
  drm/panel-edp: Allow querying the detected panel via debugfs

 drivers/gpu/drm/bridge/panel.c | 12 +
 drivers/gpu/drm/bridge/ti-sn65dsi86.c  | 72 +-
 drivers/gpu/drm/drm_bridge_connector.c | 15 ++
 drivers/gpu/drm/drm_debugfs.c  |  3 ++
 drivers/gpu/drm/panel/panel-edp.c  | 37 +++--
 include/drm/drm_bridge.h   |  7 +++
 include/drm/drm_connector.h|  7 +++
 include/drm/drm_panel.h|  8 +++
 8 files changed, 98 insertions(+), 63 deletions(-)

-- 
2.35.0.263.gb82422642f-goog



Re: [PATCH 05/12] drm/msm/dpu: add an API to reset the encoder related hw blocks

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add an API to reset the encoder related hw blocks to ensure
a proper teardown of the pipeline. At the moment this is being
used only for the writeback encoder but eventually we can start
using this for all interfaces.

Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c  | 92 
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 10 +++
  2 files changed, 102 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1e648db..e977c05 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
   * Copyright (C) 2013 Red Hat
   * Author: Rob Clark 
@@ -21,6 +22,7 @@
  #include "dpu_hw_intf.h"
  #include "dpu_hw_ctl.h"
  #include "dpu_hw_dspp.h"
+#include "dpu_hw_merge3d.h"
  #include "dpu_formats.h"
  #include "dpu_encoder_phys.h"
  #include "dpu_crtc.h"
@@ -1813,6 +1815,96 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
DPU_ATRACE_END("encoder_kickoff");
  }
  
+static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc)

+{
+   struct dpu_hw_mixer_cfg mixer;
+   int i, num_lm;
+   u32 flush_mask = 0;
+   struct dpu_global_state *global_state;
+   struct dpu_hw_blk *hw_lm[2];
+   struct dpu_hw_mixer *hw_mixer[2];
+   struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+
+   memset(&mixer, 0, sizeof(mixer));
+
+   /* reset all mixers for this encoder */
+   if (phys_enc->hw_ctl->ops.clear_all_blendstages)
+   phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl);
+
+   global_state = dpu_kms_get_existing_global_state(phys_enc->dpu_kms);
+
+   num_lm = dpu_rm_get_assigned_resources(&phys_enc->dpu_kms->rm, 
global_state,
+   phys_enc->parent->base.id, DPU_HW_BLK_LM, hw_lm, 
ARRAY_SIZE(hw_lm));
+
+   for (i = 0; i < num_lm; i++) {
+   hw_mixer[i] = to_dpu_hw_mixer(hw_lm[i]);
+   flush_mask = phys_enc->hw_ctl->ops.get_bitmask_mixer(ctl, 
hw_mixer[i]->idx);
+   if (phys_enc->hw_ctl->ops.update_pending_flush)
+   phys_enc->hw_ctl->ops.update_pending_flush(ctl, 
flush_mask);
+
+   /* clear all blendstages */
+   if (phys_enc->hw_ctl->ops.setup_blendstage)
+   phys_enc->hw_ctl->ops.setup_blendstage(ctl, 
hw_mixer[i]->idx, NULL);
+   }
+}
+
+void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
+{
+   struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+   struct dpu_hw_intf_cfg intf_cfg = { 0 };
+   int i;
+   struct dpu_encoder_virt *dpu_enc;
+
+   dpu_enc = to_dpu_encoder_virt(phys_enc->parent);
+
+   phys_enc->hw_ctl->ops.reset(ctl);
+
+   dpu_encoder_helper_reset_mixers(phys_enc);
+
+   if (phys_enc->hw_wb) {
+   /* disable the PP block */
+   if (phys_enc->hw_wb->ops.bind_pingpong_blk)
+   phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, 
false,
+   phys_enc->hw_pp->idx);
+
+   /* mark WB flush as pending */
+   if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
+   phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, 
phys_enc->hw_wb->idx);
+   } else {
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   if (dpu_enc->phys_encs[i] && 
phys_enc->hw_intf->ops.bind_pingpong_blk)
+   phys_enc->hw_intf->ops.bind_pingpong_blk(
+   dpu_enc->phys_encs[i]->hw_intf, 
false,
+   
dpu_enc->phys_encs[i]->hw_pp->idx);
+   /* mark INTF flush as pending */
+   if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
+   
phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
+   
dpu_enc->phys_encs[i]->hw_intf->idx);
+   }
+   }
+
+   /* reset the merge 3D HW block */
+   if (phys_enc->hw_pp->merge_3d) {
+   
phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
+   BLEND_3D_NONE);
+   if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d)
+   phys_enc->hw_ctl->ops.update_pending_flush_merge_3d(ctl,
+   phys_enc->hw_pp->merge_3d->idx);
+   }
+
+   intf_cfg.stream_sel = 0; /* Don't care value for video mode */
+   intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+   if 

Re: [PATCH 03/12] drm/msm/dpu: add writeback blocks to DPU RM

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add writeback blocks to DPU resource manager so that
writeback encoders can request for writeback hardware blocks
through RM and their usage can be tracked.

Signed-off-by: Abhinav Kumar 


[please excuse me for the duplicate, I've sent the email without the 
proper distribution list]


We have WB blocks being allocated manually. Could you please consider 
following the ideas from 
https://patchwork.freedesktop.org/patch/470394/?series=99175&rev=1 ?


I think it simplifies the code and shows exact correspondence between WB 
and dpu_encoder.



---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  3 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h |  2 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c  | 71 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h  |  2 +
  4 files changed, 78 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index e241914..cc10436 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -1,5 +1,6 @@
  /* SPDX-License-Identifier: GPL-2.0-only */
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   * Copyright (C) 2013 Red Hat
   * Author: Rob Clark 
@@ -21,9 +22,11 @@
  /**
   * Encoder functions and data types
   * @intfs:Interfaces this encoder is using, INTF_MODE_NONE if unused
+ * @wbs:Writeback blocks this encoder is using
   */
  struct dpu_encoder_hw_resources {
enum dpu_intf_mode intfs[INTF_MAX];
+   enum dpu_intf_mode wbs[WB_MAX];
  };
  
  /**

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index 2d385b4..1e00804 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -1,5 +1,6 @@
  /* SPDX-License-Identifier: GPL-2.0-only */
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   * Copyright (C) 2013 Red Hat
   * Author: Rob Clark 
@@ -146,6 +147,7 @@ struct dpu_global_state {
uint32_t ctl_to_enc_id[CTL_MAX - CTL_0];
uint32_t intf_to_enc_id[INTF_MAX - INTF_0];
uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
+   uint32_t wb_to_enc_id[WB_MAX - WB_0];
  };
  
  struct dpu_global_state

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index f9c83d6..edd0b7a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
   */
  
@@ -9,6 +10,7 @@

  #include "dpu_hw_ctl.h"
  #include "dpu_hw_pingpong.h"
  #include "dpu_hw_intf.h"
+#include "dpu_hw_wb.h"
  #include "dpu_hw_dspp.h"
  #include "dpu_hw_merge3d.h"
  #include "dpu_encoder.h"
@@ -75,6 +77,14 @@ int dpu_rm_destroy(struct dpu_rm *rm)
dpu_hw_intf_destroy(hw);
}
}
+   for (i = 0; i < ARRAY_SIZE(rm->wb_blks); i++) {
+   struct dpu_hw_wb *hw;
+
+   if (rm->wb_blks[i]) {
+   hw = to_dpu_hw_wb(rm->wb_blks[i]);
+   dpu_hw_wb_destroy(hw);
+   }
+   }
  
  	return 0;

  }
@@ -187,6 +197,24 @@ int dpu_rm_init(struct dpu_rm *rm,
rm->intf_blks[intf->id - INTF_0] = &hw->base;
}
  
+	for (i = 0; i < cat->wb_count; i++) {

+   struct dpu_hw_wb *hw;
+   const struct dpu_wb_cfg *wb = &cat->wb[i];
+
+   if (wb->id < WB_0 || wb->id >= WB_MAX) {
+   DPU_ERROR("skip intf %d with invalid id\n", wb->id);
+   continue;
+   }
+
+   hw = dpu_hw_wb_init(wb->id, mmio, cat);
+   if (IS_ERR_OR_NULL(hw)) {
+   rc = PTR_ERR(hw);
+   DPU_ERROR("failed wb object creation: err %d\n", rc);
+   goto fail;
+   }
+   rm->wb_blks[wb->id - WB_0] = &hw->base;
+   }
+
for (i = 0; i < cat->ctl_count; i++) {
struct dpu_hw_ctl *hw;
const struct dpu_ctl_cfg *ctl = &cat->ctl[i];
@@ -479,6 +507,33 @@ static int _dpu_rm_reserve_intf(
return 0;
  }
  
+static int _dpu_rm_reserve_wb(

+   struct dpu_rm *rm,
+   struct dpu_global_state *global_state,
+   uint32_t enc_id,
+   uint32_t id)
+{
+   int idx = id - WB_0;
+
+   if (idx < 0 || idx >= ARRAY_SIZE(rm->wb_blks)) {
+   DPU_ERROR("invalid intf id: %d", id);
+   return -EINVAL;
+   }
+
+   if (!rm->wb_blks[idx]) {
+   

Re: [PATCH 07/12] drm/msm/dpu: add encoder operations to prepare/cleanup wb job

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

add dpu encoder APIs to prepare and cleanup writeback job
for the writeback encoder. These shall be invoked from the
prepare_wb_job/cleanup_wb_job hooks of the drm_writeback
framework.


Having dpu-encoder-wide API for the single case of WB looks like an 
overkill. But I think we have no other choice here.


Reviewed-by: Dmitry Baryshkov 



Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c  | 34 
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h  | 16 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  5 
  3 files changed, 55 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 947069b..b51a677 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -958,6 +958,40 @@ static int dpu_encoder_resource_control(struct drm_encoder 
*drm_enc,
return 0;
  }
  
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,

+   struct drm_writeback_job *job)
+{
+   struct dpu_encoder_virt *dpu_enc;
+   int i;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+   if (phys->ops.prepare_wb_job)
+   phys->ops.prepare_wb_job(phys, job);
+
+   }
+}
+
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job)
+{
+   struct dpu_encoder_virt *dpu_enc;
+   int i;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+   if (phys->ops.cleanup_wb_job)
+   phys->ops.cleanup_wb_job(phys, job);
+
+   }
+}
+
  static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
  struct drm_display_mode *mode,
  struct drm_display_mode *adj_mode)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index cc10436..da5b6d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -171,4 +171,20 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
   */
  int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
  
+/**

+ * dpu_encoder_prepare_wb_job - prepare writeback job for the encoder.
+ * @drm_enc:Pointer to previously created drm encoder structure
+ * @job:Pointer to the current drm writeback job
+ */
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job);
+
+/**
+ * dpu_encoder_cleanup_wb_job - cleanup writeback job for the encoder.
+ * @drm_enc:Pointer to previously created drm encoder structure
+ * @job:Pointer to the current drm writeback job
+ */
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job);
+
  #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 07c3525..7b3354d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -7,6 +7,7 @@
  #ifndef __DPU_ENCODER_PHYS_H__
  #define __DPU_ENCODER_PHYS_H__
  
+#include 

  #include 
  
  #include "dpu_kms.h"

@@ -146,6 +147,10 @@ struct dpu_encoder_phys_ops {
void (*restore)(struct dpu_encoder_phys *phys);
int (*get_line_count)(struct dpu_encoder_phys *phys);
int (*get_frame_count)(struct dpu_encoder_phys *phys);
+   void (*prepare_wb_job)(struct dpu_encoder_phys *phys_enc,
+   struct drm_writeback_job *job);
+   void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
+   struct drm_writeback_job *job);
  };
  
  /**



--
With best wishes
Dmitry


Re: [PATCH v3 1/3] drm/msm/dp: revise timing engine programming to support widebus feature

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 02:26, Kuogee Hsieh wrote:


On 2/4/2022 2:05 PM, Dmitry Baryshkov wrote:

On 04/02/2022 21:36, Kuogee Hsieh wrote:
Widebus feature will transmit two pixel data per pixel clock to 
interface.

Timing engine provides driving force for this purpose. This patch base
on HPG (Hardware Programming Guide) to revise timing engine register
setting to accommodate both widebus and non widebus application. Also
horizontal width parameters need to be reduced by half since two pixel
data are clocked out per pixel clock when widebus feature enabled.
In addition, revised timing engine function is an generic function and
intend to be shared by all platforms to reduce maintenance efforts.

Changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    | 10 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h    |  2 +
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c    | 99 
++

  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h    |  2 +
  5 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c

index 0d315b4..0c22839 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -208,6 +208,8 @@ struct dpu_encoder_virt {
    u32 idle_timeout;
  +    bool wide_bus_en;
+
  struct msm_dp *dp;
  };
  @@ -217,6 +219,14 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
  15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
  };
  +
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+    struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+    return dpu_enc->wide_bus_en;
+}
+
  static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong 
*hw_pp, unsigned bpc)

  {
  struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h

index 99a5d73..893d74d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -168,4 +168,6 @@ int dpu_encoder_get_linecount(struct drm_encoder 
*drm_enc);

   */
  int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc);
  +bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc);
+
  #endif /* __DPU_ENCODER_H__ */


This chunk does not apply against the msm-next. The conflict is 
trivial, but it would be nice to know that the code was tested against 
the current tip.
My fault, I forget to cherry-pick to msm-next this time before upload 
for review


diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c

index 185379b..3d6c914 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -110,6 +110,20 @@ static void drm_mode_to_intf_timing_params(
  timing->v_back_porch += timing->v_front_porch;
  timing->v_front_porch = 0;
  }
+
+    timing->wide_bus_en = 
dpu_encoder_is_widebus_enabled(phys_enc->parent);

+
+    /*
+ * for DP, divide the horizonal parameters by 2 when
+ * widebus is enabled
+ */
+    if (timing->wide_bus_en) {
+    timing->width = timing->width >> 1;
+    timing->xres = timing->xres >> 1;
+    timing->h_back_porch = timing->h_back_porch >> 1;
+    timing->h_front_porch = timing->h_front_porch >> 1;
+    timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+    }
  }
    static u32 get_horizontal_total(const struct intf_timing_params 
*timing)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c

index 116e2b5..35d4aaa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -33,6 +33,7 @@
  #define INTF_TP_COLOR1  0x05C
  #define INTF_CONFIG2    0x060
  #define INTF_DISPLAY_DATA_HCTL  0x064
+#define INTF_ACTIVE_DATA_HCTL   0x068
  #define INTF_FRAME_LINE_COUNT_EN    0x0A8
  #define INTF_FRAME_COUNT    0x0AC
  #define   INTF_LINE_COUNT   0x0B0
@@ -90,68 +91,95 @@ static void 
dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,

  u32 hsync_period, vsync_period;
  u32 display_v_start, display_v_end;
  u32 hsync_start_x, hsync_end_x;
+    u32 hsync_data_start_x, hsync_data_end_x;
  u32 active_h_start, active_h_end;
  u32 active_v_start, active_v_end;
  u32 active_hctl, display_hctl, hsync_ctl;
  u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
  u3

Re: [PATCH 06/12] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Make changes to dpu_encoder to support virtual encoder needed
to support writeback for dpu.


This patch will change significantly if



Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 57 +
  1 file changed, 42 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index e977c05..947069b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -974,6 +974,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL };
+   enum dpu_hw_blk_type blk_type;
int num_lm, num_ctl, num_pp;
int i, j;
  
@@ -1061,20 +1062,36 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,

phys->hw_pp = dpu_enc->hw_pp[i];
phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
  
+		if (phys->intf_mode == INTF_MODE_WB_LINE)

+   blk_type = DPU_HW_BLK_WB;
+   else
+   blk_type = DPU_HW_BLK_INTF;
+
num_blk = dpu_rm_get_assigned_resources(&dpu_kms->rm,
-   global_state, drm_enc->base.id, DPU_HW_BLK_INTF,
+   global_state, drm_enc->base.id, blk_type,
hw_blk, ARRAY_SIZE(hw_blk));
-   for (j = 0; j < num_blk; j++) {
-   struct dpu_hw_intf *hw_intf;
  
-			hw_intf = to_dpu_hw_intf(hw_blk[i]);

-   if (hw_intf->idx == phys->intf_idx)
-   phys->hw_intf = hw_intf;
+   if (blk_type == DPU_HW_BLK_WB) {
+   for (j = 0; j < num_blk; j++) {
+   struct dpu_hw_wb *hw_wb;
+
+   hw_wb = to_dpu_hw_wb(hw_blk[i]);
+   if (hw_wb->idx == phys->intf_idx)
+   phys->hw_wb = hw_wb;
+   }
+   } else {
+   for (j = 0; j < num_blk; j++) {
+   struct dpu_hw_intf *hw_intf;
+
+   hw_intf = to_dpu_hw_intf(hw_blk[i]);
+   if (hw_intf->idx == phys->intf_idx)
+   phys->hw_intf = hw_intf;
+   }
}


I think that if we sequentially call dpu_rm_get_assigned_resources(.., 
DPU_HW_BLK_INTF, ...) and then dpu_rm_get_assigned_resources(.., 
DPU_HW_BLK_WB, ...), the code would be cleaner.


Or even better get the WB direclty using the provided ID.

  
-		if (!phys->hw_intf) {

+   if (!phys->hw_intf && !phys->hw_wb) {
DPU_ERROR_ENC(dpu_enc,
- "no intf block assigned at idx: %d\n", i);
+ "no intf or WB block assigned at idx: 
%d\n", i);
return;
}
  
@@ -1224,15 +1241,22 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)

mutex_unlock(&dpu_enc->enc_lock);
  }
  
-static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,

+static enum dpu_intf dpu_encoder_get_intf_or_wb(struct dpu_mdss_cfg *catalog,
enum dpu_intf_type type, u32 controller_id)
  {
int i = 0;
  
-	for (i = 0; i < catalog->intf_count; i++) {

-   if (catalog->intf[i].type == type
-   && catalog->intf[i].controller_id == controller_id) {
-   return catalog->intf[i].id;
+   if (type != INTF_WB) {
+   for (i = 0; i < catalog->intf_count; i++) {
+   if (catalog->intf[i].type == type
+   && catalog->intf[i].controller_id == 
controller_id) {
+   return catalog->intf[i].id;
+   }
+   }
+   } else {
+   for (i = 0; i < catalog->wb_count; i++) {
+   if (catalog->wb[i].id == controller_id)
+   return catalog->wb[i].id;
}
}
  
@@ -2096,6 +2120,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,

case DRM_MODE_ENCODER_TMDS:
intf_type = INTF_DP;
break;
+   case DRM_MODE_ENCODER_VIRTUAL:
+   intf_type = INTF_WB;
+   break;
}
  
  	WARN_ON(disp_info->num_of_h_tiles < 1);

@@ -2128,11 +2155,11 @@ static int dpu_encoder_setup_display(struct 
dpu_encoder_virt *dpu_enc,
DPU_DEBUG("h_tile_instance %d = %d, split_role %d\n",
i, controller_id, phys_params.split_role);
  
-		phys_params.intf

Re: [PATCH v3 1/3] drm/msm/dp: revise timing engine programming to support widebus feature

2022-02-04 Thread Kuogee Hsieh



On 2/4/2022 2:05 PM, Dmitry Baryshkov wrote:

On 04/02/2022 21:36, Kuogee Hsieh wrote:
Widebus feature will transmit two pixel data per pixel clock to 
interface.

Timing engine provides driving force for this purpose. This patch base
on HPG (Hardware Programming Guide) to revise timing engine register
setting to accommodate both widebus and non widebus application. Also
horizontal width parameters need to be reduced by half since two pixel
data are clocked out per pixel clock when widebus feature enabled.
In addition, revised timing engine function is an generic function and
intend to be shared by all platforms to reduce maintenance efforts.

Changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    | 10 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h    |  2 +
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c    | 99 
++

  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h    |  2 +
  5 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c

index 0d315b4..0c22839 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -208,6 +208,8 @@ struct dpu_encoder_virt {
    u32 idle_timeout;
  +    bool wide_bus_en;
+
  struct msm_dp *dp;
  };
  @@ -217,6 +219,14 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
  15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
  };
  +
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+    struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+    return dpu_enc->wide_bus_en;
+}
+
  static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong 
*hw_pp, unsigned bpc)

  {
  struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h

index 99a5d73..893d74d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -168,4 +168,6 @@ int dpu_encoder_get_linecount(struct drm_encoder 
*drm_enc);

   */
  int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc);
  +bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc);
+
  #endif /* __DPU_ENCODER_H__ */


This chunk does not apply against the msm-next. The conflict is 
trivial, but it would be nice to know that the code was tested against 
the current tip.
My fault, I forget to cherry-pick to msm-next this time before upload 
for review


diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c

index 185379b..3d6c914 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -110,6 +110,20 @@ static void drm_mode_to_intf_timing_params(
  timing->v_back_porch += timing->v_front_porch;
  timing->v_front_porch = 0;
  }
+
+    timing->wide_bus_en = 
dpu_encoder_is_widebus_enabled(phys_enc->parent);

+
+    /*
+ * for DP, divide the horizonal parameters by 2 when
+ * widebus is enabled
+ */
+    if (timing->wide_bus_en) {
+    timing->width = timing->width >> 1;
+    timing->xres = timing->xres >> 1;
+    timing->h_back_porch = timing->h_back_porch >> 1;
+    timing->h_front_porch = timing->h_front_porch >> 1;
+    timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+    }
  }
    static u32 get_horizontal_total(const struct intf_timing_params 
*timing)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c

index 116e2b5..35d4aaa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -33,6 +33,7 @@
  #define INTF_TP_COLOR1  0x05C
  #define INTF_CONFIG2    0x060
  #define INTF_DISPLAY_DATA_HCTL  0x064
+#define INTF_ACTIVE_DATA_HCTL   0x068
  #define INTF_FRAME_LINE_COUNT_EN    0x0A8
  #define INTF_FRAME_COUNT    0x0AC
  #define   INTF_LINE_COUNT   0x0B0
@@ -90,68 +91,95 @@ static void 
dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,

  u32 hsync_period, vsync_period;
  u32 display_v_start, display_v_end;
  u32 hsync_start_x, hsync_end_x;
+    u32 hsync_data_start_x, hsync_data_end_x;
  u32 active_h_start, active_h_end;
  u32 active_v_start, active_v_end;
  u32 active_hctl, display_hctl, hsync_ctl;
  u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
  u32 panel_format;
-    u32 intf_cfg, intf_c

Re: [PATCH 09/12] drm/msm/dpu: add the writeback connector layer

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Introduce the dpu_writeback module which serves as the
interface between dpu operations and the drm_writeback.

This module manages the connector related operations for
dpu writeback.

Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/Makefile  |  1 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 71 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h | 27 ++
  3 files changed, 99 insertions(+)
  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 3abaf84..05a8515 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -74,6 +74,7 @@ msm-y := \
disp/dpu1/dpu_plane.o \
disp/dpu1/dpu_rm.o \
disp/dpu1/dpu_vbif.o \
+   disp/dpu1/dpu_writeback.o \
disp/msm_disp_snapshot.o \
disp/msm_disp_snapshot_util.o \
msm_atomic.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
new file mode 100644
index 000..7b61fad
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "dpu_writeback.h"
+
+static int dpu_wb_conn_get_modes(struct drm_connector *connector)
+{
+   struct drm_device *dev = connector->dev;
+
+   return drm_add_modes_noedid(connector, dev->mode_config.max_width,
+   dev->mode_config.max_height);
+}
+
+static const struct drm_connector_funcs dpu_wb_conn_funcs = {
+   .reset = drm_atomic_helper_connector_reset,
+   .fill_modes = drm_helper_probe_single_connector_modes,
+   .destroy = drm_connector_cleanup,
+   .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dpu_wb_conn_prepare_job(struct drm_writeback_connector *connector,
+   struct drm_writeback_job *job)
+{
+   if (!job->fb)
+   return 0;
+
+   dpu_encoder_prepare_wb_job(connector->encoder, job);
+
+   return 0;
+}
+
+static void dpu_wb_conn_cleanup_job(struct drm_writeback_connector *connector,
+   struct drm_writeback_job *job)
+{
+   if (!job->fb)
+   return;
+
+   dpu_encoder_cleanup_wb_job(connector->encoder, job);
+}
+
+static const struct drm_connector_helper_funcs dpu_wb_conn_helper_funcs = {
+   .get_modes = dpu_wb_conn_get_modes,
+   .prepare_writeback_job = dpu_wb_conn_prepare_job,
+   .cleanup_writeback_job = dpu_wb_conn_cleanup_job,
+};
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+   const struct drm_encoder_helper_funcs *enc_helper_funcs, const 
u32 *format_list,
+   u32 num_formats)


the enc_helper_funcs is always dpu_encoder_helper_funcs here. And 
enc->helper_private is already initalized. You can drop the argument.



+{
+   struct msm_drm_private *priv = dev->dev_private;
+   struct dpu_wb_connector *dpu_wb_conn;
+   int rc = 0;
+
+   dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
+   dpu_wb_conn->base.base = &dpu_wb_conn->connector;
+   dpu_wb_conn->base.encoder = enc;
+
+   drm_connector_helper_add(dpu_wb_conn->base.base, 
&dpu_wb_conn_helper_funcs);
+
+   rc = drm_writeback_connector_init(dev, &dpu_wb_conn->base,
+   &dpu_wb_conn_funcs, enc_helper_funcs,
+   format_list, num_formats);
+
+   priv->connectors[priv->num_connectors++] = dpu_wb_conn->base.base;
+
+   return rc;
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
new file mode 100644
index 000..206ce5e
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DPU_WRITEBACK_H
+#define _DPU_WRITEBACK_H
+
+#include 
+#include 
+#include 
+#include 
+
+#include "msm_drv.h"
+#include "dpu_kms.h"
+#include "dpu_encoder_phys.h"
+
+struct dpu_wb_connector {
+   struct drm_connector connector;
+   struct drm_writeback_connector base;
+};
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+   const struct drm_encoder_helper_funcs *enc_helper_funcs,
+   const u32 *format_list, u32 num_formats);
+
+#endif /*_DPU_WRITEBACK_H */



--
With best wishes
Dmitry


Re: [PATCH 08/12] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Introduce the dpu_encoder_phys_* for the writeback interface
to handle writeback specific hardware programming.

Signed-off-by: Abhinav Kumar 


Mostly looks ok, see minor comments bellow.


---
  drivers/gpu/drm/msm/Makefile   |   1 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  36 +-
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c| 813 +
  3 files changed, 849 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index c43ef35..3abaf84 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -53,6 +53,7 @@ msm-y := \
disp/dpu1/dpu_encoder.o \
disp/dpu1/dpu_encoder_phys_cmd.o \
disp/dpu1/dpu_encoder_phys_vid.o \
+   disp/dpu1/dpu_encoder_phys_wb.o \
disp/dpu1/dpu_formats.o \
disp/dpu1/dpu_hw_catalog.o \
disp/dpu1/dpu_hw_ctl.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 7b3354d..80da0a9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -159,6 +159,7 @@ struct dpu_encoder_phys_ops {
   * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
   * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
   * @INTR_IDX_RDPTR:Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_WB_DONE:  Writeback fone interrupt for virtual connector
   */
  enum dpu_intr_idx {
INTR_IDX_VSYNC,
@@ -166,6 +167,7 @@ enum dpu_intr_idx {
INTR_IDX_UNDERRUN,
INTR_IDX_CTL_START,
INTR_IDX_RDPTR,
+   INTR_IDX_WB_DONE,
INTR_IDX_MAX,
  };
  
@@ -196,7 +198,7 @@ struct dpu_encoder_irq {

   * @hw_ctl:   Hardware interface to the ctl registers
   * @hw_pp:Hardware interface to the ping pong registers
   * @hw_intf:  Hardware interface to the intf registers
- * @hw_wb: Hardware interface to the wb registers
+ * @hw_wb: Hardware interface to the wb registers
   * @dpu_kms:  Pointer to the dpu_kms top level
   * @cached_mode:  DRM mode cached at mode_set time, acted on in enable
   * @enabled:  Whether the encoder has enabled and running a mode
@@ -250,6 +252,31 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
  }
  
  /**

+ * struct dpu_encoder_phys_wb - sub-class of dpu_encoder_phys to handle command
+ * mode specific operations
+ * @base:  Baseclass physical encoder structure
+ * @wbirq_refcount: Reference count of writeback interrupt
+ * @wb_done_timeout_cnt: number of wb done irq timeout errors
+ * @wb_cfg:  writeback block config to store fb related details
+ * @cdp_cfg: chroma down prefetch block config for wb
+ * @aspace: address space to be used for wb framebuffer
+ * @wb_conn: backpointer to writeback connector
+ * @wb_job: backpointer to current writeback job
+ * @dest:   dpu buffer layout for current writeback output buffer
+ */
+struct dpu_encoder_phys_wb {
+   struct dpu_encoder_phys base;
+   atomic_t wbirq_refcount;
+   int wb_done_timeout_cnt;
+   struct dpu_hw_wb_cfg wb_cfg;
+   struct dpu_hw_wb_cdp_cfg cdp_cfg;


What about moving them to the stack rather storing them in the structure?


+   struct msm_gem_address_space *aspace;
+   struct drm_writeback_connector *wb_conn;
+   struct drm_writeback_job *wb_job;
+   struct dpu_hw_fmt_layout dest;
+};
+
+/**
   * struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle 
command
   *mode specific operations
   * @base: Baseclass physical encoder structure
@@ -317,6 +344,13 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
struct dpu_enc_phys_init_params *p);
  
  /**

+ * dpu_encoder_phys_wb_init - initialize writeback encoder
+ * @init:  Pointer to init info structure with initialization params
+ */
+struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
+   struct dpu_enc_phys_init_params *p);
+
+/**
   * dpu_encoder_helper_trigger_start - control start helper function
   *This helper function may be optionally specified by physical
   *encoders if they require ctl_start triggering.
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
new file mode 100644
index 000..783f83e
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -0,0 +1,813 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define pr_fmt(fmt)"[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include 


the header is unused


+
+#include "dpu_encoder_phys.h"
+#include "dpu_formats.h"
+#include "dpu_hw_top.h"
+#include "dpu

Re: [PATCH 02/12] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add the dpu_hw_wb abstraction to program registers related to the
writeback block. These will be invoked once all the configuration
is set and ready to be programmed to the registers.


Reviewed-by: Dmitry Baryshkov 

Few minor comments bellow.



Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/Makefile  |   1 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c | 267 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h | 145 
  3 files changed, 413 insertions(+)
  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 03ab55c..c43ef35 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -66,6 +66,7 @@ msm-y := \
disp/dpu1/dpu_hw_top.o \
disp/dpu1/dpu_hw_util.o \
disp/dpu1/dpu_hw_vbif.o \
+   disp/dpu1/dpu_hw_wb.o \
disp/dpu1/dpu_io_util.o \
disp/dpu1/dpu_kms.o \
disp/dpu1/dpu_mdss.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
new file mode 100644
index 000..d395475
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+ /*
+  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
+  */
+
+#include "dpu_hw_mdss.h"
+#include "dpu_hwio.h"
+#include "dpu_hw_catalog.h"
+#include "dpu_hw_wb.h"
+#include "dpu_formats.h"
+#include "dpu_kms.h"
+
+#define WB_DST_FORMAT 0x000
+#define WB_DST_OP_MODE0x004
+#define WB_DST_PACK_PATTERN   0x008
+#define WB_DST0_ADDR  0x00C
+#define WB_DST1_ADDR  0x010
+#define WB_DST2_ADDR  0x014
+#define WB_DST3_ADDR  0x018
+#define WB_DST_YSTRIDE0   0x01C
+#define WB_DST_YSTRIDE1   0x020
+#define WB_DST_YSTRIDE1   0x020
+#define WB_DST_DITHER_BITDEPTH0x024
+#define WB_DST_MATRIX_ROW00x030
+#define WB_DST_MATRIX_ROW10x034
+#define WB_DST_MATRIX_ROW20x038
+#define WB_DST_MATRIX_ROW30x03C
+#define WB_DST_WRITE_CONFIG   0x048
+#define WB_ROTATION_DNSCALER  0x050
+#define WB_ROTATOR_PIPE_DOWNSCALER0x054
+#define WB_N16_INIT_PHASE_X_C03   0x060
+#define WB_N16_INIT_PHASE_X_C12   0x064
+#define WB_N16_INIT_PHASE_Y_C03   0x068
+#define WB_N16_INIT_PHASE_Y_C12   0x06C
+#define WB_OUT_SIZE   0x074
+#define WB_ALPHA_X_VALUE  0x078
+#define WB_DANGER_LUT 0x084
+#define WB_SAFE_LUT   0x088
+#define WB_QOS_CTRL   0x090
+#define WB_CREQ_LUT_0 0x098
+#define WB_CREQ_LUT_1 0x09C
+#define WB_UBWC_STATIC_CTRL   0x144
+#define WB_MUX0x150
+#define WB_CROP_CTRL  0x154
+#define WB_CROP_OFFSET0x158
+#define WB_CSC_BASE   0x260
+#define WB_DST_ADDR_SW_STATUS 0x2B0
+#define WB_CDP_CNTL   0x2B4
+#define WB_OUT_IMAGE_SIZE 0x2C0
+#define WB_OUT_XY 0x2C4
+
+/* WB_QOS_CTRL */
+#define WB_QOS_CTRL_DANGER_SAFE_ENBIT(0)
+
+static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
+   const struct dpu_mdss_cfg *m, void __iomem *addr,
+   struct dpu_hw_blk_reg_map *b)
+{
+   int i;
+
+   for (i = 0; i < m->wb_count; i++) {
+   if (wb == m->wb[i].id) {
+   b->base_off = addr;
+   b->blk_off = m->wb[i].base;
+   b->length = m->wb[i].len;
+   b->hwversion = m->hwversion;
+   return &m->wb[i];
+   }
+   }
+   return ERR_PTR(-EINVAL);
+}
+
+static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
+   struct dpu_hw_wb_cfg *data)
+{
+   struct dpu_hw_blk_reg_map *c = &ctx->hw;
+
+   DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
+   DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
+   DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
+   DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
+}
+
+static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
+   struct dpu_hw_wb_cfg *data)
+{
+   struct dpu_hw_blk_reg_map *c = &ctx->hw;
+   const struct dpu_format *fmt = data->dest.format;
+   u32 dst_format, pattern, ystride0, ystride1, 

Re: [PATCH 01/12] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add writeback blocks to the sm8250 DPU hardware catalog. Other
chipsets support writeback too but add it to sm8250 to prototype
the feature so that it can be easily extended to other chipsets.

Signed-off-by: Abhinav Kumar 


Reviewed-by: Dmitry Baryshkov 


---
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 73 +-
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 66 ++-
  2 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index aa75991..fdd878d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   */
  
  #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__

@@ -90,6 +91,15 @@
 BIT(MDP_INTF3_INTR) | \
 BIT(MDP_INTF4_INTR))
  
+#define WB_SM8250_MASK (BIT(DPU_WB_LINE_MODE) | \

+BIT(DPU_WB_UBWC) | \
+BIT(DPU_WB_YUV_CONFIG) | \
+BIT(DPU_WB_PIPE_ALPHA) | \
+BIT(DPU_WB_XY_ROI_OFFSET) | \
+BIT(DPU_WB_QOS) | \
+BIT(DPU_WB_QOS_8LVL) | \
+BIT(DPU_WB_CDP) | \
+BIT(DPU_WB_INPUT_CTRL))
  
  #define DEFAULT_PIXEL_RAM_SIZE		(50 * 1024)

  #define DEFAULT_DPU_LINE_WIDTH2048
@@ -177,6 +187,40 @@ static const uint32_t plane_formats_yuv[] = {
DRM_FORMAT_YVU420,
  };
  
+static const uint32_t wb2_formats[] = {

+   DRM_FORMAT_RGB565,
+   DRM_FORMAT_BGR565,
+   DRM_FORMAT_RGB888,
+   DRM_FORMAT_ARGB,
+   DRM_FORMAT_RGBA,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_XRGB,
+   DRM_FORMAT_RGBX,
+   DRM_FORMAT_XBGR,
+   DRM_FORMAT_ARGB1555,
+   DRM_FORMAT_RGBA5551,
+   DRM_FORMAT_XRGB1555,
+   DRM_FORMAT_RGBX5551,
+   DRM_FORMAT_ARGB,
+   DRM_FORMAT_RGBA,
+   DRM_FORMAT_RGBX,
+   DRM_FORMAT_XRGB,
+   DRM_FORMAT_BGR565,
+   DRM_FORMAT_BGR888,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_BGRA,
+   DRM_FORMAT_BGRX,
+   DRM_FORMAT_XBGR,
+   DRM_FORMAT_ABGR1555,
+   DRM_FORMAT_BGRA5551,
+   DRM_FORMAT_XBGR1555,
+   DRM_FORMAT_BGRX5551,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_BGRA,
+   DRM_FORMAT_BGRX,
+   DRM_FORMAT_XBGR,
+};
+
  /*
   * DPU sub blocks config
   */
@@ -317,6 +361,8 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = {
.reg_off = 0x2C4, .bit_off = 8},
.clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
.reg_off = 0x2BC, .bit_off = 20},
+   .clk_ctrls[DPU_CLK_CTRL_WB2] = {
+   .reg_off = 0x3B8, .bit_off = 24},
},
  };
  
@@ -862,6 +908,29 @@ static const struct dpu_intf_cfg sc7280_intf[] = {

  };
  
  /*

+ * Writeback blocks config
+ */
+#define WB_BLK(_name, _id, _base, _features, _clk_ctrl, \
+   __xin_id, vbif_id, _reg, _wb_done_bit) \
+   { \
+   .name = _name, .id = _id, \
+   .base = _base, .len = 0x2c8, \
+   .features = _features, \
+   .format_list = wb2_formats, \
+   .num_formats = ARRAY_SIZE(wb2_formats), \
+   .clk_ctrl = _clk_ctrl, \
+   .xin_id = __xin_id, \
+   .vbif_idx = vbif_id, \
+   .maxlinewidth = DEFAULT_DPU_LINE_WIDTH, \
+   .intr_wb_done = DPU_IRQ_IDX(_reg, _wb_done_bit) \
+   }
+
+static const struct dpu_wb_cfg sm8250_wb[] = {
+   WB_BLK("wb_2", WB_2, 0x65000, WB_SM8250_MASK, DPU_CLK_CTRL_WB2, 6,
+   VBIF_RT, MDP_SSPP_TOP0_INTR, 4),
+};
+
+/*
   * VBIF sub blocks config
   */
  /* VBIF QOS remap */
@@ -1225,6 +1294,8 @@ static void sm8250_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
.intf = sm8150_intf,
.vbif_count = ARRAY_SIZE(sdm845_vbif),
.vbif = sdm845_vbif,
+   .wb_count = ARRAY_SIZE(sm8250_wb),
+   .wb = sm8250_wb,
.reg_dma_count = 1,
.dma_cfg = sm8250_regdma,
.perf = sm8250_perf_data,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
ind

Re: [PATCH 11/12] drm/msm/dpu: gracefully handle null fb commits for writeback

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

kms_writeback test cases also verify with a null fb for the
writeback connector job. In addition there are also other
commit paths which can result in kickoffs without a valid
framebuffer like while closing the fb which results in the
callback to drm_atomic_helper_dirtyfb() which internally
triggers a commit.

Add protection in the dpu driver to ensure that commits for
writeback encoders without a valid fb are gracefully skipped.

Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c|  9 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  6 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h|  1 +
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 12 
  5 files changed, 49 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index e7c9fe1..f7963b0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -869,6 +869,13 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
  
  	DPU_ATRACE_BEGIN("crtc_commit");
  
+	drm_for_each_encoder_mask(encoder, crtc->dev,

+   crtc->state->encoder_mask) {
+   if (!dpu_encoder_has_valid_fb(encoder)) {


Two small comments here. First, let's probably rename the function to 
dpu_encoder_is_valid() or dpu_encoder_is_valid_for_commit() (ugh, too 
long). There might be other cases (in theory), why encoder is invalid at 
this moment.


Also (a minor nit): I think that we should commit if at least one of 
encoders is valid. So we might want to create an encoder_valid_mask 
basing on the calls to dpu_encoder. And then use it later for calling 
dpu_encoder_prepare_for_kickoff() and dpu_encoder_kickoff().



+   DRM_DEBUG_ATOMIC("invalid FB not kicking off crtc\n");
+   goto end;
+   }
+   }
/*
 * Encoder will flush/start now, unless it has a tx pending. If so, it
 * may delay and flush at an irq event (e.g. ppdone)
@@ -891,6 +898,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
dpu_encoder_kickoff(encoder);
  
  	reinit_completion(&dpu_crtc->frame_done_comp);

+
+end:
DPU_ATRACE_END("crtc_commit");
  }
  
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c

index 3746432..e990dbc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1832,6 +1832,27 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder 
*drm_enc)
}
  }
  
+bool dpu_encoder_has_valid_fb(struct drm_encoder *drm_enc)

+{
+   struct dpu_encoder_virt *dpu_enc;
+   unsigned int i;
+   struct dpu_encoder_phys *phys;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   if (drm_enc->encoder_type == DRM_MODE_ENCODER_VIRTUAL) {
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   phys = dpu_enc->phys_encs[i];
+   if (phys->ops.has_valid_output_fb && 
!phys->ops.has_valid_output_fb(phys)) {
+   DPU_DEBUG("invalid FB not kicking off\n");
+   return false;
+   }
+   }
+   }
+
+   return true;
+}
+
  void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
  {
struct dpu_encoder_virt *dpu_enc;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index da5b6d6..63d90b8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -187,4 +187,10 @@ void dpu_encoder_prepare_wb_job(struct drm_encoder 
*drm_enc,
  void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
struct drm_writeback_job *job);
  
+/**

+ * dpu_encoder_has_valid_fb - cleanup writeback job for the encoder.
+ * @drm_enc:Pointer to drm encoder structure
+ */
+bool dpu_encoder_has_valid_fb(struct drm_encoder *drm_enc);
+
  #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 80da0a9..5b45b3c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -151,6 +151,7 @@ struct dpu_encoder_phys_ops {
struct drm_writeback_job *job);
void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
struct drm_writeback_job *job);
+   bool (*has_valid_output_fb)(struct dpu_encoder_phys *phys_enc);
  };
  
  /**

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 783f83e..7eeed79 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_ph

Re: [v5 1/3] dt-bindings: msm/dsi: Add 10nm dsi phy tuning properties

2022-02-04 Thread Rob Herring
On Mon, 31 Jan 2022 01:45:17 +0530, Rajeev Nandan wrote:
> In most cases, the default values of DSI PHY tuning registers should be
> sufficient as they are fully optimized. However, in some cases where
> extreme board parasitics cause the eye shape to degrade, the override
> bits can be used to improve the signal quality.
> 
> The general guidelines for DSI PHY tuning include:
> - High and moderate data rates may benefit from the drive strength and
>   drive level tuning.
> - Drive strength tuning will affect the output impedance and may be used
>   for matching optimization.
> - Drive level tuning will affect the output levels without affecting the
>   impedance.
> 
> The clock and data lanes have a calibration circuitry feature. The drive
> strength tuning can be done by adjusting rescode offset for hstop/hsbot,
> and the drive level tuning can be done by adjusting the LDO output level
> for the HSTX drive.
> 
> Signed-off-by: Rajeev Nandan 
> ---
> 
> Changes in v2:
>  - More details in the commit text (Stephen Boyd)
>  - Use human understandable values (Stephen Boyd, Dmitry Baryshkov)
>  - Do not take values that are going to be unused (Dmitry Baryshkov)
> 
> Changes in v3:
>  - Use "qcom," prefix (Dmitry Baryshkov)
>  - Remove encoding from phy-drive-ldo-level (Dmitry Baryshkov)
>  - Use negative values instead of two's complement (Dmitry, Rob Herring)
> 
> Changes in v4:
>  - Fix dt_binding_check error (Rob Herring's bot)
> 
> Changes in v5:
>  - None
> 
>  .../bindings/display/msm/dsi-phy-10nm.yaml | 36 
> ++
>  1 file changed, 36 insertions(+)
> 

Reviewed-by: Rob Herring 


Re: [PATCH 12/12] drm/msm/dpu: add writeback blocks to the display snapshot

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add writeback block information while capturing the display
snapshot.

Signed-off-by: Abhinav Kumar 


Reviewed-by: Dmitry Baryshkov 


---
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 +
  1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 6327ba9..e227b35 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -987,6 +987,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state 
*disp_state, struct msm_k
msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len,
dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i);
  
+	/* dump WB sub-blocks HW regs info */

+   for (i = 0; i < cat->wb_count; i++)
+   msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
+   dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
+
msm_disp_snapshot_add_block(disp_state, top->hw.length,
dpu_kms->mmio + top->hw.blk_off, "top");
  



--
With best wishes
Dmitry


Re: [PATCH 10/12] drm/msm/dpu: initialize dpu encoder and connector for writeback

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Initialize dpu encoder and connector for writeback if the
target supports it in the catalog.

Signed-off-by: Abhinav Kumar 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 37 -
  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 62 +
  2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index b51a677..3746432 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2066,7 +2066,7 @@ static void dpu_encoder_early_unregister(struct 
drm_encoder *encoder)
  }
  
  static int dpu_encoder_virt_add_phys_encs(

-   u32 display_caps,
+   struct msm_display_info *disp_info,
struct dpu_encoder_virt *dpu_enc,
struct dpu_enc_phys_init_params *params)
  {
@@ -2085,7 +2085,7 @@ static int dpu_encoder_virt_add_phys_encs(
return -EINVAL;
}
  
-	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {

+   if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
enc = dpu_encoder_phys_vid_init(params);
  
  		if (IS_ERR_OR_NULL(enc)) {

@@ -2098,7 +2098,7 @@ static int dpu_encoder_virt_add_phys_encs(
++dpu_enc->num_phys_encs;
}
  
-	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {

+   if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
enc = dpu_encoder_phys_cmd_init(params);
  
  		if (IS_ERR_OR_NULL(enc)) {

@@ -2111,6 +2111,19 @@ static int dpu_encoder_virt_add_phys_encs(
++dpu_enc->num_phys_encs;
}
  
+	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {

+   enc = dpu_encoder_phys_wb_init(params);
+
+   if (IS_ERR_OR_NULL(enc)) {
+   DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
+   PTR_ERR(enc));
+   return enc == NULL ? -EINVAL : PTR_ERR(enc);
+   }
+
+   dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
+   ++dpu_enc->num_phys_encs;
+   }
+
if (params->split_role == ENC_ROLE_SLAVE)
dpu_enc->cur_slave = enc;
else
@@ -2199,9 +2212,8 @@ static int dpu_encoder_setup_display(struct 
dpu_encoder_virt *dpu_enc,
}
  
  		if (!ret) {

-   ret = 
dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
-   
 dpu_enc,
-   
 &phys_params);
+   ret = dpu_encoder_virt_add_phys_encs(disp_info,
+   dpu_enc, &phys_params);
if (ret)
DPU_ERROR_ENC(dpu_enc, "failed to add phys 
encs\n");
}
@@ -2317,11 +2329,14 @@ struct drm_encoder *dpu_encoder_init(struct drm_device 
*dev,
if (!dpu_enc)
return ERR_PTR(-ENOMEM);
  
-	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,

-   drm_enc_mode, NULL);
-   if (rc) {
-   devm_kfree(dev->dev, dpu_enc);
-   return ERR_PTR(rc);
+   /* this is handled by drm_writeback_connector_init for virtual encoder 
*/
+   if (drm_enc_mode != DRM_MODE_ENCODER_VIRTUAL) {
+   rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
+ drm_enc_mode, NULL);
+   if (rc) {
+   devm_kfree(dev->dev, dpu_enc);
+   return ERR_PTR(rc);
+   }
}
  
  	drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs);

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 47fe11a..6327ba9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
   * Copyright (C) 2013 Red Hat
   * Author: Rob Clark 
@@ -15,6 +16,7 @@
  #include 
  #include 
  #include 
+#include 
  
  #include "msm_drv.h"

  #include "msm_mmu.h"
@@ -29,6 +31,7 @@
  #include "dpu_kms.h"
  #include "dpu_plane.h"
  #include "dpu_vbif.h"
+#include "dpu_writeback.h"
  
  #define CREATE_TRACE_POINTS

  #include "dpu_trace.h"
@@ -642,6 +645,56 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return 0;
  }
  
+static int _dpu_kms_initialize_writeback(struct drm_device *dev,

+   struct msm_drm_private *priv, struct dpu_kms *dpu_kms)
+{
+   struct drm_encoder *encoder 

Re: [PATCH v6 4/4] dt-bindings: drm/bridge: anx7625: Add aux-bus node

2022-02-04 Thread Rob Herring
On Thu, 03 Feb 2022 22:10:23 +0800, Hsin-Yi Wang wrote:
> List panel under aux-bus node if it's connected to anx7625's aux bus.
> 
> Signed-off-by: Hsin-Yi Wang 
> ---
>  .../display/bridge/analogix,anx7625.yaml| 17 +
>  1 file changed, 17 insertions(+)
> 

Reviewed-by: Rob Herring 


Re: [PATCH 04/12] drm/msm/dpu: add changes to support writeback in hw_ctl

2022-02-04 Thread Dmitry Baryshkov

On 05/02/2022 00:17, Abhinav Kumar wrote:

Add changes to support writeback module in the dpu_hw_ctl
interface. In addition inroduce a reset_intf_cfg op to reset
the interface bits for the currently active interfaces in
the ctl path.

Signed-off-by: Abhinav Kumar 
---
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c   |  3 +-
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  6 +-
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 65 --
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 27 -
  4 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
index 34a6940..4cb72fa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   * Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
   */
  
@@ -70,7 +71,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg(

intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD;
intf_cfg.stream_sel = cmd_enc->stream_sel;
intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
-   ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
+   ctl->ops.setup_intf_cfg(ctl, &intf_cfg, false);
  }
  
  static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index ddd9d89..950fcd6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -1,5 +1,7 @@
  // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
+/*
+ *  Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *  Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
   */
  
  #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__

@@ -290,7 +292,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
&timing_params, fmt);
-   phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
+   phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg, 
false);
  
  	/* setup which pp blk will connect to this intf */

if (phys_enc->hw_intf->ops.bind_pingpong_blk)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index 02da9ec..a2069af 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -1,5 +1,6 @@
  // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   */
  
  #include 

@@ -23,8 +24,10 @@
  #define   CTL_SW_RESET  0x030
  #define   CTL_LAYER_EXTN_OFFSET 0x40
  #define   CTL_MERGE_3D_ACTIVE   0x0E4
+#define   CTL_WB_ACTIVE 0x0EC
  #define   CTL_INTF_ACTIVE   0x0F4
  #define   CTL_MERGE_3D_FLUSH0x100
+#define   CTL_WB_FLUSH  0x108
  #define   CTL_INTF_FLUSH0x110
  #define   CTL_INTF_MASTER   0x134
  #define   CTL_FETCH_PIPE_ACTIVE 0x0FC
@@ -35,6 +38,7 @@
  #define DPU_REG_RESET_TIMEOUT_US2000
  #define  MERGE_3D_IDX   23
  #define  INTF_IDX   31
+#define WB_IDX  16
  #define CTL_INVALID_BIT 0x
  #define CTL_DEFAULT_GROUP_ID  0xf
  
@@ -128,6 +132,9 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)

if (ctx->pending_flush_mask & BIT(INTF_IDX))
DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
ctx->pending_intf_flush_mask);
+   if (ctx->pending_flush_mask & BIT(WB_IDX))
+   DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
+   ctx->pending_wb_flush_mask);
  
  	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);

  }
@@ -248,6 +255,13 @@ static void dpu_hw_ctl_update_pending_flush_intf(struct 
dpu_hw_ctl *ctx,
}
  }
  
+static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,

+   enum dpu_wb wb)
+{
+   ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
+   ctx->pending_flush_mask |= BIT(WB_IDX);
+}
+
  static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
enum dpu_intf intf)
  {
@@ -493,10 +507,11 @@ static void dpu_hw_ctl_setup_blendstage(struct

Re: [PATCH v3 1/3] drm/msm/dp: revise timing engine programming to support widebus feature

2022-02-04 Thread Dmitry Baryshkov

On 04/02/2022 21:36, Kuogee Hsieh wrote:

Widebus feature will transmit two pixel data per pixel clock to interface.
Timing engine provides driving force for this purpose. This patch base
on HPG (Hardware Programming Guide) to revise timing engine register
setting to accommodate both widebus and non widebus application. Also
horizontal width parameters need to be reduced by half since two pixel
data are clocked out per pixel clock when widebus feature enabled.
In addition, revised timing engine function is an generic function and
intend to be shared by all platforms to reduce maintenance efforts.

Changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 10 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h|  2 +
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c| 99 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h|  2 +
  5 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0d315b4..0c22839 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -208,6 +208,8 @@ struct dpu_encoder_virt {
  
  	u32 idle_timeout;
  
+	bool wide_bus_en;

+
struct msm_dp *dp;
  };
  
@@ -217,6 +219,14 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {

15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
  };
  
+

+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+   struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   return dpu_enc->wide_bus_en;
+}
+
  static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned 
bpc)
  {
struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 99a5d73..893d74d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -168,4 +168,6 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
   */
  int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc);
  
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc);

+
  #endif /* __DPU_ENCODER_H__ */


This chunk does not apply against the msm-next. The conflict is trivial, 
but it would be nice to know that the code was tested against the 
current tip.



diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 185379b..3d6c914 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -110,6 +110,20 @@ static void drm_mode_to_intf_timing_params(
timing->v_back_porch += timing->v_front_porch;
timing->v_front_porch = 0;
}
+
+   timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent);
+
+   /*
+* for DP, divide the horizonal parameters by 2 when
+* widebus is enabled
+*/
+   if (timing->wide_bus_en) {
+   timing->width = timing->width >> 1;
+   timing->xres = timing->xres >> 1;
+   timing->h_back_porch = timing->h_back_porch >> 1;
+   timing->h_front_porch = timing->h_front_porch >> 1;
+   timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+   }
  }
  
  static u32 get_horizontal_total(const struct intf_timing_params *timing)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 116e2b5..35d4aaa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -33,6 +33,7 @@
  #define INTF_TP_COLOR1  0x05C
  #define INTF_CONFIG20x060
  #define INTF_DISPLAY_DATA_HCTL  0x064
+#define INTF_ACTIVE_DATA_HCTL   0x068
  #define INTF_FRAME_LINE_COUNT_EN0x0A8
  #define INTF_FRAME_COUNT0x0AC
  #define   INTF_LINE_COUNT   0x0B0
@@ -90,68 +91,95 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
u32 hsync_period, vsync_period;
u32 display_v_start, display_v_end;
u32 hsync_start_x, hsync_end_x;
+   u32 hsync_data_start_x, hsync_data_end_x;
u32 active_h_start, active_h_end;
u32 active_v_start, active_v_end;
u32 active_hctl, display_hctl, hsync_ctl;
u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
u32 panel_format;
-   u32 intf_cfg, intf_cfg2 = 0, display_data_hctl = 0;
+ 

Re: [PATCH v3 2/3] drm/msm/dp: revise timing engine programming to support compression (DSC)

2022-02-04 Thread Dmitry Baryshkov

On 04/02/2022 21:36, Kuogee Hsieh wrote:

Divides horizontal width by 3 at timing engine of interface. There are
major part of  compression (DSC) programming have to be done at DSC
controller which is not covered by this patch.

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 22 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h |  3 +++
  2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 35d4aaa..ee7ca34 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -128,7 +128,7 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
 * video timing. It is recommended to enable it for all cases, except
 * if compression is enabled in 1 pixel per clock mode
 */
-   if (p->wide_bus_en)
+   if (!p->compression_en || p->wide_bus_en)
intf_cfg2 |= BIT(4);


So, what exactly is BIT(4)? Is it WIDE_BUS_ENABLE of some kind? Then why 
do you disable it for compression_en?


Please, add defines for all the respective BIT(n) values.

  
  	if (p->wide_bus_en)

@@ -150,10 +150,16 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
 */
data_width = p->width;
  
-	if (!dp_intf && p->wide_bus_en)

+   if (p->compression_en) {
+   data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
+
+   if (p->wide_bus_en)
+   data_width >>= 1;
+   } else if (!dp_intf && p->wide_bus_en) {
data_width = p->width >> 1;
-   else
+   } else {
data_width = p->width;
+   }
  
  	hsync_data_start_x = hsync_start_x;

hsync_data_end_x =  hsync_start_x + data_width - 1;
@@ -178,8 +184,16 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
  
  	active_hctl = (active_h_end << 16) | active_h_start;
  
-	if (dp_intf)

+   if (dp_intf) {
display_hctl = active_hctl;
+   if (p->compression_en) {
+   active_data_hctl = (hsync_start_x +
+   p->extra_dto_cycles) << 16;
+   active_data_hctl += hsync_start_x;
+
+   display_data_hctl = active_data_hctl;
+   }
+   }
  
  	den_polarity = 0;

if (ctx->cap->type == INTF_HDMI) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
index e4a518a..8fc71ce 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
@@ -32,6 +32,9 @@ struct intf_timing_params {
u32 hsync_skew;
  
  	bool wide_bus_en;

+   bool compression_en;
+   u32 extra_dto_cycles;   /* for DP only */
+   u32 dce_bytes_per_line;
  };
  
  struct intf_prog_fetch {



--
With best wishes
Dmitry


Re: [PATCH v3 1/3] drm/msm/dp: revise timing engine programming to support widebus feature

2022-02-04 Thread Dmitry Baryshkov

On 04/02/2022 21:36, Kuogee Hsieh wrote:

Widebus feature will transmit two pixel data per pixel clock to interface.
Timing engine provides driving force for this purpose. This patch base
on HPG (Hardware Programming Guide) to revise timing engine register
setting to accommodate both widebus and non widebus application. Also
horizontal width parameters need to be reduced by half since two pixel
data are clocked out per pixel clock when widebus feature enabled.
In addition, revised timing engine function is an generic function and
intend to be shared by all platforms to reduce maintenance efforts.

Changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 10 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h|  2 +
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c| 99 ++
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h|  2 +
  5 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0d315b4..0c22839 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -208,6 +208,8 @@ struct dpu_encoder_virt {
  
  	u32 idle_timeout;
  
+	bool wide_bus_en;

+
struct msm_dp *dp;
  };
  
@@ -217,6 +219,14 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {

15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
  };
  
+

+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+   struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   return dpu_enc->wide_bus_en;
+}
+
  static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned 
bpc)
  {
struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 99a5d73..893d74d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -168,4 +168,6 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
   */
  int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc);
  
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc);

+
  #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 185379b..3d6c914 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -110,6 +110,20 @@ static void drm_mode_to_intf_timing_params(
timing->v_back_porch += timing->v_front_porch;
timing->v_front_porch = 0;
}
+
+   timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent);
+
+   /*
+* for DP, divide the horizonal parameters by 2 when
+* widebus is enabled
+*/
+   if (timing->wide_bus_en) {
+   timing->width = timing->width >> 1;
+   timing->xres = timing->xres >> 1;
+   timing->h_back_porch = timing->h_back_porch >> 1;
+   timing->h_front_porch = timing->h_front_porch >> 1;
+   timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+   }
  }
  
  static u32 get_horizontal_total(const struct intf_timing_params *timing)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 116e2b5..35d4aaa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -33,6 +33,7 @@
  #define INTF_TP_COLOR1  0x05C
  #define INTF_CONFIG20x060
  #define INTF_DISPLAY_DATA_HCTL  0x064
+#define INTF_ACTIVE_DATA_HCTL   0x068
  #define INTF_FRAME_LINE_COUNT_EN0x0A8
  #define INTF_FRAME_COUNT0x0AC
  #define   INTF_LINE_COUNT   0x0B0
@@ -90,68 +91,95 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
u32 hsync_period, vsync_period;
u32 display_v_start, display_v_end;
u32 hsync_start_x, hsync_end_x;
+   u32 hsync_data_start_x, hsync_data_end_x;
u32 active_h_start, active_h_end;
u32 active_v_start, active_v_end;
u32 active_hctl, display_hctl, hsync_ctl;
u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
u32 panel_format;
-   u32 intf_cfg, intf_cfg2 = 0, display_data_hctl = 0;
+   u32 intf_cfg, intf_cfg2 = 0;
+   u32 display_data_hctl = 0, active_data_hctl = 0;
+   u32 data_width;
+   bool dp_intf = false;
  
  	/* read

Re: [PATCH v3 3/3] drm/msm/dp: enable widebus feature for display port

2022-02-04 Thread Dmitry Baryshkov

On 04/02/2022 21:36, Kuogee Hsieh wrote:

Widebus feature will transmit two pixel data per pixel clock to interface.
This feature now is required to be enabled to easy migrant to higher
resolution applications in future. However since some legacy chipsets
does not support this feature, this feature is enabled base on chip's
hardware revision.

changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches
-- enable widebus feature base on chip hardware revision

Signed-off-by: Kuogee Hsieh 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  4 +++-
  drivers/gpu/drm/msm/dp/dp_catalog.c | 36 +++--
  drivers/gpu/drm/msm/dp/dp_catalog.h |  3 ++-
  drivers/gpu/drm/msm/dp/dp_ctrl.c| 13 +++
  drivers/gpu/drm/msm/dp/dp_ctrl.h|  1 +
  drivers/gpu/drm/msm/dp/dp_display.c | 30 
  drivers/gpu/drm/msm/dp/dp_display.h |  2 ++
  drivers/gpu/drm/msm/dp/dp_panel.c   |  4 ++--
  drivers/gpu/drm/msm/dp/dp_panel.h   |  2 +-
  drivers/gpu/drm/msm/msm_drv.h   |  6 +
  10 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0c22839..b2d23c2 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2167,8 +2167,10 @@ int dpu_encoder_setup(struct drm_device *dev, struct 
drm_encoder *enc,
timer_setup(&dpu_enc->vsync_event_timer,
dpu_encoder_vsync_event_handler,
0);
-   else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS)
+   else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS) {
dpu_enc->dp = priv->dp[disp_info->h_tile_instance[0]];
+   dpu_enc->wide_bus_en = msm_dp_wide_bus_enable(dpu_enc->dp);
+   }
  
  	INIT_DELAYED_WORK(&dpu_enc->delayed_off_work,

dpu_encoder_off_work);


If this patch is moved to #1, this hunk can go into the respective DPU 
patch. Could you please change the order?



diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 64f0b26..99d087e 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -483,6 +483,27 @@ int dp_catalog_ctrl_set_pattern_state_bit(struct 
dp_catalog *dp_catalog,
  }
  
  /**

+ * dp_catalog_hw_revision() - retrieve DP hw revision
+ *
+ * @dp_catalog: DP catalog structure
+ *
+ * return: u32
+ *
+ * This function return the DP controller hw revision
+ *
+ */
+u32 dp_catalog_hw_revision(struct dp_catalog *dp_catalog)
+{
+   u32 revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   revision = dp_read_ahb(catalog, REG_DP_HW_VERSION);
+
+   return revision;
+}
+
+/**
   * dp_catalog_ctrl_reset() - reset DP controller
   *
   * @dp_catalog: DP catalog structure
@@ -739,10 +760,11 @@ u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog 
*dp_catalog)
  }
  
  /* panel related catalog functions */

-int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog, bool 
wide_bus_en)
  {
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
+   u32 reg;
  
  	dp_write_link(catalog, REG_DP_TOTAL_HOR_VER,

dp_catalog->total);
@@ -751,7 +773,17 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY,
dp_catalog->width_blanking);
dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
-   dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0);
+
+   reg = dp_read_p0(catalog, MMSS_DP_INTF_CONFIG);
+
+   if (wide_bus_en)
+   reg |= BIT(4);  /* DATABUS_WIDEN */
+   else
+   reg &= ~BIT(4);
+
+   DRM_DEBUG_DP("wide_bus_en=%d reg=%x\n", wide_bus_en, reg);
+
+   dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, reg);
return 0;
  }
  
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h

index 7dea101..a3a0129 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -95,6 +95,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog, u32 cc, u32 tb);
  void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
u32 stream_rate_khz, bool fixed_nvid);
  int dp_catalog_ctrl_set_pattern_state_bit(struct 

Re: [PATCH] drm/panel: simple: Assign data from panel_dpi_probe() correctly

2022-02-04 Thread Sam Ravnborg
On Tue, Feb 01, 2022 at 12:01:53PM +0100, Christoph Niedermaier wrote:
> In the function panel_simple_probe() the pointer panel->desc is
> assigned to the passed pointer desc. If function panel_dpi_probe()
> is called panel->desc will be updated, but further on only desc
> will be evaluated. So update the desc pointer to be able to use
> the data from the function panel_dpi_probe().
> 
> Fixes: 4a1d0dbc8332 ("drm/panel: simple: add panel-dpi support")
> 
> Signed-off-by: Christoph Niedermaier 
> Cc: Marek Vasut 
> Cc: Thierry Reding 
> Cc: Sam Ravnborg 
> Cc: David Airlie 
> Cc: Daniel Vetter 
> To: dri-devel@lists.freedesktop.org

Thanks for fixing this
Reviewed-by: Sam Ravnborg 

> ---
>  drivers/gpu/drm/panel/panel-simple.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/panel/panel-simple.c 
> b/drivers/gpu/drm/panel/panel-simple.c
> index 9e46db5e359c..3c08f9827acf 100644
> --- a/drivers/gpu/drm/panel/panel-simple.c
> +++ b/drivers/gpu/drm/panel/panel-simple.c
> @@ -588,6 +588,7 @@ static int panel_simple_probe(struct device *dev, const 
> struct panel_desc *desc)
>   err = panel_dpi_probe(dev, panel);
>   if (err)
>   goto free_ddc;
> + desc = panel->desc;
>   } else {
>   if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
>   panel_simple_parse_panel_timing_node(dev, panel, &dt);
> -- 
> 2.11.0


[PATCH 12/12] drm/msm/dpu: add writeback blocks to the display snapshot

2022-02-04 Thread Abhinav Kumar
Add writeback block information while capturing the display
snapshot.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 6327ba9..e227b35 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -987,6 +987,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state 
*disp_state, struct msm_k
msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len,
dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i);
 
+   /* dump WB sub-blocks HW regs info */
+   for (i = 0; i < cat->wb_count; i++)
+   msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
+   dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
+
msm_disp_snapshot_add_block(disp_state, top->hw.length,
dpu_kms->mmio + top->hw.blk_off, "top");
 
-- 
2.7.4



[PATCH 10/12] drm/msm/dpu: initialize dpu encoder and connector for writeback

2022-02-04 Thread Abhinav Kumar
Initialize dpu encoder and connector for writeback if the
target supports it in the catalog.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 37 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 62 +
 2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index b51a677..3746432 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2066,7 +2066,7 @@ static void dpu_encoder_early_unregister(struct 
drm_encoder *encoder)
 }
 
 static int dpu_encoder_virt_add_phys_encs(
-   u32 display_caps,
+   struct msm_display_info *disp_info,
struct dpu_encoder_virt *dpu_enc,
struct dpu_enc_phys_init_params *params)
 {
@@ -2085,7 +2085,7 @@ static int dpu_encoder_virt_add_phys_encs(
return -EINVAL;
}
 
-   if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
+   if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
enc = dpu_encoder_phys_vid_init(params);
 
if (IS_ERR_OR_NULL(enc)) {
@@ -2098,7 +2098,7 @@ static int dpu_encoder_virt_add_phys_encs(
++dpu_enc->num_phys_encs;
}
 
-   if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
+   if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
enc = dpu_encoder_phys_cmd_init(params);
 
if (IS_ERR_OR_NULL(enc)) {
@@ -2111,6 +2111,19 @@ static int dpu_encoder_virt_add_phys_encs(
++dpu_enc->num_phys_encs;
}
 
+   if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
+   enc = dpu_encoder_phys_wb_init(params);
+
+   if (IS_ERR_OR_NULL(enc)) {
+   DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
+   PTR_ERR(enc));
+   return enc == NULL ? -EINVAL : PTR_ERR(enc);
+   }
+
+   dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
+   ++dpu_enc->num_phys_encs;
+   }
+
if (params->split_role == ENC_ROLE_SLAVE)
dpu_enc->cur_slave = enc;
else
@@ -2199,9 +2212,8 @@ static int dpu_encoder_setup_display(struct 
dpu_encoder_virt *dpu_enc,
}
 
if (!ret) {
-   ret = 
dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
-   
 dpu_enc,
-   
 &phys_params);
+   ret = dpu_encoder_virt_add_phys_encs(disp_info,
+   dpu_enc, &phys_params);
if (ret)
DPU_ERROR_ENC(dpu_enc, "failed to add phys 
encs\n");
}
@@ -2317,11 +2329,14 @@ struct drm_encoder *dpu_encoder_init(struct drm_device 
*dev,
if (!dpu_enc)
return ERR_PTR(-ENOMEM);
 
-   rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
-   drm_enc_mode, NULL);
-   if (rc) {
-   devm_kfree(dev->dev, dpu_enc);
-   return ERR_PTR(rc);
+   /* this is handled by drm_writeback_connector_init for virtual encoder 
*/
+   if (drm_enc_mode != DRM_MODE_ENCODER_VIRTUAL) {
+   rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
+ drm_enc_mode, NULL);
+   if (rc) {
+   devm_kfree(dev->dev, dpu_enc);
+   return ERR_PTR(rc);
+   }
}
 
drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 47fe11a..6327ba9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark 
@@ -15,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "msm_drv.h"
 #include "msm_mmu.h"
@@ -29,6 +31,7 @@
 #include "dpu_kms.h"
 #include "dpu_plane.h"
 #include "dpu_vbif.h"
+#include "dpu_writeback.h"
 
 #define CREATE_TRACE_POINTS
 #include "dpu_trace.h"
@@ -642,6 +645,56 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return 0;
 }
 
+static int _dpu_kms_initialize_writeback(struct drm_device *dev,
+   struct msm_drm_private *priv, struct dpu_kms *dpu_kms)
+{
+   struct drm_encoder *encoder = NULL;
+   struct ms

[PATCH 11/12] drm/msm/dpu: gracefully handle null fb commits for writeback

2022-02-04 Thread Abhinav Kumar
kms_writeback test cases also verify with a null fb for the
writeback connector job. In addition there are also other
commit paths which can result in kickoffs without a valid
framebuffer like while closing the fb which results in the
callback to drm_atomic_helper_dirtyfb() which internally
triggers a commit.

Add protection in the dpu driver to ensure that commits for
writeback encoders without a valid fb are gracefully skipped.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c|  9 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  6 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h|  1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 12 
 5 files changed, 49 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index e7c9fe1..f7963b0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -869,6 +869,13 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
 
DPU_ATRACE_BEGIN("crtc_commit");
 
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   crtc->state->encoder_mask) {
+   if (!dpu_encoder_has_valid_fb(encoder)) {
+   DRM_DEBUG_ATOMIC("invalid FB not kicking off crtc\n");
+   goto end;
+   }
+   }
/*
 * Encoder will flush/start now, unless it has a tx pending. If so, it
 * may delay and flush at an irq event (e.g. ppdone)
@@ -891,6 +898,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
dpu_encoder_kickoff(encoder);
 
reinit_completion(&dpu_crtc->frame_done_comp);
+
+end:
DPU_ATRACE_END("crtc_commit");
 }
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 3746432..e990dbc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1832,6 +1832,27 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder 
*drm_enc)
}
 }
 
+bool dpu_encoder_has_valid_fb(struct drm_encoder *drm_enc)
+{
+   struct dpu_encoder_virt *dpu_enc;
+   unsigned int i;
+   struct dpu_encoder_phys *phys;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   if (drm_enc->encoder_type == DRM_MODE_ENCODER_VIRTUAL) {
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   phys = dpu_enc->phys_encs[i];
+   if (phys->ops.has_valid_output_fb && 
!phys->ops.has_valid_output_fb(phys)) {
+   DPU_DEBUG("invalid FB not kicking off\n");
+   return false;
+   }
+   }
+   }
+
+   return true;
+}
+
 void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
 {
struct dpu_encoder_virt *dpu_enc;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index da5b6d6..63d90b8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -187,4 +187,10 @@ void dpu_encoder_prepare_wb_job(struct drm_encoder 
*drm_enc,
 void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
struct drm_writeback_job *job);
 
+/**
+ * dpu_encoder_has_valid_fb - cleanup writeback job for the encoder.
+ * @drm_enc:Pointer to drm encoder structure
+ */
+bool dpu_encoder_has_valid_fb(struct drm_encoder *drm_enc);
+
 #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 80da0a9..5b45b3c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -151,6 +151,7 @@ struct dpu_encoder_phys_ops {
struct drm_writeback_job *job);
void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
struct drm_writeback_job *job);
+   bool (*has_valid_output_fb)(struct dpu_encoder_phys *phys_enc);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 783f83e..7eeed79 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -717,6 +717,16 @@ static void dpu_encoder_phys_wb_cleanup_wb_job(struct 
dpu_encoder_phys *phys_enc
wb_enc->wb_conn = NULL;
 }
 
+static bool dpu_encoder_phys_wb_has_valid_fb(struct dpu_encoder_phys *phys_enc)
+{
+   struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+
+   if (wb_enc->wb_job)
+   return true;
+   else
+   return false;
+}
+
 /**
  * dpu_encoder_phys_wb_init_ops - initialize writeback operations
  * @ops:

[PATCH 07/12] drm/msm/dpu: add encoder operations to prepare/cleanup wb job

2022-02-04 Thread Abhinav Kumar
add dpu encoder APIs to prepare and cleanup writeback job
for the writeback encoder. These shall be invoked from the
prepare_wb_job/cleanup_wb_job hooks of the drm_writeback
framework.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c  | 34 
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h  | 16 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  5 
 3 files changed, 55 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 947069b..b51a677 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -958,6 +958,40 @@ static int dpu_encoder_resource_control(struct drm_encoder 
*drm_enc,
return 0;
 }
 
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job)
+{
+   struct dpu_encoder_virt *dpu_enc;
+   int i;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+   if (phys->ops.prepare_wb_job)
+   phys->ops.prepare_wb_job(phys, job);
+
+   }
+}
+
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job)
+{
+   struct dpu_encoder_virt *dpu_enc;
+   int i;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+   if (phys->ops.cleanup_wb_job)
+   phys->ops.cleanup_wb_job(phys, job);
+
+   }
+}
+
 static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
  struct drm_display_mode *mode,
  struct drm_display_mode *adj_mode)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index cc10436..da5b6d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -171,4 +171,20 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_prepare_wb_job - prepare writeback job for the encoder.
+ * @drm_enc:Pointer to previously created drm encoder structure
+ * @job:Pointer to the current drm writeback job
+ */
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job);
+
+/**
+ * dpu_encoder_cleanup_wb_job - cleanup writeback job for the encoder.
+ * @drm_enc:Pointer to previously created drm encoder structure
+ * @job:Pointer to the current drm writeback job
+ */
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+   struct drm_writeback_job *job);
+
 #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 07c3525..7b3354d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -7,6 +7,7 @@
 #ifndef __DPU_ENCODER_PHYS_H__
 #define __DPU_ENCODER_PHYS_H__
 
+#include 
 #include 
 
 #include "dpu_kms.h"
@@ -146,6 +147,10 @@ struct dpu_encoder_phys_ops {
void (*restore)(struct dpu_encoder_phys *phys);
int (*get_line_count)(struct dpu_encoder_phys *phys);
int (*get_frame_count)(struct dpu_encoder_phys *phys);
+   void (*prepare_wb_job)(struct dpu_encoder_phys *phys_enc,
+   struct drm_writeback_job *job);
+   void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
+   struct drm_writeback_job *job);
 };
 
 /**
-- 
2.7.4



[PATCH 09/12] drm/msm/dpu: add the writeback connector layer

2022-02-04 Thread Abhinav Kumar
Introduce the dpu_writeback module which serves as the
interface between dpu operations and the drm_writeback.

This module manages the connector related operations for
dpu writeback.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/Makefile  |  1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 71 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h | 27 ++
 3 files changed, 99 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 3abaf84..05a8515 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -74,6 +74,7 @@ msm-y := \
disp/dpu1/dpu_plane.o \
disp/dpu1/dpu_rm.o \
disp/dpu1/dpu_vbif.o \
+   disp/dpu1/dpu_writeback.o \
disp/msm_disp_snapshot.o \
disp/msm_disp_snapshot_util.o \
msm_atomic.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
new file mode 100644
index 000..7b61fad
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "dpu_writeback.h"
+
+static int dpu_wb_conn_get_modes(struct drm_connector *connector)
+{
+   struct drm_device *dev = connector->dev;
+
+   return drm_add_modes_noedid(connector, dev->mode_config.max_width,
+   dev->mode_config.max_height);
+}
+
+static const struct drm_connector_funcs dpu_wb_conn_funcs = {
+   .reset = drm_atomic_helper_connector_reset,
+   .fill_modes = drm_helper_probe_single_connector_modes,
+   .destroy = drm_connector_cleanup,
+   .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dpu_wb_conn_prepare_job(struct drm_writeback_connector *connector,
+   struct drm_writeback_job *job)
+{
+   if (!job->fb)
+   return 0;
+
+   dpu_encoder_prepare_wb_job(connector->encoder, job);
+
+   return 0;
+}
+
+static void dpu_wb_conn_cleanup_job(struct drm_writeback_connector *connector,
+   struct drm_writeback_job *job)
+{
+   if (!job->fb)
+   return;
+
+   dpu_encoder_cleanup_wb_job(connector->encoder, job);
+}
+
+static const struct drm_connector_helper_funcs dpu_wb_conn_helper_funcs = {
+   .get_modes = dpu_wb_conn_get_modes,
+   .prepare_writeback_job = dpu_wb_conn_prepare_job,
+   .cleanup_writeback_job = dpu_wb_conn_cleanup_job,
+};
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+   const struct drm_encoder_helper_funcs *enc_helper_funcs, const 
u32 *format_list,
+   u32 num_formats)
+{
+   struct msm_drm_private *priv = dev->dev_private;
+   struct dpu_wb_connector *dpu_wb_conn;
+   int rc = 0;
+
+   dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
+   dpu_wb_conn->base.base = &dpu_wb_conn->connector;
+   dpu_wb_conn->base.encoder = enc;
+
+   drm_connector_helper_add(dpu_wb_conn->base.base, 
&dpu_wb_conn_helper_funcs);
+
+   rc = drm_writeback_connector_init(dev, &dpu_wb_conn->base,
+   &dpu_wb_conn_funcs, enc_helper_funcs,
+   format_list, num_formats);
+
+   priv->connectors[priv->num_connectors++] = dpu_wb_conn->base.base;
+
+   return rc;
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
new file mode 100644
index 000..206ce5e
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DPU_WRITEBACK_H
+#define _DPU_WRITEBACK_H
+
+#include 
+#include 
+#include 
+#include 
+
+#include "msm_drv.h"
+#include "dpu_kms.h"
+#include "dpu_encoder_phys.h"
+
+struct dpu_wb_connector {
+   struct drm_connector connector;
+   struct drm_writeback_connector base;
+};
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+   const struct drm_encoder_helper_funcs *enc_helper_funcs,
+   const u32 *format_list, u32 num_formats);
+
+#endif /*_DPU_WRITEBACK_H */
-- 
2.7.4



[PATCH 08/12] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback

2022-02-04 Thread Abhinav Kumar
Introduce the dpu_encoder_phys_* for the writeback interface
to handle writeback specific hardware programming.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/Makefile   |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  36 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c| 813 +
 3 files changed, 849 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index c43ef35..3abaf84 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -53,6 +53,7 @@ msm-y := \
disp/dpu1/dpu_encoder.o \
disp/dpu1/dpu_encoder_phys_cmd.o \
disp/dpu1/dpu_encoder_phys_vid.o \
+   disp/dpu1/dpu_encoder_phys_wb.o \
disp/dpu1/dpu_formats.o \
disp/dpu1/dpu_hw_catalog.o \
disp/dpu1/dpu_hw_ctl.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 7b3354d..80da0a9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -159,6 +159,7 @@ struct dpu_encoder_phys_ops {
  * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
  * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
  * @INTR_IDX_RDPTR:Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_WB_DONE:  Writeback fone interrupt for virtual connector
  */
 enum dpu_intr_idx {
INTR_IDX_VSYNC,
@@ -166,6 +167,7 @@ enum dpu_intr_idx {
INTR_IDX_UNDERRUN,
INTR_IDX_CTL_START,
INTR_IDX_RDPTR,
+   INTR_IDX_WB_DONE,
INTR_IDX_MAX,
 };
 
@@ -196,7 +198,7 @@ struct dpu_encoder_irq {
  * @hw_ctl:Hardware interface to the ctl registers
  * @hw_pp: Hardware interface to the ping pong registers
  * @hw_intf:   Hardware interface to the intf registers
- * @hw_wb: Hardware interface to the wb registers
+ * @hw_wb: Hardware interface to the wb registers
  * @dpu_kms:   Pointer to the dpu_kms top level
  * @cached_mode:   DRM mode cached at mode_set time, acted on in enable
  * @enabled:   Whether the encoder has enabled and running a mode
@@ -250,6 +252,31 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
 }
 
 /**
+ * struct dpu_encoder_phys_wb - sub-class of dpu_encoder_phys to handle command
+ * mode specific operations
+ * @base:  Baseclass physical encoder structure
+ * @wbirq_refcount: Reference count of writeback interrupt
+ * @wb_done_timeout_cnt: number of wb done irq timeout errors
+ * @wb_cfg:  writeback block config to store fb related details
+ * @cdp_cfg: chroma down prefetch block config for wb
+ * @aspace: address space to be used for wb framebuffer
+ * @wb_conn: backpointer to writeback connector
+ * @wb_job: backpointer to current writeback job
+ * @dest:   dpu buffer layout for current writeback output buffer
+ */
+struct dpu_encoder_phys_wb {
+   struct dpu_encoder_phys base;
+   atomic_t wbirq_refcount;
+   int wb_done_timeout_cnt;
+   struct dpu_hw_wb_cfg wb_cfg;
+   struct dpu_hw_wb_cdp_cfg cdp_cfg;
+   struct msm_gem_address_space *aspace;
+   struct drm_writeback_connector *wb_conn;
+   struct drm_writeback_job *wb_job;
+   struct dpu_hw_fmt_layout dest;
+};
+
+/**
  * struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle 
command
  * mode specific operations
  * @base:  Baseclass physical encoder structure
@@ -317,6 +344,13 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
struct dpu_enc_phys_init_params *p);
 
 /**
+ * dpu_encoder_phys_wb_init - initialize writeback encoder
+ * @init:  Pointer to init info structure with initialization params
+ */
+struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
+   struct dpu_enc_phys_init_params *p);
+
+/**
  * dpu_encoder_helper_trigger_start - control start helper function
  * This helper function may be optionally specified by physical
  * encoders if they require ctl_start triggering.
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
new file mode 100644
index 000..783f83e
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -0,0 +1,813 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define pr_fmt(fmt)"[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include 
+
+#include "dpu_encoder_phys.h"
+#include "dpu_formats.h"
+#include "dpu_hw_top.h"
+#include "dpu_hw_wb.h"
+#include "dpu_hw_lm.h"
+#include "dpu_hw_blk.h"
+#include "dpu_hw_merge3d.h"
+#include "dpu_hw_interrupts.h"
+#include "dpu_core_irq.h"
+#include "dpu_vbif.h"
+#include "dpu_crtc.h"
+#include "disp/msm_disp

[PATCH 05/12] drm/msm/dpu: add an API to reset the encoder related hw blocks

2022-02-04 Thread Abhinav Kumar
Add an API to reset the encoder related hw blocks to ensure
a proper teardown of the pipeline. At the moment this is being
used only for the writeback encoder but eventually we can start
using this for all interfaces.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c  | 92 
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 10 +++
 2 files changed, 102 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1e648db..e977c05 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark 
@@ -21,6 +22,7 @@
 #include "dpu_hw_intf.h"
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_dspp.h"
+#include "dpu_hw_merge3d.h"
 #include "dpu_formats.h"
 #include "dpu_encoder_phys.h"
 #include "dpu_crtc.h"
@@ -1813,6 +1815,96 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
DPU_ATRACE_END("encoder_kickoff");
 }
 
+static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc)
+{
+   struct dpu_hw_mixer_cfg mixer;
+   int i, num_lm;
+   u32 flush_mask = 0;
+   struct dpu_global_state *global_state;
+   struct dpu_hw_blk *hw_lm[2];
+   struct dpu_hw_mixer *hw_mixer[2];
+   struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+
+   memset(&mixer, 0, sizeof(mixer));
+
+   /* reset all mixers for this encoder */
+   if (phys_enc->hw_ctl->ops.clear_all_blendstages)
+   phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl);
+
+   global_state = dpu_kms_get_existing_global_state(phys_enc->dpu_kms);
+
+   num_lm = dpu_rm_get_assigned_resources(&phys_enc->dpu_kms->rm, 
global_state,
+   phys_enc->parent->base.id, DPU_HW_BLK_LM, hw_lm, 
ARRAY_SIZE(hw_lm));
+
+   for (i = 0; i < num_lm; i++) {
+   hw_mixer[i] = to_dpu_hw_mixer(hw_lm[i]);
+   flush_mask = phys_enc->hw_ctl->ops.get_bitmask_mixer(ctl, 
hw_mixer[i]->idx);
+   if (phys_enc->hw_ctl->ops.update_pending_flush)
+   phys_enc->hw_ctl->ops.update_pending_flush(ctl, 
flush_mask);
+
+   /* clear all blendstages */
+   if (phys_enc->hw_ctl->ops.setup_blendstage)
+   phys_enc->hw_ctl->ops.setup_blendstage(ctl, 
hw_mixer[i]->idx, NULL);
+   }
+}
+
+void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
+{
+   struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+   struct dpu_hw_intf_cfg intf_cfg = { 0 };
+   int i;
+   struct dpu_encoder_virt *dpu_enc;
+
+   dpu_enc = to_dpu_encoder_virt(phys_enc->parent);
+
+   phys_enc->hw_ctl->ops.reset(ctl);
+
+   dpu_encoder_helper_reset_mixers(phys_enc);
+
+   if (phys_enc->hw_wb) {
+   /* disable the PP block */
+   if (phys_enc->hw_wb->ops.bind_pingpong_blk)
+   phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, 
false,
+   phys_enc->hw_pp->idx);
+
+   /* mark WB flush as pending */
+   if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
+   phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, 
phys_enc->hw_wb->idx);
+   } else {
+   for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+   if (dpu_enc->phys_encs[i] && 
phys_enc->hw_intf->ops.bind_pingpong_blk)
+   phys_enc->hw_intf->ops.bind_pingpong_blk(
+   dpu_enc->phys_encs[i]->hw_intf, 
false,
+   
dpu_enc->phys_encs[i]->hw_pp->idx);
+   /* mark INTF flush as pending */
+   if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
+   
phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
+   
dpu_enc->phys_encs[i]->hw_intf->idx);
+   }
+   }
+
+   /* reset the merge 3D HW block */
+   if (phys_enc->hw_pp->merge_3d) {
+   
phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
+   BLEND_3D_NONE);
+   if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d)
+   phys_enc->hw_ctl->ops.update_pending_flush_merge_3d(ctl,
+   phys_enc->hw_pp->merge_3d->idx);
+   }
+
+   intf_cfg.stream_sel = 0; /* Don't care value for video mode */
+   intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+   if (phys_enc->hw_pp->merge_3d)
+   intf_cfg.merge_3d

[PATCH 04/12] drm/msm/dpu: add changes to support writeback in hw_ctl

2022-02-04 Thread Abhinav Kumar
Add changes to support writeback module in the dpu_hw_ctl
interface. In addition inroduce a reset_intf_cfg op to reset
the interface bits for the currently active interfaces in
the ctl path.

Signed-off-by: Abhinav Kumar 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c   |  3 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  6 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 65 --
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 27 -
 4 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
index 34a6940..4cb72fa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
  */
 
@@ -70,7 +71,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg(
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD;
intf_cfg.stream_sel = cmd_enc->stream_sel;
intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
-   ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
+   ctl->ops.setup_intf_cfg(ctl, &intf_cfg, false);
 }
 
 static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index ddd9d89..950fcd6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
+/*
+ *  Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *  Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights 
reserved.
  */
 
 #define pr_fmt(fmt)"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -290,7 +292,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
&timing_params, fmt);
-   phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
+   phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg, 
false);
 
/* setup which pp blk will connect to this intf */
if (phys_enc->hw_intf->ops.bind_pingpong_blk)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index 02da9ec..a2069af 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  */
 
 #include 
@@ -23,8 +24,10 @@
 #define   CTL_SW_RESET  0x030
 #define   CTL_LAYER_EXTN_OFFSET 0x40
 #define   CTL_MERGE_3D_ACTIVE   0x0E4
+#define   CTL_WB_ACTIVE 0x0EC
 #define   CTL_INTF_ACTIVE   0x0F4
 #define   CTL_MERGE_3D_FLUSH0x100
+#define   CTL_WB_FLUSH  0x108
 #define   CTL_INTF_FLUSH0x110
 #define   CTL_INTF_MASTER   0x134
 #define   CTL_FETCH_PIPE_ACTIVE 0x0FC
@@ -35,6 +38,7 @@
 #define DPU_REG_RESET_TIMEOUT_US2000
 #define  MERGE_3D_IDX   23
 #define  INTF_IDX   31
+#define WB_IDX  16
 #define CTL_INVALID_BIT 0x
 #define CTL_DEFAULT_GROUP_ID   0xf
 
@@ -128,6 +132,9 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct 
dpu_hw_ctl *ctx)
if (ctx->pending_flush_mask & BIT(INTF_IDX))
DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
ctx->pending_intf_flush_mask);
+   if (ctx->pending_flush_mask & BIT(WB_IDX))
+   DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
+   ctx->pending_wb_flush_mask);
 
DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
@@ -248,6 +255,13 @@ static void dpu_hw_ctl_update_pending_flush_intf(struct 
dpu_hw_ctl *ctx,
}
 }
 
+static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,
+   enum dpu_wb wb)
+{
+   ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
+   ctx->pending_flush_mask |= BIT(WB_IDX);
+}
+
 static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
enum dpu_intf intf)
 {
@@ -493,10 +507,11 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl 
*ctx,
 
 
 static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *c

[PATCH 06/12] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder

2022-02-04 Thread Abhinav Kumar
Make changes to dpu_encoder to support virtual encoder needed
to support writeback for dpu.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 57 +
 1 file changed, 42 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index e977c05..947069b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -974,6 +974,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder 
*drm_enc,
struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL };
+   enum dpu_hw_blk_type blk_type;
int num_lm, num_ctl, num_pp;
int i, j;
 
@@ -1061,20 +1062,36 @@ static void dpu_encoder_virt_mode_set(struct 
drm_encoder *drm_enc,
phys->hw_pp = dpu_enc->hw_pp[i];
phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
 
+   if (phys->intf_mode == INTF_MODE_WB_LINE)
+   blk_type = DPU_HW_BLK_WB;
+   else
+   blk_type = DPU_HW_BLK_INTF;
+
num_blk = dpu_rm_get_assigned_resources(&dpu_kms->rm,
-   global_state, drm_enc->base.id, DPU_HW_BLK_INTF,
+   global_state, drm_enc->base.id, blk_type,
hw_blk, ARRAY_SIZE(hw_blk));
-   for (j = 0; j < num_blk; j++) {
-   struct dpu_hw_intf *hw_intf;
 
-   hw_intf = to_dpu_hw_intf(hw_blk[i]);
-   if (hw_intf->idx == phys->intf_idx)
-   phys->hw_intf = hw_intf;
+   if (blk_type == DPU_HW_BLK_WB) {
+   for (j = 0; j < num_blk; j++) {
+   struct dpu_hw_wb *hw_wb;
+
+   hw_wb = to_dpu_hw_wb(hw_blk[i]);
+   if (hw_wb->idx == phys->intf_idx)
+   phys->hw_wb = hw_wb;
+   }
+   } else {
+   for (j = 0; j < num_blk; j++) {
+   struct dpu_hw_intf *hw_intf;
+
+   hw_intf = to_dpu_hw_intf(hw_blk[i]);
+   if (hw_intf->idx == phys->intf_idx)
+   phys->hw_intf = hw_intf;
+   }
}
 
-   if (!phys->hw_intf) {
+   if (!phys->hw_intf && !phys->hw_wb) {
DPU_ERROR_ENC(dpu_enc,
- "no intf block assigned at idx: %d\n", i);
+ "no intf or WB block assigned at idx: 
%d\n", i);
return;
}
 
@@ -1224,15 +1241,22 @@ static void dpu_encoder_virt_disable(struct drm_encoder 
*drm_enc)
mutex_unlock(&dpu_enc->enc_lock);
 }
 
-static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
+static enum dpu_intf dpu_encoder_get_intf_or_wb(struct dpu_mdss_cfg *catalog,
enum dpu_intf_type type, u32 controller_id)
 {
int i = 0;
 
-   for (i = 0; i < catalog->intf_count; i++) {
-   if (catalog->intf[i].type == type
-   && catalog->intf[i].controller_id == controller_id) {
-   return catalog->intf[i].id;
+   if (type != INTF_WB) {
+   for (i = 0; i < catalog->intf_count; i++) {
+   if (catalog->intf[i].type == type
+   && catalog->intf[i].controller_id == 
controller_id) {
+   return catalog->intf[i].id;
+   }
+   }
+   } else {
+   for (i = 0; i < catalog->wb_count; i++) {
+   if (catalog->wb[i].id == controller_id)
+   return catalog->wb[i].id;
}
}
 
@@ -2096,6 +2120,9 @@ static int dpu_encoder_setup_display(struct 
dpu_encoder_virt *dpu_enc,
case DRM_MODE_ENCODER_TMDS:
intf_type = INTF_DP;
break;
+   case DRM_MODE_ENCODER_VIRTUAL:
+   intf_type = INTF_WB;
+   break;
}
 
WARN_ON(disp_info->num_of_h_tiles < 1);
@@ -2128,11 +2155,11 @@ static int dpu_encoder_setup_display(struct 
dpu_encoder_virt *dpu_enc,
DPU_DEBUG("h_tile_instance %d = %d, split_role %d\n",
i, controller_id, phys_params.split_role);
 
-   phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog,
+   phys_params.intf_idx = 
dpu_encoder_get_intf_or_wb(dpu_kms->catalog,

intf_type,

[PATCH 03/12] drm/msm/dpu: add writeback blocks to DPU RM

2022-02-04 Thread Abhinav Kumar
Add writeback blocks to DPU resource manager so that
writeback encoders can request for writeback hardware blocks
through RM and their usage can be tracked.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  3 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h |  2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c  | 71 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h  |  2 +
 4 files changed, 78 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index e241914..cc10436 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark 
@@ -21,9 +22,11 @@
 /**
  * Encoder functions and data types
  * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused
+ * @wbs:Writeback blocks this encoder is using
  */
 struct dpu_encoder_hw_resources {
enum dpu_intf_mode intfs[INTF_MAX];
+   enum dpu_intf_mode wbs[WB_MAX];
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
index 2d385b4..1e00804 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark 
@@ -146,6 +147,7 @@ struct dpu_global_state {
uint32_t ctl_to_enc_id[CTL_MAX - CTL_0];
uint32_t intf_to_enc_id[INTF_MAX - INTF_0];
uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
+   uint32_t wb_to_enc_id[WB_MAX - WB_0];
 };
 
 struct dpu_global_state
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index f9c83d6..edd0b7a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  */
 
@@ -9,6 +10,7 @@
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_pingpong.h"
 #include "dpu_hw_intf.h"
+#include "dpu_hw_wb.h"
 #include "dpu_hw_dspp.h"
 #include "dpu_hw_merge3d.h"
 #include "dpu_encoder.h"
@@ -75,6 +77,14 @@ int dpu_rm_destroy(struct dpu_rm *rm)
dpu_hw_intf_destroy(hw);
}
}
+   for (i = 0; i < ARRAY_SIZE(rm->wb_blks); i++) {
+   struct dpu_hw_wb *hw;
+
+   if (rm->wb_blks[i]) {
+   hw = to_dpu_hw_wb(rm->wb_blks[i]);
+   dpu_hw_wb_destroy(hw);
+   }
+   }
 
return 0;
 }
@@ -187,6 +197,24 @@ int dpu_rm_init(struct dpu_rm *rm,
rm->intf_blks[intf->id - INTF_0] = &hw->base;
}
 
+   for (i = 0; i < cat->wb_count; i++) {
+   struct dpu_hw_wb *hw;
+   const struct dpu_wb_cfg *wb = &cat->wb[i];
+
+   if (wb->id < WB_0 || wb->id >= WB_MAX) {
+   DPU_ERROR("skip intf %d with invalid id\n", wb->id);
+   continue;
+   }
+
+   hw = dpu_hw_wb_init(wb->id, mmio, cat);
+   if (IS_ERR_OR_NULL(hw)) {
+   rc = PTR_ERR(hw);
+   DPU_ERROR("failed wb object creation: err %d\n", rc);
+   goto fail;
+   }
+   rm->wb_blks[wb->id - WB_0] = &hw->base;
+   }
+
for (i = 0; i < cat->ctl_count; i++) {
struct dpu_hw_ctl *hw;
const struct dpu_ctl_cfg *ctl = &cat->ctl[i];
@@ -479,6 +507,33 @@ static int _dpu_rm_reserve_intf(
return 0;
 }
 
+static int _dpu_rm_reserve_wb(
+   struct dpu_rm *rm,
+   struct dpu_global_state *global_state,
+   uint32_t enc_id,
+   uint32_t id)
+{
+   int idx = id - WB_0;
+
+   if (idx < 0 || idx >= ARRAY_SIZE(rm->wb_blks)) {
+   DPU_ERROR("invalid intf id: %d", id);
+   return -EINVAL;
+   }
+
+   if (!rm->wb_blks[idx]) {
+   DPU_ERROR("couldn't find wb id %d\n", id);
+   return -EINVAL;
+   }
+
+   if (reserved_by_other(global_state->wb_to_enc_id, idx, enc_id)) {
+   DPU_ERROR("intf id %d already reserved\n", id);
+   return -ENAVAIL;
+   }
+
+   global_state->wb_to_enc_id[idx] = enc_id;
+   return 0;
+}
+
 static int _dpu_rm_reserve_intf_related_hw(
struct dpu_rm *rm,
   

[PATCH 02/12] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks

2022-02-04 Thread Abhinav Kumar
Add the dpu_hw_wb abstraction to program registers related to the
writeback block. These will be invoked once all the configuration
is set and ready to be programmed to the registers.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/Makefile  |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c | 267 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h | 145 
 3 files changed, 413 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 03ab55c..c43ef35 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -66,6 +66,7 @@ msm-y := \
disp/dpu1/dpu_hw_top.o \
disp/dpu1/dpu_hw_util.o \
disp/dpu1/dpu_hw_vbif.o \
+   disp/dpu1/dpu_hw_wb.o \
disp/dpu1/dpu_io_util.o \
disp/dpu1/dpu_kms.o \
disp/dpu1/dpu_mdss.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
new file mode 100644
index 000..d395475
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+ /*
+  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
+  */
+
+#include "dpu_hw_mdss.h"
+#include "dpu_hwio.h"
+#include "dpu_hw_catalog.h"
+#include "dpu_hw_wb.h"
+#include "dpu_formats.h"
+#include "dpu_kms.h"
+
+#define WB_DST_FORMAT 0x000
+#define WB_DST_OP_MODE0x004
+#define WB_DST_PACK_PATTERN   0x008
+#define WB_DST0_ADDR  0x00C
+#define WB_DST1_ADDR  0x010
+#define WB_DST2_ADDR  0x014
+#define WB_DST3_ADDR  0x018
+#define WB_DST_YSTRIDE0   0x01C
+#define WB_DST_YSTRIDE1   0x020
+#define WB_DST_YSTRIDE1   0x020
+#define WB_DST_DITHER_BITDEPTH0x024
+#define WB_DST_MATRIX_ROW00x030
+#define WB_DST_MATRIX_ROW10x034
+#define WB_DST_MATRIX_ROW20x038
+#define WB_DST_MATRIX_ROW30x03C
+#define WB_DST_WRITE_CONFIG   0x048
+#define WB_ROTATION_DNSCALER  0x050
+#define WB_ROTATOR_PIPE_DOWNSCALER0x054
+#define WB_N16_INIT_PHASE_X_C03   0x060
+#define WB_N16_INIT_PHASE_X_C12   0x064
+#define WB_N16_INIT_PHASE_Y_C03   0x068
+#define WB_N16_INIT_PHASE_Y_C12   0x06C
+#define WB_OUT_SIZE   0x074
+#define WB_ALPHA_X_VALUE  0x078
+#define WB_DANGER_LUT 0x084
+#define WB_SAFE_LUT   0x088
+#define WB_QOS_CTRL   0x090
+#define WB_CREQ_LUT_0 0x098
+#define WB_CREQ_LUT_1 0x09C
+#define WB_UBWC_STATIC_CTRL   0x144
+#define WB_MUX0x150
+#define WB_CROP_CTRL  0x154
+#define WB_CROP_OFFSET0x158
+#define WB_CSC_BASE   0x260
+#define WB_DST_ADDR_SW_STATUS 0x2B0
+#define WB_CDP_CNTL   0x2B4
+#define WB_OUT_IMAGE_SIZE 0x2C0
+#define WB_OUT_XY 0x2C4
+
+/* WB_QOS_CTRL */
+#define WB_QOS_CTRL_DANGER_SAFE_ENBIT(0)
+
+static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
+   const struct dpu_mdss_cfg *m, void __iomem *addr,
+   struct dpu_hw_blk_reg_map *b)
+{
+   int i;
+
+   for (i = 0; i < m->wb_count; i++) {
+   if (wb == m->wb[i].id) {
+   b->base_off = addr;
+   b->blk_off = m->wb[i].base;
+   b->length = m->wb[i].len;
+   b->hwversion = m->hwversion;
+   return &m->wb[i];
+   }
+   }
+   return ERR_PTR(-EINVAL);
+}
+
+static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
+   struct dpu_hw_wb_cfg *data)
+{
+   struct dpu_hw_blk_reg_map *c = &ctx->hw;
+
+   DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
+   DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
+   DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
+   DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
+}
+
+static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
+   struct dpu_hw_wb_cfg *data)
+{
+   struct dpu_hw_blk_reg_map *c = &ctx->hw;
+   const struct dpu_format *fmt = data->dest.format;
+   u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
+   u32 write_config = 0;
+   u32 opmode = 0;
+   u32 dst_addr_sw = 0;
+
+ 

[PATCH 01/12] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog

2022-02-04 Thread Abhinav Kumar
Add writeback blocks to the sm8250 DPU hardware catalog. Other
chipsets support writeback too but add it to sm8250 to prototype
the feature so that it can be easily extended to other chipsets.

Signed-off-by: Abhinav Kumar 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 73 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 66 ++-
 2 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index aa75991..fdd878d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -90,6 +91,15 @@
 BIT(MDP_INTF3_INTR) | \
 BIT(MDP_INTF4_INTR))
 
+#define WB_SM8250_MASK (BIT(DPU_WB_LINE_MODE) | \
+BIT(DPU_WB_UBWC) | \
+BIT(DPU_WB_YUV_CONFIG) | \
+BIT(DPU_WB_PIPE_ALPHA) | \
+BIT(DPU_WB_XY_ROI_OFFSET) | \
+BIT(DPU_WB_QOS) | \
+BIT(DPU_WB_QOS_8LVL) | \
+BIT(DPU_WB_CDP) | \
+BIT(DPU_WB_INPUT_CTRL))
 
 #define DEFAULT_PIXEL_RAM_SIZE (50 * 1024)
 #define DEFAULT_DPU_LINE_WIDTH 2048
@@ -177,6 +187,40 @@ static const uint32_t plane_formats_yuv[] = {
DRM_FORMAT_YVU420,
 };
 
+static const uint32_t wb2_formats[] = {
+   DRM_FORMAT_RGB565,
+   DRM_FORMAT_BGR565,
+   DRM_FORMAT_RGB888,
+   DRM_FORMAT_ARGB,
+   DRM_FORMAT_RGBA,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_XRGB,
+   DRM_FORMAT_RGBX,
+   DRM_FORMAT_XBGR,
+   DRM_FORMAT_ARGB1555,
+   DRM_FORMAT_RGBA5551,
+   DRM_FORMAT_XRGB1555,
+   DRM_FORMAT_RGBX5551,
+   DRM_FORMAT_ARGB,
+   DRM_FORMAT_RGBA,
+   DRM_FORMAT_RGBX,
+   DRM_FORMAT_XRGB,
+   DRM_FORMAT_BGR565,
+   DRM_FORMAT_BGR888,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_BGRA,
+   DRM_FORMAT_BGRX,
+   DRM_FORMAT_XBGR,
+   DRM_FORMAT_ABGR1555,
+   DRM_FORMAT_BGRA5551,
+   DRM_FORMAT_XBGR1555,
+   DRM_FORMAT_BGRX5551,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_BGRA,
+   DRM_FORMAT_BGRX,
+   DRM_FORMAT_XBGR,
+};
+
 /*
  * DPU sub blocks config
  */
@@ -317,6 +361,8 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = {
.reg_off = 0x2C4, .bit_off = 8},
.clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
.reg_off = 0x2BC, .bit_off = 20},
+   .clk_ctrls[DPU_CLK_CTRL_WB2] = {
+   .reg_off = 0x3B8, .bit_off = 24},
},
 };
 
@@ -862,6 +908,29 @@ static const struct dpu_intf_cfg sc7280_intf[] = {
 };
 
 /*
+ * Writeback blocks config
+ */
+#define WB_BLK(_name, _id, _base, _features, _clk_ctrl, \
+   __xin_id, vbif_id, _reg, _wb_done_bit) \
+   { \
+   .name = _name, .id = _id, \
+   .base = _base, .len = 0x2c8, \
+   .features = _features, \
+   .format_list = wb2_formats, \
+   .num_formats = ARRAY_SIZE(wb2_formats), \
+   .clk_ctrl = _clk_ctrl, \
+   .xin_id = __xin_id, \
+   .vbif_idx = vbif_id, \
+   .maxlinewidth = DEFAULT_DPU_LINE_WIDTH, \
+   .intr_wb_done = DPU_IRQ_IDX(_reg, _wb_done_bit) \
+   }
+
+static const struct dpu_wb_cfg sm8250_wb[] = {
+   WB_BLK("wb_2", WB_2, 0x65000, WB_SM8250_MASK, DPU_CLK_CTRL_WB2, 6,
+   VBIF_RT, MDP_SSPP_TOP0_INTR, 4),
+};
+
+/*
  * VBIF sub blocks config
  */
 /* VBIF QOS remap */
@@ -1225,6 +1294,8 @@ static void sm8250_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
.intf = sm8150_intf,
.vbif_count = ARRAY_SIZE(sdm845_vbif),
.vbif = sdm845_vbif,
+   .wb_count = ARRAY_SIZE(sm8250_wb),
+   .wb = sm8250_wb,
.reg_dma_count = 1,
.dma_cfg = sm8250_regdma,
.perf = sm8250_perf_data,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 31af04a..a3ca695 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/

[PATCH 00/12] Add writeback block support for DPU

2022-02-04 Thread Abhinav Kumar
This series adds support for writeback block on DPU. Writeback
block is extremely useful to validate boards having no physical displays
in addition to many other use-cases where we want to get the output
of the display pipeline to examine whether issue is with the display
pipeline or with the panel.

These changes have been validated on SM8250 RB5 boards with IGT KMS
writeback test-suite thereby further increasing the IGT test coverage
for DPU. I am sharing the test results below.

root@linaro-developer:~/igt_repo/igt-gpu-tools/build/tests# ./kms_writeback
[   35.066157] Console: switching to colour dummy device 80x25
[   35.071964] [IGT] kms_writeback: executing
IGT-Version: 1.26-gae2eb9e1 (aarch64) (Linux: 5.16.0-rc2-62171-g132577e2697b 
aarch64)
[   35.611418] [IGT] kms_writeback: starting subtest writeback-pixel-formats
Starting subtest: writeback-pixel-formats
[   35.618528] [IGT] kms_writeback: starting subtest 
writeback-invalid-parameters
Subtest writeback-pixel-formats: SUCCESS (0.000s)
Starting subtest: writeback-invalid-parameters
Subtest writeback-invalid-parameters: SUCCESS (0.028s)   35.657437] [IGT] 
kms_writeback: starting subtest writeback-fb-id
Starting subtest: writeback-fb-id
Subtest writeback-fb-id: SUCCESS (0.030s)
[   35.698957] [IGT] kms_writeback: starting subtest writeback-check-output
Starting subtest: writeback-check-output
[   35.852834] [IGT] kms_writeback: exiting, ret=0
Subtest writeback-check-output: SUCCESS (0.142s)
[   35.861291] Console: switching to colour frame buffer device 240x67
root@linaro-developer:~/igt_repo/igt-gpu-tools/build/tests# 

The changes can easily be extended to support any other chipset using
the DPU driver by adding the support in the catalog.

Writeback block supports various formats and features. The support
for all of them can be incrementally added on top of this framework when
validation is improved and the test frameworks are extended to validate
them.

Abhinav Kumar (12):
  drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog
  drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks
  drm/msm/dpu: add writeback blocks to DPU RM
  drm/msm/dpu: add changes to support writeback in hw_ctl
  drm/msm/dpu: add an API to reset the encoder related hw blocks
  drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  drm/msm/dpu: add encoder operations to prepare/cleanup wb job
  drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback
  drm/msm/dpu: add the writeback connector layer
  drm/msm/dpu: initialize dpu encoder and connector for writeback
  drm/msm/dpu: gracefully handle null fb commits for writeback
  drm/msm/dpu: add writeback blocks to the display snapshot

 drivers/gpu/drm/msm/Makefile   |   3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |   9 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 241 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h|  25 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  50 ++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c   |   3 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   6 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c| 825 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  73 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  66 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c |  65 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h |  27 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c  | 267 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h  | 145 
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|  67 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h|   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c |  71 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c  |  71 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h  |  27 +
 20 files changed, 2007 insertions(+), 38 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h

-- 
2.7.4



Re: [PATCH v2 1/4] drm/format-helper: Add drm_fb_{xrgb8888, gray8}_to_mono_reversed()

2022-02-04 Thread Ilia Mirkin
On Fri, Feb 4, 2022 at 10:53 AM Thomas Zimmermann  wrote:
>
> Hi
>
> Am 04.02.22 um 14:43 schrieb Javier Martinez Canillas:
> > Add support to convert XR24 and 8-bit grayscale to reversed monochrome for
> > drivers that control monochromatic panels, that only have 1 bit per pixel.
> >
> > The drm_fb_gray8_to_mono_reversed() helper was based on the function that
> > does the same in the drivers/gpu/drm/tiny/repaper.c driver.
> >
> > Signed-off-by: Javier Martinez Canillas 
> > ---
> >
> > (no changes since v1)
> >
> >   drivers/gpu/drm/drm_format_helper.c | 80 +
> >   include/drm/drm_format_helper.h |  7 +++
> >   2 files changed, 87 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_format_helper.c 
> > b/drivers/gpu/drm/drm_format_helper.c
> > index 0f28dd2bdd72..cdce4b7c25d9 100644
> > --- a/drivers/gpu/drm/drm_format_helper.c
> > +++ b/drivers/gpu/drm/drm_format_helper.c
> > @@ -584,3 +584,83 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int 
> > dst_pitch, uint32_t dst_for
> >   return -EINVAL;
> >   }
> >   EXPORT_SYMBOL(drm_fb_blit_toio);
> > +
> > +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, 
> > size_t pixels)
> > +{
> > + unsigned int xb, i;
> > +
> > + for (xb = 0; xb < pixels / 8; xb++) {
>
> In practice, all mode widths are multiples of 8 because VGA mandated it.
> So it's ok-ish to assume this here. You should probably at least print a
> warning somewhere if (pixels % 8 != 0)

Not sure if it's relevant, but 1366x768 was a fairly popular laptop
resolution. There's even a dedicated drm_mode_fixup_1366x768 in
drm_edid.c. (Would it have killed them to add 2 more horizontal
pixels? Apparently.)

Cheers,

  -ilia


Re: [PATCH v2 1/4] drm/format-helper: Add drm_fb_{xrgb8888,gray8}_to_mono_reversed()

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 20:31 schrieb Javier Martinez Canillas:

Hello Thomas,

Thanks a lot for your feedback.

On 2/4/22 16:52, Thomas Zimmermann wrote:

[snip]


+static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, size_t 
pixels)
+{
+   unsigned int xb, i;
+
+   for (xb = 0; xb < pixels / 8; xb++) {


In practice, all mode widths are multiples of 8 because VGA mandated it.
So it's ok-ish to assume this here. You should probably at least print a
warning somewhere if (pixels % 8 != 0)



Agreed.


After sending the mail, I realized that some code copies only parts of 
the source around; specifically for damage handling. None of this is 
aligned to multiple of 8. So the copying could start and end in the 
middle of bytes. You'd need a pixel-offset value of some sort.


If you don't want to handle this now, maybe at least detect this case 
and put a warning somewhere.


  
[snip]



+ * DRM doesn't have native monochrome or grayscale support.
+ * Such drivers can announce the commonly supported XR24 format to userspace
+ * and use drm_fb_xrgb_to_gray8() to convert to grayscale and then this
+ * helper function to convert to the native format.
+ */
+void drm_fb_gray8_to_mono_reversed(void *dst, unsigned int dst_pitch, const 
void *src,
+  const struct drm_rect *clip)


There's a bug here. You want to pass in a drm_framebuffer as fourth
argument.


+{
+
+   size_t height = drm_rect_height(clip);
+   size_t width = drm_rect_width(clip);
+   unsigned int y;
+   const u8 *gray8 = src;
+   u8 *mono = dst;
+
+   if (!dst_pitch)
+   dst_pitch = width;


The dst_pitch is given in bytes. You have to device by 8. Here would be
a good place to warn if (width % 8 != 0).



Ok.
  

+
+   for (y = 0; y < height; y++) {
+   drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch);
+   mono += (dst_pitch / 8);


The dst_pitch is already given in bytes.



Yes, I know but for reversed mono we want only 1/8 of the width since we
are converting from 8 bits per pixel greyscale to 1 bit per pixel mono.

Or am I misunderstanding what you meant ?


I mean that if there are 80 pixel on a scanline, the value of dst_pitch 
is already 10. These pitch values are always given in bytes.


Best regards
Thomas




+   gray8 += dst_pitch;


'gray8 += fb->pitches[0]' would be correct.



Ok.
  
[snip]



+ */
+void drm_fb_xrgb_to_mono_reversed(void *dst, unsigned int dst_pitch, const 
void *src,
+ const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+   if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB))
+   return;
+
+   if (!dst_pitch)
+   dst_pitch = drm_rect_width(clip);
+
+   drm_fb_xrgb_to_gray8(dst, dst_pitch, src, fb, clip);
+   drm_fb_gray8_to_mono_reversed(dst, dst_pitch, dst, fb, clip);


Converting from dst into dst can give incorrect results. At some point
we probably want to add restrict qualifiers to these pointers, to help
the compiler with optimizing.

A better approach here is to pull the per-line conversion from
drm_fb_xrgb_to_gray8() into a separate helper and implement a
line-by-line conversion here. something like this:

drm_fb_xrgb_to_mono_reversed()
{
  char *tmp = kmalloc(size of a single line of gray8)

  for (heigth) {
 drm_fb_xrgb_to_gray8_line(tmp, ..., src, ...);
 drm_fb_gray8_to_mono_reversed(dst, ..., tmp, ...);

 src += fb->pitches[0]
 dst += dst_pitch;
  }

  kfree(tmp);
}



I see. Yes, that sounds a much better approach. I'll change it in v3.
  
Best regards,


--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


OpenPGP_signature
Description: OpenPGP digital signature


Re: [git pull] drm fixes for 5.17-rc3

2022-02-04 Thread pr-tracker-bot
The pull request you sent on Fri, 4 Feb 2022 16:09:15 +1000:

> git://anongit.freedesktop.org/drm/drm tags/drm-fixes-2022-02-04

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/31462d9e47cf6e2cb10a69c833b5e081fff7086d

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


Re: [PATCH 19/21] fbcon: Maintain a private array of fb_info

2022-02-04 Thread Sam Ravnborg
Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:50PM +0100, Daniel Vetter wrote:
> Accessing the one in fbmem.c without taking the right locks is a bad
> idea. Instead maintain our own private copy, which is fully protected
> by console_lock() (like everything else in fbcon.c). That copy is
> serialized through fbcon_fb_registered/unregistered() calls.

I fail to see why we can make a private copy of registered_fb
just like that - are they not somehow shared between fbcon and fbmem.
So when fbmem updates it, then fbcon will use the entry or such?

I guess I am just ignorant of how registered_fb is used - but please
explain.

Sam

> 
> Also this means we do not need to hold a full fb_info reference, which
> is nice because doing so would mean a refcount loop between the
> console and the fb_info. But it's also not nice since it means
> console_lock() must be held absolutely everywhere. Well strictly
> speaking we could still try to do some refcounting games again by
> calling get_fb_info before we drop the console_lock. But things will
> get tricky.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Tetsuo Handa 
> Cc: Claudio Suarez 
> Cc: Du Cheng 
> Cc: Greg Kroah-Hartman 
> ---
>  drivers/video/fbdev/core/fbcon.c | 82 +---
>  1 file changed, 43 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index 22581952b4fd..a0ca34b29615 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -86,10 +86,6 @@
>   * - fbcon state itself is protected by the console_lock, and the code does a
>   *   pretty good job at making sure that lock is held everywhere it's needed.
>   *
> - * - access to the registered_fb array is entirely unprotected. This should 
> use
> - *   proper object lifetime handling, i.e. get/put_fb_info. This also means
> - *   switching from indices to proper pointers for fb_info everywhere.
> - *
>   * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it
>   *   means concurrent access to the same fbdev from both fbcon and userspace
>   *   will blow up. To fix this all fbcon calls from fbmem.c need to be moved 
> out
> @@ -107,6 +103,13 @@ enum {
>  
>  static struct fbcon_display fb_display[MAX_NR_CONSOLES];
>  
> +struct fb_info *fbcon_registered_fb[FB_MAX];
> +int fbcon_num_registered_fb;
> +
> +#define fbcon_for_each_registered_fb(i)  \
> + for (i = 0; WARN_CONSOLE_UNLOCKED(), i < FB_MAX; i++)   \
> + if (!fbcon_registered_fb[i]) {} else
> +
>  static signed char con2fb_map[MAX_NR_CONSOLES];
>  static signed char con2fb_map_boot[MAX_NR_CONSOLES];
>  
> @@ -114,12 +117,7 @@ static struct fb_info *fbcon_info_from_console(int 
> console)
>  {
>   WARN_CONSOLE_UNLOCKED();
>  
> - /*
> -  * Note that only con2fb_map is protected by the console lock,
> -  * registered_fb is protected by a separate mutex. This lookup can
> -  * therefore race.
> -  */
> - return registered_fb[con2fb_map[console]];
> + return fbcon_registered_fb[con2fb_map[console]];
>  }
>  
>  static int logo_lines;
> @@ -516,7 +514,7 @@ static int do_fbcon_takeover(int show_logo)
>  {
>   int err, i;
>  
> - if (!num_registered_fb)
> + if (!fbcon_num_registered_fb)
>   return -ENODEV;
>  
>   if (!show_logo)
> @@ -822,7 +820,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
>  {
>   struct vc_data *vc = vc_cons[unit].d;
>   int oldidx = con2fb_map[unit];
> - struct fb_info *info = registered_fb[newidx];
> + struct fb_info *info = fbcon_registered_fb[newidx];
>   struct fb_info *oldinfo = NULL;
>   int found, err = 0, show_logo;
>  
> @@ -840,7 +838,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
>   }
>  
>   if (oldidx != -1)
> - oldinfo = registered_fb[oldidx];
> + oldinfo = fbcon_registered_fb[oldidx];
>  
>   found = search_fb_in_map(newidx);
>  
> @@ -932,13 +930,13 @@ static const char *fbcon_startup(void)
>*  If num_registered_fb is zero, this is a call for the dummy part.
>*  The frame buffer devices weren't initialized yet.
>*/
> - if (!num_registered_fb || info_idx == -1)
> + if (!fbcon_num_registered_fb || info_idx == -1)
>   return display_desc;
>   /*
>* Instead of blindly using registered_fb[0], we use info_idx, set by
>* fbcon_fb_registered();
>*/
> - info = registered_fb[info_idx];
> + info = fbcon_registered_fb[info_idx];
>   if (!info)
>   return NULL;
>   
> @@ -1153,9 +1151,9 @@ static void fbcon_release_all(void)
>   struct fb_info *info;
>   int i, j, mapped;
>  
> - for_each_registered_fb(i) {
> + fbcon_for_each_registered_fb(i) {
>   mapped = 0;
> - info = registered_fb[i];
> + info = fbcon_registered_fb[i];

Re: [PATCH 18/21] fbcon: untangle fbcon_exit

2022-02-04 Thread Sam Ravnborg
Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:49PM +0100, Daniel Vetter wrote:
> There's a bunch of confusions going on here:
> - The deferred fbcon setup notifier should only be cleaned up from
>   fb_console_exit(), to be symmetric with fb_console_init()
> - We also need to make sure we don't race with the work, which means
>   temporarily dropping the console lock (or we can deadlock)
> - That also means no point in clearing deferred_takeover, we are
>   unloading everything anyway.
> - Finally rename fbcon_exit to fbcon_release_all and move it, since
>   that's what's it doing when being called from consw->con_deinit
>   through fbcon_deinit.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Greg Kroah-Hartman 
> Cc: Claudio Suarez 
> Cc: Du Cheng 
> Cc: Tetsuo Handa 
> ---
>  drivers/video/fbdev/core/fbcon.c | 63 
>  1 file changed, 32 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index 5c14e24d14a1..22581952b4fd 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -185,7 +185,6 @@ static void fbcon_set_disp(struct fb_info *info, struct 
> fb_var_screeninfo *var,
>  int unit);
>  static void fbcon_modechanged(struct fb_info *info);
>  static void fbcon_set_all_vcs(struct fb_info *info);
> -static void fbcon_exit(void);
>  
>  static struct device *fbcon_device;
>  
> @@ -1149,6 +1148,27 @@ static void fbcon_free_font(struct fbcon_display *p, 
> bool freefont)
>  
>  static void set_vc_hi_font(struct vc_data *vc, bool set);
>  
> +static void fbcon_release_all(void)
> +{
> + struct fb_info *info;
> + int i, j, mapped;
> +
> + for_each_registered_fb(i) {
> + mapped = 0;
> + info = registered_fb[i];
> +
> + for (j = first_fb_vc; j <= last_fb_vc; j++) {
> + if (con2fb_map[j] == i) {
> + mapped = 1;
> + con2fb_map[j] = -1;
> + }
> + }
> +
> + if (mapped)
> + fbcon_release(info);
> + }
> +}
> +
>  static void fbcon_deinit(struct vc_data *vc)
>  {
>   struct fbcon_display *p = &fb_display[vc->vc_num];
> @@ -1188,7 +1208,7 @@ static void fbcon_deinit(struct vc_data *vc)
>   set_vc_hi_font(vc, false);
>  
>   if (!con_is_bound(&fb_con))
> - fbcon_exit();
> + fbcon_release_all();
>  
>   if (vc->vc_num == logo_shown)
>   logo_shown = FBCON_LOGO_CANSHOW;
> @@ -3316,34 +3336,6 @@ static void fbcon_start(void)
>  #endif
>  }
>  
> -static void fbcon_exit(void)
> -{
> - struct fb_info *info;
> - int i, j, mapped;
> -
> -#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> - if (deferred_takeover) {
> - dummycon_unregister_output_notifier(&fbcon_output_nb);
> - deferred_takeover = false;
> - }
> -#endif
> -
> - for_each_registered_fb(i) {
> - mapped = 0;
> - info = registered_fb[i];
> -
> - for (j = first_fb_vc; j <= last_fb_vc; j++) {
> - if (con2fb_map[j] == i) {
> - mapped = 1;
> - con2fb_map[j] = -1;
> - }
> - }
> -
> - if (mapped)
> - fbcon_release(info);
> - }
> -}
> -
>  void __init fb_console_init(void)
>  {
>   int i;
> @@ -3383,10 +3375,19 @@ static void __exit fbcon_deinit_device(void)
>  
>  void __exit fb_console_exit(void)
>  {
> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> + console_lock();
> + if (deferred_takeover)
> + dummycon_unregister_output_notifier(&fbcon_output_nb);
> + console_unlock();
> +
> + cancel_work_sync(&fbcon_deferred_takeover_work);
> +#endif
> +
>   console_lock();
>   fbcon_deinit_device();
>   device_destroy(fb_class, MKDEV(0, 0));
> - fbcon_exit();
> +
We loose the call to fbcon_release_all() here.
We have part of the old fbcon_exit() above, but miss the release parts.

Maybe I missed something obvious?

The rest looks fine.

Sam

>   do_unregister_con_driver(&fb_con);
>   console_unlock();
>  }
> -- 
> 2.33.0


Re: [PATCH 17/21] fbcon: Move more code into fbcon_release

2022-02-04 Thread Sam Ravnborg
On Mon, Jan 31, 2022 at 10:05:48PM +0100, Daniel Vetter wrote:
> con2fb_release_oldinfo() has a bunch more kfree() calls than
> fbcon_exit(), but since kfree() on NULL is harmless doing that in both
> places should be ok. This is also a bit more symmetric now again with
> fbcon_open also allocating the fbcon_ops structure.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Tetsuo Handa 
> Cc: Greg Kroah-Hartman 
> Cc: Du Cheng 
> Cc: Claudio Suarez 

Thanks, like I wrote earlier this makes sense.
Acked-by: Sam Ravnborg 


Re: [PATCH 16/21] fbcon: Move console_lock for register/unlink/unregister

2022-02-04 Thread Sam Ravnborg
Hi Daniel.

On Mon, Jan 31, 2022 at 10:05:47PM +0100, Daniel Vetter wrote:
> Ideally console_lock becomes an implementation detail of fbcon.c and
> doesn't show up anywhere in fbmem.c. We're still pretty far from that,
> but at least the register/unregister code is there now.
> 
> With this the do_fb_ioctl() handler is the only code in fbmem.c still
> calling console_lock().
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Thomas Zimmermann 
> Cc: Du Cheng 
> Cc: Claudio Suarez 
> Cc: Greg Kroah-Hartman 
> Cc: Tetsuo Handa 
> Cc: Matthew Wilcox 
> Cc: Sam Ravnborg 
> Cc: Zheyu Ma 
> Cc: Guenter Roeck 
> Cc: Alex Deucher 
> Cc: Zhen Lei 
> Cc: Xiyu Yang 

Like how lock_console is now almost local to fbcon.
Except the usage outside fbmem + fbcon taht is.

Acked-by: Sam Ravnborg 

> ---
>  drivers/video/fbdev/core/fbcon.c | 33 ++--
>  drivers/video/fbdev/core/fbmem.c | 23 ++
>  2 files changed, 29 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index 11b9f962af6f..e5e8aaf6f60d 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -2776,10 +2776,12 @@ void fbcon_fb_unbind(struct fb_info *info)
>   int i, new_idx = -1;
>   int idx = info->node;
>  
> - WARN_CONSOLE_UNLOCKED();
> + console_lock();
>  
> - if (!fbcon_has_console_bind)
> + if (!fbcon_has_console_bind) {
> + console_unlock();
>   return;
> + }
>  
>   for (i = first_fb_vc; i <= last_fb_vc; i++) {
>   if (con2fb_map[i] != idx &&
> @@ -2814,6 +2816,8 @@ void fbcon_fb_unbind(struct fb_info *info)
>   }
>   fbcon_unbind();
>   }
> +
> + console_unlock();
>  }
>  
>  /* called with console_lock held */
> @@ -2821,10 +2825,12 @@ void fbcon_fb_unregistered(struct fb_info *info)
>  {
>   int i, idx;
>  
> - WARN_CONSOLE_UNLOCKED();
> + console_lock();
>  
> - if (deferred_takeover)
> + if (deferred_takeover) {
> + console_unlock();
>   return;
> + }
>  
>   idx = info->node;
>   for (i = first_fb_vc; i <= last_fb_vc; i++) {
> @@ -2853,6 +2859,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
>  
>   if (!num_registered_fb)
>   do_unregister_con_driver(&fb_con);
> + console_unlock();
>  }
>  
>  void fbcon_remap_all(struct fb_info *info)
> @@ -2910,19 +2917,27 @@ static inline void fbcon_select_primary(struct 
> fb_info *info)
>  }
>  #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
>  
> +static bool lockless_register_fb;
> +module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 
> 0400);
> +MODULE_PARM_DESC(lockless_register_fb,
> + "Lockless framebuffer registration for debugging [default=off]");
> +
>  /* called with console_lock held */
>  int fbcon_fb_registered(struct fb_info *info)
>  {
>   int ret = 0, i, idx;
>  
> - WARN_CONSOLE_UNLOCKED();
> + if (!lockless_register_fb)
> + console_lock();
> + else
> + atomic_inc(&ignore_console_lock_warning);
>  
>   idx = info->node;
>   fbcon_select_primary(info);
>  
>   if (deferred_takeover) {
>   pr_info("fbcon: Deferring console take-over\n");
> - return 0;
> + goto out;
>   }
>  
>   if (info_idx == -1) {
> @@ -2942,6 +2957,12 @@ int fbcon_fb_registered(struct fb_info *info)
>   }
>   }
>  
> +out:
> + if (!lockless_register_fb)
> + console_unlock();
> + else
> + atomic_dec(&ignore_console_lock_warning);
> +
>   return ret;
>  }
>  
> diff --git a/drivers/video/fbdev/core/fbmem.c 
> b/drivers/video/fbdev/core/fbmem.c
> index fd51d12f2702..904ef1250677 100644
> --- a/drivers/video/fbdev/core/fbmem.c
> +++ b/drivers/video/fbdev/core/fbmem.c
> @@ -1573,14 +1573,9 @@ static void do_remove_conflicting_framebuffers(struct 
> apertures_struct *a,
>   }
>  }
>  
> -static bool lockless_register_fb;
> -module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 
> 0400);
> -MODULE_PARM_DESC(lockless_register_fb,
> - "Lockless framebuffer registration for debugging [default=off]");
> -
>  static int do_register_framebuffer(struct fb_info *fb_info)
>  {
> - int i, ret;
> + int i;
>   struct fb_videomode mode;
>  
>   if (fb_check_foreignness(fb_info))
> @@ -1649,17 +1644,7 @@ static int do_register_framebuffer(struct fb_info 
> *fb_info)
>   }
>  #endif
>  
> - if (!lockless_register_fb)
> - console_lock();
> - else
> - atomic_inc(&ignore_console_lock_warning);
> - ret = fbcon_fb_registered(fb_info);
> -
> - if (!lockless_register_fb)
> - console_unlock();
> - else
> - atomic_dec(&ignore_console_lock_warning);
> - return ret;
> + return fbcon_fb_registered(fb_info);
>  }
>  
>  st

Re: [PATCH 15/21] fbcon: Consistently protect deferred_takeover with console_lock()

2022-02-04 Thread Sam Ravnborg
On Mon, Jan 31, 2022 at 10:05:46PM +0100, Daniel Vetter wrote:
> This shouldn't be a problem in practice since until we've actually
> taken over the console there's nothing we've registered with the
> console/vt subsystem, so the exit/unbind path that check this can't
> do the wrong thing. But it's confusing, so fix it by moving it a tad
> later.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Du Cheng 
> Cc: Tetsuo Handa 
> Cc: Claudio Suarez 
> Cc: Thomas Zimmermann 

It had helped me if the commitlog was explicit that the
deferred_takeover falg is moved to the worker function to reset it as
late as possible.

With the commit log updated:
Acked-by: Sam Ravnborg 


> ---
>  drivers/video/fbdev/core/fbcon.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index 496bc5f2133e..11b9f962af6f 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -3247,6 +3247,9 @@ static void fbcon_register_existing_fbs(struct 
> work_struct *work)
>  
>   console_lock();
>  
> + deferred_takeover = false;
> + logo_shown = FBCON_LOGO_DONTSHOW;
> +
>   for_each_registered_fb(i)
>   fbcon_fb_registered(registered_fb[i]);
>  
> @@ -3264,8 +3267,6 @@ static int fbcon_output_notifier(struct notifier_block 
> *nb,
>   pr_info("fbcon: Taking over console\n");
>  
>   dummycon_unregister_output_notifier(&fbcon_output_nb);
> - deferred_takeover = false;
> - logo_shown = FBCON_LOGO_DONTSHOW;
>  
>   /* We may get called in atomic context */
>   schedule_work(&fbcon_deferred_takeover_work);
> -- 
> 2.33.0


Re: [PATCH 03/19] iosys-map: Add a few more helpers

2022-02-04 Thread Lucas De Marchi

On Fri, Feb 04, 2022 at 08:05:56PM +0100, Thomas Zimmermann wrote:

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

First the simplest ones:

- iosys_map_memset(): when abstracting system and I/O memory,
  just like the memcpy() use case, memset() also has dedicated
  functions to be called for using IO memory.
- iosys_map_memcpy_from(): we may need to copy data from I/O
  memory, not only to.

In certain situations it's useful to be able to read or write to an
offset that is calculated by having the memory layout given by a struct
declaration. Usually we are going to read/write a u8, u16, u32 or u64.

As a pre-requisite for the implementation, add iosys_map_memcpy_from()
to be the equivalent of iosys_map_memcpy_to(), but in the other
direction. Then add 2 pairs of macros:

- iosys_map_rd() / iosys_map_wr()
- iosys_map_rd_field() / iosys_map_wr_field()

The first pair takes the C-type and offset to read/write. The second
pair uses a struct describing the layout of the mapping in order to
calculate the offset and size being read/written.

We could use readb, readw, readl, readq and the write* counterparts,
however due to alignment issues this may not work on all architectures.
If alignment needs to be checked to call the right function, it's not
possible to decide at compile-time which function to call: so just leave
the decision to the memcpy function that will do exactly that.

Finally, in order to use the above macros with a map derived from
another, add another initializer: IOSYS_MAP_INIT_OFFSET().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
 include/linux/iosys-map.h | 154 +-
 1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index edd7fa3be9e9..96f8b61ac6fb 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -6,6 +6,7 @@
 #ifndef __IOSYS_MAP_H__
 #define __IOSYS_MAP_H__
+#include 
 #include 
 #include 
@@ -133,6 +134,45 @@ static inline void iosys_map_set_vaddr(struct iosys_map 
*map, void *vaddr)
map->is_iomem = false;
 }
+/**
+ * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
+ * @map_:  The dma-buf mapping structure to copy from
+ * @offset_:   Offset to add to the other mapping
+ *
+ * Initializes a new iosys_map struct based on another passed as argument. It
+ * does a shallow copy of the struct so it's possible to update the back 
storage
+ * without changing where the original map points to. It is the equivalent of
+ * doing:
+ *
+ * .. code-block: c
+ *
+ * iosys_map map = other_map;
+ * iosys_map_incr(&map, &offset);
+ *
+ * Example usage:
+ *
+ * .. code-block: c
+ *
+ * void foo(struct device *dev, struct iosys_map *base_map)
+ * {
+ * ...
+ * struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, 
FIELD_OFFSET);
+ * ...
+ * }
+ *
+ * The advantage of using the initializer over just increasing the offset with
+ * ``iosys_map_incr()`` like above is that the new map will always point to the
+ * right place of the buffer during  its scope. It reduces the risk of updating
+ * the wrong part of the buffer and having no compiler warning about that. If
+ * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can 
warn
+ * using a uninitialized variable.
+ */
+#define IOSYS_MAP_INIT_OFFSET(map_, offset_)   (struct iosys_map)  \
+   {   \
+   .vaddr = (map_)->vaddr + (offset_),  \
+   .is_iomem = (map_)->is_iomem,\
+   }


I already nak'ed this macro. This works because of the aliasing rules 
within the union and the fact that there are only plain pointers. But 
this is fragile. Do anything more complicated and it breaks. There's 
not even a test that would tell you that it failed.


Therefore, struct iosys_map should only be initialized by the code 
that creates the stored pointer.


I wonder if there is an alternative that is not fragile that allows us
to have a macro like that. In that thread I and Daniel continued
chatting and after my additional explanations he was convinced about
that.

I only came up with such a macro after doing the rest of the patches and
noticing a pattern that is hard to debug otherwise. I expanded the
explanation in the doc above this macro.

Maybe something like:

#define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({ \
struct iosys_map copy = *(map_);\
iosys_map_incr(©, offset_); \
copy;   \
})

Hopefully the compiler elides the additional copy, but I need to check.




However, you won't need the offset'ed iosys_m

Re: [PATCH 14/21] fbcon: use lock_fb_info in fbcon_open/release

2022-02-04 Thread Sam Ravnborg
On Mon, Jan 31, 2022 at 10:05:45PM +0100, Daniel Vetter wrote:
> Now we get to the real motiviation, because fbmem.c insists that
> that's the right lock for these.
> 
> Ofc fbcon.c has a lot more places where it probably should call
> lock_fb_info(). But looking at fbmem.c at least most of these seem to
> be protected by console_lock() too, which is probably what papers over
> any issues.
> 
> Note that this means we're shuffling around a bit the locking sections
> for some of the console takeover and unbind paths, but not all:
> - console binding/unbinding from the console layer never with
> lock_fb_info
> - unbind (as opposed to unlink) never bother with lock_fb_info
> 
> Also the real serialization against set_par and set_pan are still
> doing by wrapping the entire ioctl code in console_lock(). So this
> shuffling shouldn't be worse than what we had from a "can you trigger
> races?" pov, but it's at least clearer.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Claudio Suarez 
> Cc: Tetsuo Handa 
> Cc: Thomas Zimmermann 
> Cc: Greg Kroah-Hartman 
> Cc: Du Cheng 
> Cc: Sam Ravnborg 
> Cc: Matthew Wilcox 
> Cc: William Kucharski 
> Cc: Alex Deucher 
> Cc: Zheyu Ma 
> Cc: Zhen Lei 
> Cc: Xiyu Yang 

Well, the patch does what the commit log says.
Acked-by: Sam Ravnborg 


Re: [RFC PATCH 1/3] drm: Extract amdgpu_sa.c as a generic suballocation helper

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 19:29 schrieb Christian König:

Oh, that's on my TODO list for years!

Am 04.02.22 um 18:48 schrieb Maarten Lankhorst:

Suballocating a buffer object is something that is not driver
generic, and is useful for other drivers as well.

Signed-off-by: Maarten Lankhorst 
---
  drivers/gpu/drm/Makefile   |   4 +-
  drivers/gpu/drm/drm_suballoc.c | 424 +
  include/drm/drm_suballoc.h |  78 ++
  3 files changed, 505 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/drm_suballoc.c
  create mode 100644 include/drm/drm_suballoc.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8675c2af7ae1..b848bcf8790c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -57,7 +57,9 @@ drm_kms_helper-y := drm_bridge_connector.o 
drm_crtc_helper.o \

  drm_scdc_helper.o drm_gem_atomic_helper.o \
  drm_gem_framebuffer_helper.o \
  drm_atomic_state_helper.o drm_damage_helper.o \
-    drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
+    drm_format_helper.o drm_self_refresh_helper.o drm_rect.o \
+    drm_suballoc.o
+


I think we should put that into a separate module like we now do with 
other helpers as well.


Please. KMS helpers are now likely to be linked into the kernel binary. 
I've already spent time to reduce the size of the module.


Best regard
Thomas

--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


OpenPGP_signature
Description: OpenPGP digital signature


Re: [PATCH 13/21] fbcon: move more common code into fb_open()

2022-02-04 Thread Sam Ravnborg
On Mon, Jan 31, 2022 at 10:05:44PM +0100, Daniel Vetter wrote:
> No idea why con2fb_acquire_newinfo() initializes much less than
> fbcon_startup(), but so be it. From a quick look most of the
> un-initialized stuff should be fairly harmless, but who knows.
> 
> Signed-off-by: Daniel Vetter 
> Cc: Daniel Vetter 
> Cc: Greg Kroah-Hartman 
> Cc: Tetsuo Handa 
> Cc: Thomas Zimmermann 
> Cc: Claudio Suarez 
> Cc: Du Cheng 
> ---
>  drivers/video/fbdev/core/fbcon.c | 74 +---
>  1 file changed, 31 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/video/fbdev/core/fbcon.c 
> b/drivers/video/fbdev/core/fbcon.c
> index b83a5a77d8a8..5a3391ff038d 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -680,8 +680,18 @@ static int fbcon_invalid_charcount(struct fb_info *info, 
> unsigned charcount)
>  
>  #endif /* CONFIG_MISC_TILEBLITTING */
>  
> +static void fbcon_release(struct fb_info *info)
> +{
> + if (info->fbops->fb_release)
> + info->fbops->fb_release(info, 0);
> +
> + module_put(info->fbops->owner);
> +}
> +
>  static int fbcon_open(struct fb_info *info)
>  {
> + struct fbcon_ops *ops;
> +
>   if (!try_module_get(info->fbops->owner))
>   return -ENODEV;
>  
> @@ -691,19 +701,22 @@ static int fbcon_open(struct fb_info *info)
>   return -ENODEV;
>   }
>  
> - return 0;
> -}
> + ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> + if (!ops) {
> + fbcon_release(info);
> + return -ENOMEM;
> + }
>  
> -static void fbcon_release(struct fb_info *info)
> -{
> - if (info->fbops->fb_release)
> - info->fbops->fb_release(info, 0);
> + INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> + ops->info = info;
> + info->fbcon_par = ops;
> + ops->cur_blink_jiffies = HZ / 5;
>  
> - module_put(info->fbops->owner);
> + return 0;
>  }
>  
>  static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> -   int unit, int oldidx)
> +   int unit)
>  {
>   struct fbcon_ops *ops = NULL;
>   int err;
> @@ -712,27 +725,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, 
> struct fb_info *info,
>   if (err)
>   return err;
>  
> - if (!err) {
> - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> - if (!ops)
> - err = -ENOMEM;
> -
> - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> - }
> -
> - if (!err) {
> - ops->cur_blink_jiffies = HZ / 5;
> - ops->info = info;
> - info->fbcon_par = ops;
> -
> - if (vc)
> - set_blitting_type(vc, info);
> - }
> + ops = info->fbcon_par;
>  
> - if (err) {
> - con2fb_map[unit] = oldidx;
> - fbcon_release(info);
> - }
> + if (vc)
> + set_blitting_type(vc, info);
>  
>   return err;
>  }
> @@ -840,9 +836,11 @@ static int set_con2fb_map(int unit, int newidx, int user)
>  
>   found = search_fb_in_map(newidx);
>  
> - con2fb_map[unit] = newidx;
> - if (!err && !found)
> - err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
> + if (!err && !found) {
> + err = con2fb_acquire_newinfo(vc, info, unit);
> + if (!err)
> + con2fb_map[unit] = newidx;
> + }
This looks like an unintentional change of functionality as con2fb_map[unit] is
only assigned when we do a con2fb_acquire_newinfo().

Staring at the code I could not say it is wrong, but not nice to hide
the change in this patch.

Sam


>  
>   /*
>* If old fb is not mapped to any of the consoles,
> @@ -939,20 +937,10 @@ static const char *fbcon_startup(void)
>   if (fbcon_open(info))
>   return NULL;
>  
> - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> - if (!ops) {
> - fbcon_release(info);
> - return NULL;
> - }
> -
> - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> -
> + ops = info->fbcon_par;
>   ops->currcon = -1;
>   ops->graphics = 1;
>   ops->cur_rotate = -1;
> - ops->cur_blink_jiffies = HZ / 5;
> - ops->info = info;
> - info->fbcon_par = ops;
>  
>   p->con_rotate = initial_rotation;
>   if (p->con_rotate == -1)
> @@ -1022,7 +1010,7 @@ static void fbcon_init(struct vc_data *vc, int init)
>   return;
>  
>   if (!info->fbcon_par)
> - con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
> + con2fb_acquire_newinfo(vc, info, vc->vc_num);
>  
>   /* If we are not the first console on this
>  fb, copy the font from that console */
> -- 
> 2.33.0


[PATCH] drm/nouveau/backlight: Just set all backlight types as RAW

2022-02-04 Thread Lyude Paul
Currently we can get a warning on systems with eDP backlights like so:

  nv_backlight: invalid backlight type
  WARNING: CPU: 4 PID: 454 at drivers/video/backlight/backlight.c:420
backlight_device_register+0x226/0x250

This happens as a result of us not filling out props.type for the eDP
backlight, even though we do it for all other backlight types.

Since nothing in our driver uses anything but BACKLIGHT_RAW, let's take the
props\.type assignments out of the codepaths for individual backlight types
and just set it unconditionally to prevent this from happening again.

Signed-off-by: Lyude Paul 
Fixes: 6eca310e8924 ("drm/nouveau/kms/nv50-: Add basic DPCD backlight support 
for nouveau")
Cc:  # v5.15+
---
 drivers/gpu/drm/nouveau/nouveau_backlight.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c 
b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 6af12dc99d7f..daf9f87477ba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -101,7 +101,6 @@ nv40_backlight_init(struct nouveau_encoder *encoder,
if (!(nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
return -ENODEV;
 
-   props->type = BACKLIGHT_RAW;
props->max_brightness = 31;
*ops = &nv40_bl_ops;
return 0;
@@ -343,7 +342,6 @@ nv50_backlight_init(struct nouveau_backlight *bl,
else
*ops = &nva3_bl_ops;
 
-   props->type = BACKLIGHT_RAW;
props->max_brightness = 100;
 
return 0;
@@ -411,6 +409,7 @@ nouveau_backlight_init(struct drm_connector *connector)
goto fail_alloc;
}
 
+   props.type = BACKLIGHT_RAW;
bl->dev = backlight_device_register(backlight_name, connector->kdev,
nv_encoder, ops, &props);
if (IS_ERR(bl->dev)) {
-- 
2.34.1



Re: [PATCH v2 1/4] drm/format-helper: Add drm_fb_{xrgb8888,gray8}_to_mono_reversed()

2022-02-04 Thread Javier Martinez Canillas
Hello Thomas,

Thanks a lot for your feedback.

On 2/4/22 16:52, Thomas Zimmermann wrote:

[snip]

>> +static void drm_fb_gray8_to_mono_reversed_line(u8 *dst, const u8 *src, 
>> size_t pixels)
>> +{
>> +unsigned int xb, i;
>> +
>> +for (xb = 0; xb < pixels / 8; xb++) {
> 
> In practice, all mode widths are multiples of 8 because VGA mandated it. 
> So it's ok-ish to assume this here. You should probably at least print a 
> warning somewhere if (pixels % 8 != 0)
>

Agreed.
 
[snip]

>> + * DRM doesn't have native monochrome or grayscale support.
>> + * Such drivers can announce the commonly supported XR24 format to userspace
>> + * and use drm_fb_xrgb_to_gray8() to convert to grayscale and then this
>> + * helper function to convert to the native format.
>> + */
>> +void drm_fb_gray8_to_mono_reversed(void *dst, unsigned int dst_pitch, const 
>> void *src,
>> +   const struct drm_rect *clip)
> 
> There's a bug here. You want to pass in a drm_framebuffer as fourth 
> argument.
>
>> +{
>> +
>> +size_t height = drm_rect_height(clip);
>> +size_t width = drm_rect_width(clip);
>> +unsigned int y;
>> +const u8 *gray8 = src;
>> +u8 *mono = dst;
>> +
>> +if (!dst_pitch)
>> +dst_pitch = width;
> 
> The dst_pitch is given in bytes. You have to device by 8. Here would be 
> a good place to warn if (width % 8 != 0).
>

Ok.
 
>> +
>> +for (y = 0; y < height; y++) {
>> +drm_fb_gray8_to_mono_reversed_line(mono, gray8, dst_pitch);
>> +mono += (dst_pitch / 8);
> 
> The dst_pitch is already given in bytes.
>

Yes, I know but for reversed mono we want only 1/8 of the width since we
are converting from 8 bits per pixel greyscale to 1 bit per pixel mono.

Or am I misunderstanding what you meant ?

>> +gray8 += dst_pitch;
> 
> 'gray8 += fb->pitches[0]' would be correct.
>

Ok.
 
[snip]

>> + */
>> +void drm_fb_xrgb_to_mono_reversed(void *dst, unsigned int dst_pitch, 
>> const void *src,
>> +  const struct drm_framebuffer *fb,
>> +  const struct drm_rect *clip)
>> +{
>> +if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB))
>> +return;
>> +
>> +if (!dst_pitch)
>> +dst_pitch = drm_rect_width(clip);
>> +
>> +drm_fb_xrgb_to_gray8(dst, dst_pitch, src, fb, clip);
>> +drm_fb_gray8_to_mono_reversed(dst, dst_pitch, dst, fb, clip);
> 
> Converting from dst into dst can give incorrect results. At some point 
> we probably want to add restrict qualifiers to these pointers, to help 
> the compiler with optimizing.
> 
> A better approach here is to pull the per-line conversion from 
> drm_fb_xrgb_to_gray8() into a separate helper and implement a 
> line-by-line conversion here. something like this:
> 
>drm_fb_xrgb_to_mono_reversed()
>{
>  char *tmp = kmalloc(size of a single line of gray8)
> 
>  for (heigth) {
> drm_fb_xrgb_to_gray8_line(tmp, ..., src, ...);
> drm_fb_gray8_to_mono_reversed(dst, ..., tmp, ...);
> 
> src += fb->pitches[0]
> dst += dst_pitch;
>  }
> 
>  kfree(tmp);
>}
>

I see. Yes, that sounds a much better approach. I'll change it in v3.
 
Best regards,
-- 
Javier Martinez Canillas
Linux Engineering
Red Hat



Re: [PATCH 02/19] iosys-map: Add offset to iosys_map_memcpy_to()

2022-02-04 Thread Lucas De Marchi

On Fri, Feb 04, 2022 at 07:48:10PM +0100, Thomas Zimmermann wrote:

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

In certain situations it's useful to be able to write to an
offset of the mapping. Add a dst_offset to iosys_map_memcpy_to().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/drm_cache.c |  2 +-
 drivers/gpu/drm/drm_fb_helper.c |  2 +-
 include/linux/iosys-map.h   | 17 +
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 66597e411764..c3e6e615bf09 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -218,7 +218,7 @@ static void memcpy_fallback(struct iosys_map *dst,
if (!dst->is_iomem && !src->is_iomem) {
memcpy(dst->vaddr, src->vaddr, len);
} else if (!src->is_iomem) {
-   iosys_map_memcpy_to(dst, src->vaddr, len);
+   iosys_map_memcpy_to(dst, 0, src->vaddr, len);
} else if (!dst->is_iomem) {
memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
} else {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 238f815cb2a0..bf5cc9a42e5a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -385,7 +385,7 @@ static void drm_fb_helper_damage_blit_real(struct 
drm_fb_helper *fb_helper,
iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
for (y = clip->y1; y < clip->y2; y++) {
-   iosys_map_memcpy_to(dst, src, len);
+   iosys_map_memcpy_to(dst, 0, src, len);
iosys_map_incr(dst, fb->pitches[0]);
src += fb->pitches[0];
}
diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index f4186f91caa6..edd7fa3be9e9 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -220,22 +220,23 @@ static inline void iosys_map_clear(struct iosys_map *map)
 }
 /**
- * iosys_map_memcpy_to - Memcpy into iosys mapping
+ * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map


'iosys_map_memcpy_to'

With that fixed:

Reviewed-by: Thomas Zimmermann 


thanks, I noticed that, but looks like I squashed to the wrong patch.

Lucas De Marchi


Re: [PATCH 09/19] drm/i915/guc: Convert engine record to iosys_map

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

Use iosys_map to read fields from the dma_blob so access to IO and
system memory is abstracted away.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
  drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c  | 14 ++
  drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h  |  3 ++-
  .../gpu/drm/i915/gt/uc/intel_guc_submission.c   | 17 ++---
  3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 6311b9da87e4..1d21a2d457e0 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -698,18 +698,16 @@ void intel_guc_ads_reset(struct intel_guc *guc)
  
  u32 intel_guc_engine_usage_offset(struct intel_guc *guc)

  {
-   struct __guc_ads_blob *blob = guc->ads_blob;
-   u32 base = intel_guc_ggtt_offset(guc, guc->ads_vma);
-   u32 offset = base + ptr_offset(blob, engine_usage);
-
-   return offset;
+   return intel_guc_ggtt_offset(guc, guc->ads_vma) +
+   offsetof(struct __guc_ads_blob, engine_usage);
  }
  
-struct guc_engine_usage_record *intel_guc_engine_usage(struct intel_engine_cs *engine)

+struct iosys_map intel_guc_engine_usage_record_map(struct intel_engine_cs 
*engine)
  {
struct intel_guc *guc = &engine->gt->uc.guc;
-   struct __guc_ads_blob *blob = guc->ads_blob;
u8 guc_class = engine_class_to_guc_class(engine->class);
+   size_t offset = offsetof(struct __guc_ads_blob,
+
engine_usage.engines[guc_class][ilog2(engine->logical_mask)]);
  
-	return &blob->engine_usage.engines[guc_class][ilog2(engine->logical_mask)];

+   return IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);


Here's one of the few cases where you can legitimately make a copy of an 
iosys_map buffer and call iosys_map_incr() on it. Saves you the 
IOSYS_MAP_INIT_OFFSET().


Best regards
Thomas


  }
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
index e74c110facff..1c64f4d6ea21 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
@@ -7,6 +7,7 @@
  #define _INTEL_GUC_ADS_H_
  
  #include 

+#include 
  
  struct intel_guc;

  struct drm_printer;
@@ -18,7 +19,7 @@ void intel_guc_ads_init_late(struct intel_guc *guc);
  void intel_guc_ads_reset(struct intel_guc *guc);
  void intel_guc_ads_print_policy_info(struct intel_guc *guc,
 struct drm_printer *p);
-struct guc_engine_usage_record *intel_guc_engine_usage(struct intel_engine_cs 
*engine);
+struct iosys_map intel_guc_engine_usage_record_map(struct intel_engine_cs 
*engine);
  u32 intel_guc_engine_usage_offset(struct intel_guc *guc);
  
  #endif

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index b3a429a92c0d..6d34842f68b4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -1139,6 +1139,9 @@ __extend_last_switch(struct intel_guc *guc, u64 
*prev_start, u32 new_start)
*prev_start = ((u64)gt_stamp_hi << 32) | new_start;
  }
  
+#define record_read(map_, field_) \

+   iosys_map_rd_field(map_, struct guc_engine_usage_record, field_)
+
  /*
   * GuC updates shared memory and KMD reads it. Since this is not synchronized,
   * we run into a race where the value read is inconsistent. Sometimes the
@@ -1153,17 +1156,17 @@ __extend_last_switch(struct intel_guc *guc, u64 
*prev_start, u32 new_start)
  static void __get_engine_usage_record(struct intel_engine_cs *engine,
  u32 *last_in, u32 *id, u32 *total)
  {
-   struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
+   struct iosys_map rec_map = intel_guc_engine_usage_record_map(engine);
int i = 0;
  
  	do {

-   *last_in = READ_ONCE(rec->last_switch_in_stamp);
-   *id = READ_ONCE(rec->current_context_index);
-   *total = READ_ONCE(rec->total_runtime);
+   *last_in = record_read(&rec_map, last_switch_in_stamp);
+   *id = record_read(&rec_map, current_context_index);
+   *total = record_read(&rec_map, total_runtime);
  
-		if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&

-   READ_ONCE(rec->current_context_index) == *id &&
-   READ_ONCE(rec->total_runtime) == *total)
+   if (record_read(&rec_map, last_switch_in_stamp) == *last_in &&
+   record_read(&rec_map, current_context_index) == *id &&
+   record_read(&rec_map, total_runtime) == *total)
break;
} while (++i < 6);
  }


--
Thomas Zimmermann
Graphi

Re: [PATCH 07/19] drm/i915/guc: Convert golden context init to iosys_map

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

Now the map is saved during creation, so use it to initialize the
golden context, reading from shmem and writing to either system or IO
memory.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
  drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 25 +++---
  1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 3a0afce7564e..d32b407a2d25 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -473,18 +473,17 @@ static struct intel_engine_cs *find_engine_state(struct 
intel_gt *gt, u8 engine_
  
  static void guc_init_golden_context(struct intel_guc *guc)

  {
-   struct __guc_ads_blob *blob = guc->ads_blob;
struct intel_engine_cs *engine;
struct intel_gt *gt = guc_to_gt(guc);
+   struct iosys_map golden_context_map;
u32 addr_ggtt, offset;
u32 total_size = 0, alloc_size, real_size;
u8 engine_class, guc_class;
-   u8 *ptr;
  
  	if (!intel_uc_uses_guc_submission(>->uc))

return;
  
-	GEM_BUG_ON(!blob);

+   GEM_BUG_ON(iosys_map_is_null(&guc->ads_map));
  
  	/*

 * Go back and fill in the golden context data now that it is
@@ -492,15 +491,15 @@ static void guc_init_golden_context(struct intel_guc *guc)
 */
offset = guc_ads_golden_ctxt_offset(guc);
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
-   ptr = ((u8 *)blob) + offset;
+
+   golden_context_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);
  
  	for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) {

if (engine_class == OTHER_CLASS)
continue;
  
  		guc_class = engine_class_to_guc_class(engine_class);

-
-   if (!blob->system_info.engine_enabled_masks[guc_class])
+   if (!ads_blob_read(guc, 
system_info.engine_enabled_masks[guc_class]))
continue;
  
  		real_size = intel_engine_context_size(gt, engine_class);

@@ -511,18 +510,20 @@ static void guc_init_golden_context(struct intel_guc *guc)
if (!engine) {
drm_err(>->i915->drm, "No engine state recorded for class 
%d!\n",
engine_class);
-   blob->ads.eng_state_size[guc_class] = 0;
-   blob->ads.golden_context_lrca[guc_class] = 0;
+   ads_blob_write(guc, ads.eng_state_size[guc_class], 0);
+   ads_blob_write(guc, ads.golden_context_lrca[guc_class], 
0);
continue;
}
  
-		GEM_BUG_ON(blob->ads.eng_state_size[guc_class] !=

+   GEM_BUG_ON(ads_blob_read(guc, ads.eng_state_size[guc_class]) !=
   real_size - LRC_SKIP_SIZE);
-   GEM_BUG_ON(blob->ads.golden_context_lrca[guc_class] != 
addr_ggtt);
+   GEM_BUG_ON(ads_blob_read(guc, 
ads.golden_context_lrca[guc_class]) != addr_ggtt);
+
addr_ggtt += alloc_size;
  
-		shmem_read(engine->default_state, 0, ptr, real_size);

-   ptr += alloc_size;
+   shmem_read_to_iosys_map(engine->default_state, 0,
+   &golden_context_map, real_size);
+   iosys_map_incr(&golden_context_map, alloc_size);


Use an offset to index into iosys_map. Even if that means to add another 
parameter to shmem_read_to_iosys_map(). This will save you 
IOSYS_MAP_INIT_OFFSET() and iosys_map_incr().


Best regards
Thomas


}
  
  	GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);


--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


OpenPGP_signature
Description: OpenPGP digital signature


Re: [PATCH v2 2/4] drm/tiny: Add driver for Solomon SSD130X OLED displays

2022-02-04 Thread Javier Martinez Canillas
Hello Andy,

Thanks for your feedback.

On 2/4/22 15:26, Andy Shevchenko wrote:
> On Fri, Feb 04, 2022 at 02:43:45PM +0100, Javier Martinez Canillas wrote:
>> Add a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon OLED
>> controllers that can be programmed via an I2C interface. This is a port
>> of the ssd1307fb driver that already supports these devices.
>>
>> A Device Tree binding is not added because the DRM driver is compatible
>> with the existing binding for the ssd1307fb driver.
> 
> ...
> 
>> +/*
>> + * DRM driver for Solomon SSD130X OLED displays
>> + *
>> + * Copyright 2022 Red Hat Inc.
>> + *
>> + * Based on drivers/video/fbdev/ssd1307fb.c
>> + * Copyright 2012 Free Electrons
> 
>> + *
> 
> No need for this blank line.
>

Ok.
 
>> + */
> 
> ...
> 
>> +struct ssd130x_device {
>> +struct drm_device drm;
>> +struct drm_simple_display_pipe pipe;
>> +struct drm_display_mode mode;
>> +struct drm_connector connector;
> 
> 
>> +struct i2c_client *client;
> 
> Can we logically separate hw protocol vs hw interface from day 1, please?
> This will allow to add SPI support for this panel much easier.
> 
> Technically I would like to see here
> 
>   struct device *dev;
>
> and probably (I haven't looked into design)
> 
>   struct ssd130x_ops *ops;
> 
> or something alike.
>

Sure. I wanted to keep the driver simple, making the writes bus agnostic and
adding a level of indirection would make it more complex. But I agree that
it will also make easier to add more buses later. I will do that for v3.

[snip]

> 
>> +static inline int ssd130x_write_value(struct i2c_client *client, u8 value)
> 
> Not sure inline does anything useful here.
> Ditto for the rest similar cases.
>

Ok, I'll drop them.
 
> ...
> 
>> +static inline int ssd130x_write_cmd(struct i2c_client *client, int count,
>> +/* u8 cmd, u8 value, ... */...)
>> +{
>> +va_list ap;
>> +u8 value;
>> +int ret;
>> +
>> +va_start(ap, count);
> 
>> +while (count--) {
>> +value = va_arg(ap, int);
>> +ret = ssd130x_write_value(client, (u8)value);
>> +if (ret)
>> +goto out_end;
>> +}
> 
> I'm wondering if this can be written in a form
> 
>   do {
>   ...
>   } while (--count);
> 
> In this case it will give a hint that count can't be 0.
>

Sure, I don't have a strong preference. I will change it.

[snip]
 
>> +ssd130x->pwm = pwm_get(dev, NULL);
>> +if (IS_ERR(ssd130x->pwm)) {
>> +dev_err(dev, "Could not get PWM from device tree!\n");
> 
> "device tree" is a bit confusing here if I run this on ACPI.
> Maybe something like "firmware description"?
>

Indeed.
 
>> +return PTR_ERR(ssd130x->pwm);
>> +}
> 
> ...
> 
>> +/* Set initial contrast */
>> +ret = ssd130x_write_cmd(ssd130x->client, 2, SSD130X_CONTRAST, 
>> ssd130x->contrast);
> 
> Creating a local variable for client allows to:
> - make lines shorter and might even be less LOCs
> - allow to convert struct device to client in one place
>   (as per my above comment)
> 
> Ditto for other similar cases.
>

Ok.
 
[snip]

>> +/* Switch to horizontal addressing mode */
>> +ret = ssd130x_write_cmd(ssd130x->client, 2, SSD130X_SET_ADDRESS_MODE,
>> +SSD130X_SET_ADDRESS_MODE_HORIZONTAL);
>> +if (ret < 0)
>> +return ret;
>> +
>> +return 0;
> 
> Can it be
> 
>   return ssd130x_write_cmd(...);
> 
> ?
> 
> ...
>

Yes.

>> +unsigned int line_length = DIV_ROUND_UP(width, 8);
>> +unsigned int pages = DIV_ROUND_UP(height, 8);
> 
> For power of two there are more efficient roundup()/rounddown()
> (or with _ in the names, I don't remember by heart).
>

Oh, I didn't know about round_{up,down}(). Thanks a lot for the pointer.

> ...
> 
>> +for (k = 0; k < m; k++) {
> 
>> +u8 byte = buf[(8 * i + k) * line_length +
>> +   j / 8];
> 
> One line?
>

Yes.

>> +u8 bit = (byte >> (j % 8)) & 1;
>> +
>> +data |= bit << k;
>> +}
> 
> ...
> 
>> +static int ssd130x_display_pipe_mode_valid(struct drm_simple_display_pipe 
>> *pipe,
>> +   const struct drm_display_mode *mode)
>> +{
>> +struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
>> +
>> +if (mode->hdisplay != ssd130x->mode.hdisplay &&
>> +mode->vdisplay != ssd130x->mode.vdisplay)
>> +return MODE_ONE_SIZE;
> 
>> +else if (mode->hdisplay != ssd130x->mode.hdisplay)
>> +return MODE_ONE_WIDTH;
>> +else if (mode->vdisplay != ssd130x->mode.vdisplay)
>> +return MODE_ONE_HEIGHT;
> 
> 'else' in both cases is redundant.
>

Indeed.
 
>> +return MODE_OK;
>> +}
> 
> ...
> 
>> +poweroff:
> 
> out_power_off: ?
>

Ok.
 
> ...
> 
>> +if (!fb)
>> +   

Re: [PATCH 04/19] drm/i915/gt: Add helper for shmem copy to iosys_map

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

Add a variant of shmem_read() that takes a iosys_map pointer rather
than a plain pointer as argument. It's mostly a copy __shmem_rw() but
adapting the api and removing the write support since there's currently
only need to use iosys_map as destination.

Reworking __shmem_rw() to share the implementation was tempting, but
finding a good balance between reuse and clarity pushed towards a little
code duplication. Since the function is small, just add the similar
function with a copy/paste/adapt approach.

Cc: Matt Roper 
Cc: Joonas Lahtinen 
Cc: Tvrtko Ursulin 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: Matthew Auld 
Cc: Thomas Hellström 
Cc: Maarten Lankhorst 
Signed-off-by: Lucas De Marchi 
---
  drivers/gpu/drm/i915/gt/shmem_utils.c | 33 +++
  drivers/gpu/drm/i915/gt/shmem_utils.h |  3 +++
  2 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c 
b/drivers/gpu/drm/i915/gt/shmem_utils.c
index 0683b27a3890..764adefdb4be 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.c
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
@@ -3,6 +3,7 @@
   * Copyright © 2020 Intel Corporation
   */
  
+#include 

  #include 
  #include 
  #include 
@@ -123,6 +124,38 @@ static int __shmem_rw(struct file *file, loff_t off,
return 0;
  }
  


Here's a good example of how to avoid iosys_map_incr() and use the 
memcpy offset:



+int shmem_read_to_iosys_map(struct file *file, loff_t off,
+   struct iosys_map *map, size_t len)
+{
+   struct iosys_map map_iter = *map;


Rather replace map_iter with something like

  unsigned long map_off = 0;


+   unsigned long pfn;
+
+   for (pfn = off >> PAGE_SHIFT; len; pfn++) {
+   unsigned int this =
+   min_t(size_t, PAGE_SIZE - offset_in_page(off), len);
+   struct page *page;
+   void *vaddr;
+
+   page = shmem_read_mapping_page_gfp(file->f_mapping, pfn,
+  GFP_KERNEL);
+   if (IS_ERR(page))
+   return PTR_ERR(page);
+
+   vaddr = kmap(page);
+   iosys_map_memcpy_to(&map_iter, 0, vaddr + offset_in_page(off),
+   this);


Use map_off to index into map directly.


+   mark_page_accessed(page);
+   kunmap(page);
+   put_page(page);
+
+   len -= this;
+   iosys_map_incr(&map_iter, this);


Raplace iosys_map_incr() with map_off += this;


+   off = 0;


Maybe off += this ?

I think this pattern should be applied to all similar code. As you 
already noted, iosys_map_incr() is problematic.


Best regards
Thomas


+   }
+
+   return 0;
+}
+
  int shmem_read(struct file *file, loff_t off, void *dst, size_t len)
  {
return __shmem_rw(file, off, dst, len, false);
diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.h 
b/drivers/gpu/drm/i915/gt/shmem_utils.h
index c1669170c351..e1784999faee 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.h
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.h
@@ -8,6 +8,7 @@
  
  #include 
  
+struct iosys_map;

  struct drm_i915_gem_object;
  struct file;
  
@@ -17,6 +18,8 @@ struct file *shmem_create_from_object(struct drm_i915_gem_object *obj);

  void *shmem_pin_map(struct file *file);
  void shmem_unpin_map(struct file *file, void *ptr);
  
+int shmem_read_to_iosys_map(struct file *file, loff_t off,

+   struct iosys_map *map, size_t len);
  int shmem_read(struct file *file, loff_t off, void *dst, size_t len);
  int shmem_write(struct file *file, loff_t off, void *src, size_t len);
  


--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


OpenPGP_signature
Description: OpenPGP digital signature


Re: [PATCH 03/19] iosys-map: Add a few more helpers

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

First the simplest ones:

- iosys_map_memset(): when abstracting system and I/O memory,
  just like the memcpy() use case, memset() also has dedicated
  functions to be called for using IO memory.
- iosys_map_memcpy_from(): we may need to copy data from I/O
  memory, not only to.

In certain situations it's useful to be able to read or write to an
offset that is calculated by having the memory layout given by a struct
declaration. Usually we are going to read/write a u8, u16, u32 or u64.

As a pre-requisite for the implementation, add iosys_map_memcpy_from()
to be the equivalent of iosys_map_memcpy_to(), but in the other
direction. Then add 2 pairs of macros:

- iosys_map_rd() / iosys_map_wr()
- iosys_map_rd_field() / iosys_map_wr_field()

The first pair takes the C-type and offset to read/write. The second
pair uses a struct describing the layout of the mapping in order to
calculate the offset and size being read/written.

We could use readb, readw, readl, readq and the write* counterparts,
however due to alignment issues this may not work on all architectures.
If alignment needs to be checked to call the right function, it's not
possible to decide at compile-time which function to call: so just leave
the decision to the memcpy function that will do exactly that.

Finally, in order to use the above macros with a map derived from
another, add another initializer: IOSYS_MAP_INIT_OFFSET().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
  include/linux/iosys-map.h | 154 +-
  1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index edd7fa3be9e9..96f8b61ac6fb 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -6,6 +6,7 @@
  #ifndef __IOSYS_MAP_H__
  #define __IOSYS_MAP_H__
  
+#include 

  #include 
  #include 
  
@@ -133,6 +134,45 @@ static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr)

map->is_iomem = false;
  }
  
+/**

+ * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
+ * @map_:  The dma-buf mapping structure to copy from
+ * @offset_:   Offset to add to the other mapping
+ *
+ * Initializes a new iosys_map struct based on another passed as argument. It
+ * does a shallow copy of the struct so it's possible to update the back 
storage
+ * without changing where the original map points to. It is the equivalent of
+ * doing:
+ *
+ * .. code-block: c
+ *
+ * iosys_map map = other_map;
+ * iosys_map_incr(&map, &offset);
+ *
+ * Example usage:
+ *
+ * .. code-block: c
+ *
+ * void foo(struct device *dev, struct iosys_map *base_map)
+ * {
+ * ...
+ * struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, 
FIELD_OFFSET);
+ * ...
+ * }
+ *
+ * The advantage of using the initializer over just increasing the offset with
+ * ``iosys_map_incr()`` like above is that the new map will always point to the
+ * right place of the buffer during  its scope. It reduces the risk of updating
+ * the wrong part of the buffer and having no compiler warning about that. If
+ * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can 
warn
+ * using a uninitialized variable.
+ */
+#define IOSYS_MAP_INIT_OFFSET(map_, offset_)   (struct iosys_map)  \
+   {   \
+   .vaddr = (map_)->vaddr + (offset_),  \
+   .is_iomem = (map_)->is_iomem,\
+   }


I already nak'ed this macro. This works because of the aliasing rules 
within the union and the fact that there are only plain pointers. But 
this is fragile. Do anything more complicated and it breaks. There's not 
even a test that would tell you that it failed.


Therefore, struct iosys_map should only be initialized by the code that 
creates the stored pointer.


However, you won't need the offset'ed iosys_map because the 
memcpy_to/from helpers now have the offset parameter.





+
  /**
   * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address 
in I/O memory
   * @map:  The iosys_map structure
@@ -220,7 +260,7 @@ static inline void iosys_map_clear(struct iosys_map *map)
  }
  
  /**

- * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map
+ * iosys_map_memcpy_to - Memcpy into iosys_map


That's the fix for the other patch. :)


   * @dst:  The iosys_map structure
   * @dst_offset:   The offset from which to copy
   * @src:  The source buffer
@@ -239,6 +279,26 @@ static inline void iosys_map_memcpy_to(struct iosys_map 
*dst, size_t dst_offset,
memcpy(dst->vaddr + dst_offset, src, len);
  }
  
+/**

+ * 

Re: [PATCH v3 2/2] drm/i915/uapi: Add query for hwconfig table

2022-02-04 Thread John Harrison

On 2/4/2022 01:55, Daniel Vetter wrote:

On Wed, Jan 19, 2022 at 9:35 PM  wrote:

From: Rodrigo Vivi 

GuC contains a consolidated table with a bunch of information about the
current device.

Previously, this information was spread and hardcoded to all the components
including GuC, i915 and various UMDs. The goal here is to consolidate
the data into GuC in a way that all interested components can grab the
very latest and synchronized information using a simple query.

As per most of the other queries, this one can be called twice.
Once with item.length=0 to determine the exact buffer size, then
allocate the user memory and call it again for to retrieve the
table data. For example:
   struct drm_i915_query_item item = {
 .query_id = DRM_I915_QUERY_HWCONCFIG_TABLE;
   };
   query.items_ptr = (int64_t) &item;
   query.num_items = 1;

   ioctl(fd, DRM_IOCTL_I915_QUERY, query, sizeof(query));

   if (item.length <= 0)
 return -ENOENT;

   data = malloc(item.length);
   item.data_ptr = (int64_t) &data;
   ioctl(fd, DRM_IOCTL_I915_QUERY, query, sizeof(query));

   // Parse the data as appropriate...

The returned array is a simple and flexible KLV (Key/Length/Value)
formatted table. For example, it could be just:
   enum device_attr {
  ATTR_SOME_VALUE = 0,
  ATTR_SOME_MASK  = 1,
   };

   static const u32 hwconfig[] = {
   ATTR_SOME_VALUE,
   1, // Value Length in DWords
   8, // Value

   ATTR_SOME_MASK,
   3,
   0x00, 0x, 0xFF00,
   };

The attribute ids are defined in a hardware spec.

Cc: Tvrtko Ursulin 
Cc: Kenneth Graunke 
Cc: Michal Wajdeczko 
Cc: Slawomir Milczarek 
Signed-off-by: Rodrigo Vivi 
Signed-off-by: John Harrison 
Reviewed-by: Matthew Brost 
---
  drivers/gpu/drm/i915/i915_query.c | 23 +++
  include/uapi/drm/i915_drm.h   |  1 +
  2 files changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_query.c 
b/drivers/gpu/drm/i915/i915_query.c
index 2dfbc22857a3..609e64d5f395 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -479,12 +479,35 @@ static int query_memregion_info(struct drm_i915_private 
*i915,
 return total_length;
  }

+static int query_hwconfig_table(struct drm_i915_private *i915,
+   struct drm_i915_query_item *query_item)
+{
+   struct intel_gt *gt = to_gt(i915);
+   struct intel_guc_hwconfig *hwconfig = >->uc.guc.hwconfig;
+
+   if (!hwconfig->size || !hwconfig->ptr)
+   return -ENODEV;
+
+   if (query_item->length == 0)
+   return hwconfig->size;
+
+   if (query_item->length < hwconfig->size)
+   return -EINVAL;
+
+   if (copy_to_user(u64_to_user_ptr(query_item->data_ptr),
+hwconfig->ptr, hwconfig->size))
+   return -EFAULT;
+
+   return hwconfig->size;
+}
+
  static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv,
 struct drm_i915_query_item 
*query_item) = {
 query_topology_info,
 query_engine_info,
 query_perf_config,
 query_memregion_info,
+   query_hwconfig_table,
  };

  int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file 
*file)
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 914ebd9290e5..132515199f27 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -2685,6 +2685,7 @@ struct drm_i915_query_item {
  #define DRM_I915_QUERY_ENGINE_INFO 2
  #define DRM_I915_QUERY_PERF_CONFIG  3
  #define DRM_I915_QUERY_MEMORY_REGIONS   4
+#define DRM_I915_QUERY_HWCONFIG_TABLE   5
  /* Must be kept compact -- no holes and well documented */

New uapi needs kerneldoc in the uapi header, and please fill in any
gaps you have (i.e. if the query uapi this is built on top of isn't
fully documented yet).

Also this holds across the board, so please keep in mind in patch review.
-Daniel

There is no extra documentation to add.

The query interface itself is already documented. This new query does 
not have any kernel defined data structures associated with it. There is 
just 'struct drm_i915_query_item' with a length and a pointer, all of 
which are fully documented.


John.



Re: [PATCH 02/19] iosys-map: Add offset to iosys_map_memcpy_to()

2022-02-04 Thread Thomas Zimmermann

Hi

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

In certain situations it's useful to be able to write to an
offset of the mapping. Add a dst_offset to iosys_map_memcpy_to().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
  drivers/gpu/drm/drm_cache.c |  2 +-
  drivers/gpu/drm/drm_fb_helper.c |  2 +-
  include/linux/iosys-map.h   | 17 +
  3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 66597e411764..c3e6e615bf09 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -218,7 +218,7 @@ static void memcpy_fallback(struct iosys_map *dst,
if (!dst->is_iomem && !src->is_iomem) {
memcpy(dst->vaddr, src->vaddr, len);
} else if (!src->is_iomem) {
-   iosys_map_memcpy_to(dst, src->vaddr, len);
+   iosys_map_memcpy_to(dst, 0, src->vaddr, len);
} else if (!dst->is_iomem) {
memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
} else {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 238f815cb2a0..bf5cc9a42e5a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -385,7 +385,7 @@ static void drm_fb_helper_damage_blit_real(struct 
drm_fb_helper *fb_helper,
iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
  
  	for (y = clip->y1; y < clip->y2; y++) {

-   iosys_map_memcpy_to(dst, src, len);
+   iosys_map_memcpy_to(dst, 0, src, len);
iosys_map_incr(dst, fb->pitches[0]);
src += fb->pitches[0];
}
diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index f4186f91caa6..edd7fa3be9e9 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -220,22 +220,23 @@ static inline void iosys_map_clear(struct iosys_map *map)
  }
  
  /**

- * iosys_map_memcpy_to - Memcpy into iosys mapping
+ * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map


'iosys_map_memcpy_to'

With that fixed:

Reviewed-by: Thomas Zimmermann 

Best regards
Thomas


   * @dst:  The iosys_map structure
+ * @dst_offset:The offset from which to copy
   * @src:  The source buffer
   * @len:  The number of byte in src
   *
- * Copies data into a iosys mapping. The source buffer is in system
- * memory. Depending on the buffer's location, the helper picks the correct
- * method of accessing the memory.
+ * Copies data into a iosys_map with an offset. The source buffer is in
+ * system memory. Depending on the buffer's location, the helper picks the
+ * correct method of accessing the memory.
   */
-static inline void iosys_map_memcpy_to(struct iosys_map *dst, const void *src,
-  size_t len)
+static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t 
dst_offset,
+  const void *src, size_t len)
  {
if (dst->is_iomem)
-   memcpy_toio(dst->vaddr_iomem, src, len);
+   memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
else
-   memcpy(dst->vaddr, src, len);
+   memcpy(dst->vaddr + dst_offset, src, len);
  }
  
  /**


--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


OpenPGP_signature
Description: OpenPGP digital signature


[PATCH v3 3/3] drm/msm/dp: enable widebus feature for display port

2022-02-04 Thread Kuogee Hsieh
Widebus feature will transmit two pixel data per pixel clock to interface.
This feature now is required to be enabled to easy migrant to higher
resolution applications in future. However since some legacy chipsets
does not support this feature, this feature is enabled base on chip's
hardware revision.

changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches
-- enable widebus feature base on chip hardware revision

Signed-off-by: Kuogee Hsieh 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  4 +++-
 drivers/gpu/drm/msm/dp/dp_catalog.c | 36 +++--
 drivers/gpu/drm/msm/dp/dp_catalog.h |  3 ++-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 13 +++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|  1 +
 drivers/gpu/drm/msm/dp/dp_display.c | 30 
 drivers/gpu/drm/msm/dp/dp_display.h |  2 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  4 ++--
 drivers/gpu/drm/msm/dp/dp_panel.h   |  2 +-
 drivers/gpu/drm/msm/msm_drv.h   |  6 +
 10 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0c22839..b2d23c2 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2167,8 +2167,10 @@ int dpu_encoder_setup(struct drm_device *dev, struct 
drm_encoder *enc,
timer_setup(&dpu_enc->vsync_event_timer,
dpu_encoder_vsync_event_handler,
0);
-   else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS)
+   else if (disp_info->intf_type == DRM_MODE_ENCODER_TMDS) {
dpu_enc->dp = priv->dp[disp_info->h_tile_instance[0]];
+   dpu_enc->wide_bus_en = msm_dp_wide_bus_enable(dpu_enc->dp);
+   }
 
INIT_DELAYED_WORK(&dpu_enc->delayed_off_work,
dpu_encoder_off_work);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 64f0b26..99d087e 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -483,6 +483,27 @@ int dp_catalog_ctrl_set_pattern_state_bit(struct 
dp_catalog *dp_catalog,
 }
 
 /**
+ * dp_catalog_hw_revision() - retrieve DP hw revision
+ *
+ * @dp_catalog: DP catalog structure
+ *
+ * return: u32
+ *
+ * This function return the DP controller hw revision
+ *
+ */
+u32 dp_catalog_hw_revision(struct dp_catalog *dp_catalog)
+{
+   u32 revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   revision = dp_read_ahb(catalog, REG_DP_HW_VERSION);
+
+   return revision;
+}
+
+/**
  * dp_catalog_ctrl_reset() - reset DP controller
  *
  * @dp_catalog: DP catalog structure
@@ -739,10 +760,11 @@ u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog 
*dp_catalog)
 }
 
 /* panel related catalog functions */
-int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
+int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog, bool 
wide_bus_en)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
+   u32 reg;
 
dp_write_link(catalog, REG_DP_TOTAL_HOR_VER,
dp_catalog->total);
@@ -751,7 +773,17 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY,
dp_catalog->width_blanking);
dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
-   dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0);
+
+   reg = dp_read_p0(catalog, MMSS_DP_INTF_CONFIG);
+
+   if (wide_bus_en)
+   reg |= BIT(4);  /* DATABUS_WIDEN */
+   else
+   reg &= ~BIT(4);
+
+   DRM_DEBUG_DP("wide_bus_en=%d reg=%x\n", wide_bus_en, reg);
+
+   dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, reg);
return 0;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 7dea101..a3a0129 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -95,6 +95,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog, u32 cc, u32 tb);
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
u32 stream_rate_khz, bool fixed_nvid);
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 
pattern);
+u32 dp_catalog_hw_revision(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
 bool dp_catalog_ctrl_ma

[PATCH v3 2/3] drm/msm/dp: revise timing engine programming to support compression (DSC)

2022-02-04 Thread Kuogee Hsieh
Divides horizontal width by 3 at timing engine of interface. There are
major part of  compression (DSC) programming have to be done at DSC
controller which is not covered by this patch.

Signed-off-by: Kuogee Hsieh 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 22 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h |  3 +++
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 35d4aaa..ee7ca34 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -128,7 +128,7 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
 * video timing. It is recommended to enable it for all cases, except
 * if compression is enabled in 1 pixel per clock mode
 */
-   if (p->wide_bus_en)
+   if (!p->compression_en || p->wide_bus_en)
intf_cfg2 |= BIT(4);
 
if (p->wide_bus_en)
@@ -150,10 +150,16 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
 */
data_width = p->width;
 
-   if (!dp_intf && p->wide_bus_en)
+   if (p->compression_en) {
+   data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
+
+   if (p->wide_bus_en)
+   data_width >>= 1;
+   } else if (!dp_intf && p->wide_bus_en) {
data_width = p->width >> 1;
-   else
+   } else {
data_width = p->width;
+   }
 
hsync_data_start_x = hsync_start_x;
hsync_data_end_x =  hsync_start_x + data_width - 1;
@@ -178,8 +184,16 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
 
active_hctl = (active_h_end << 16) | active_h_start;
 
-   if (dp_intf)
+   if (dp_intf) {
display_hctl = active_hctl;
+   if (p->compression_en) {
+   active_data_hctl = (hsync_start_x +
+   p->extra_dto_cycles) << 16;
+   active_data_hctl += hsync_start_x;
+
+   display_data_hctl = active_data_hctl;
+   }
+   }
 
den_polarity = 0;
if (ctx->cap->type == INTF_HDMI) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
index e4a518a..8fc71ce 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
@@ -32,6 +32,9 @@ struct intf_timing_params {
u32 hsync_skew;
 
bool wide_bus_en;
+   bool compression_en;
+   u32 extra_dto_cycles;   /* for DP only */
+   u32 dce_bytes_per_line;
 };
 
 struct intf_prog_fetch {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v3 1/3] drm/msm/dp: revise timing engine programming to support widebus feature

2022-02-04 Thread Kuogee Hsieh
Widebus feature will transmit two pixel data per pixel clock to interface.
Timing engine provides driving force for this purpose. This patch base
on HPG (Hardware Programming Guide) to revise timing engine register
setting to accommodate both widebus and non widebus application. Also
horizontal width parameters need to be reduced by half since two pixel
data are clocked out per pixel clock when widebus feature enabled.
In addition, revised timing engine function is an generic function and
intend to be shared by all platforms to reduce maintenance efforts.

Changes in v2:
-- remove compression related code from timing
-- remove op_info from  struct msm_drm_private
-- remove unnecessary wide_bus_en variables
-- pass wide_bus_en into timing configuration by struct msm_dp

Changes in v3:
-- split patch into 3 patches

Signed-off-by: Kuogee Hsieh 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 10 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h|  2 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c| 99 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h|  2 +
 5 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 0d315b4..0c22839 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -208,6 +208,8 @@ struct dpu_encoder_virt {
 
u32 idle_timeout;
 
+   bool wide_bus_en;
+
struct msm_dp *dp;
 };
 
@@ -217,6 +219,14 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
 };
 
+
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc)
+{
+   struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+   return dpu_enc->wide_bus_en;
+}
+
 static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned 
bpc)
 {
struct dpu_hw_dither_cfg dither_cfg = { 0 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 99a5d73..893d74d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -168,4 +168,6 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_frame_count(struct drm_encoder *drm_enc);
 
+bool dpu_encoder_is_widebus_enabled(struct drm_encoder *drm_enc);
+
 #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 185379b..3d6c914 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -110,6 +110,20 @@ static void drm_mode_to_intf_timing_params(
timing->v_back_porch += timing->v_front_porch;
timing->v_front_porch = 0;
}
+
+   timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent);
+
+   /*
+* for DP, divide the horizonal parameters by 2 when
+* widebus is enabled
+*/
+   if (timing->wide_bus_en) {
+   timing->width = timing->width >> 1;
+   timing->xres = timing->xres >> 1;
+   timing->h_back_porch = timing->h_back_porch >> 1;
+   timing->h_front_porch = timing->h_front_porch >> 1;
+   timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+   }
 }
 
 static u32 get_horizontal_total(const struct intf_timing_params *timing)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 116e2b5..35d4aaa 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -33,6 +33,7 @@
 #define INTF_TP_COLOR1  0x05C
 #define INTF_CONFIG20x060
 #define INTF_DISPLAY_DATA_HCTL  0x064
+#define INTF_ACTIVE_DATA_HCTL   0x068
 #define INTF_FRAME_LINE_COUNT_EN0x0A8
 #define INTF_FRAME_COUNT0x0AC
 #define   INTF_LINE_COUNT   0x0B0
@@ -90,68 +91,95 @@ static void dpu_hw_intf_setup_timing_engine(struct 
dpu_hw_intf *ctx,
u32 hsync_period, vsync_period;
u32 display_v_start, display_v_end;
u32 hsync_start_x, hsync_end_x;
+   u32 hsync_data_start_x, hsync_data_end_x;
u32 active_h_start, active_h_end;
u32 active_v_start, active_v_end;
u32 active_hctl, display_hctl, hsync_ctl;
u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
u32 panel_format;
-   u32 intf_cfg, intf_cfg2 = 0, display_data_hctl = 0;
+   u32 intf_cfg, intf_cfg2 = 0;
+   u32 display_data_hctl = 0, active_data_hctl = 0;
+   u32 data_width;
+   bool dp_intf = false;
 
/* read interface_cfg */
intf_cfg = DPU_REG_READ(c, INTF_CO

[PATCH v3 0/3] enable widebus feature base on chip hardware revision

2022-02-04 Thread Kuogee Hsieh
split into 3 patches
1) widebus timing engine programming
2) dsc timing engine
3) enable widebus feature base on chip hardware revision


Kuogee Hsieh (3):
  drm/msm/dp:  revise timing engine programming to support widebus
feature
  drm/msm/dp: revise timing engine programming to support compression
(DSC)
  drm/msm/dp: enable widebus feature for display port

 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  14 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h|   2 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  14 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c| 107 +++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h|   5 +
 drivers/gpu/drm/msm/dp/dp_catalog.c|  36 ++-
 drivers/gpu/drm/msm/dp/dp_catalog.h|   3 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  13 ++-
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   1 +
 drivers/gpu/drm/msm/dp/dp_display.c|  30 ++
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_panel.c  |   4 +-
 drivers/gpu/drm/msm/dp/dp_panel.h  |   2 +-
 drivers/gpu/drm/msm/msm_drv.h  |   6 ++
 14 files changed, 197 insertions(+), 42 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [PATCH 02/19] iosys-map: Add offset to iosys_map_memcpy_to()

2022-02-04 Thread Christian König

Am 04.02.22 um 18:44 schrieb Lucas De Marchi:

In certain situations it's useful to be able to write to an
offset of the mapping. Add a dst_offset to iosys_map_memcpy_to().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 


Reviewed-by: Christian König 


---
  drivers/gpu/drm/drm_cache.c |  2 +-
  drivers/gpu/drm/drm_fb_helper.c |  2 +-
  include/linux/iosys-map.h   | 17 +
  3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 66597e411764..c3e6e615bf09 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -218,7 +218,7 @@ static void memcpy_fallback(struct iosys_map *dst,
if (!dst->is_iomem && !src->is_iomem) {
memcpy(dst->vaddr, src->vaddr, len);
} else if (!src->is_iomem) {
-   iosys_map_memcpy_to(dst, src->vaddr, len);
+   iosys_map_memcpy_to(dst, 0, src->vaddr, len);
} else if (!dst->is_iomem) {
memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
} else {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 238f815cb2a0..bf5cc9a42e5a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -385,7 +385,7 @@ static void drm_fb_helper_damage_blit_real(struct 
drm_fb_helper *fb_helper,
iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
  
  	for (y = clip->y1; y < clip->y2; y++) {

-   iosys_map_memcpy_to(dst, src, len);
+   iosys_map_memcpy_to(dst, 0, src, len);
iosys_map_incr(dst, fb->pitches[0]);
src += fb->pitches[0];
}
diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index f4186f91caa6..edd7fa3be9e9 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -220,22 +220,23 @@ static inline void iosys_map_clear(struct iosys_map *map)
  }
  
  /**

- * iosys_map_memcpy_to - Memcpy into iosys mapping
+ * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map
   * @dst:  The iosys_map structure
+ * @dst_offset:The offset from which to copy
   * @src:  The source buffer
   * @len:  The number of byte in src
   *
- * Copies data into a iosys mapping. The source buffer is in system
- * memory. Depending on the buffer's location, the helper picks the correct
- * method of accessing the memory.
+ * Copies data into a iosys_map with an offset. The source buffer is in
+ * system memory. Depending on the buffer's location, the helper picks the
+ * correct method of accessing the memory.
   */
-static inline void iosys_map_memcpy_to(struct iosys_map *dst, const void *src,
-  size_t len)
+static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t 
dst_offset,
+  const void *src, size_t len)
  {
if (dst->is_iomem)
-   memcpy_toio(dst->vaddr_iomem, src, len);
+   memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
else
-   memcpy(dst->vaddr, src, len);
+   memcpy(dst->vaddr + dst_offset, src, len);
  }
  
  /**




Re: [RFC PATCH 1/3] drm: Extract amdgpu_sa.c as a generic suballocation helper

2022-02-04 Thread Christian König

Oh, that's on my TODO list for years!

Am 04.02.22 um 18:48 schrieb Maarten Lankhorst:

Suballocating a buffer object is something that is not driver
generic, and is useful for other drivers as well.

Signed-off-by: Maarten Lankhorst 
---
  drivers/gpu/drm/Makefile   |   4 +-
  drivers/gpu/drm/drm_suballoc.c | 424 +
  include/drm/drm_suballoc.h |  78 ++
  3 files changed, 505 insertions(+), 1 deletion(-)
  create mode 100644 drivers/gpu/drm/drm_suballoc.c
  create mode 100644 include/drm/drm_suballoc.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8675c2af7ae1..b848bcf8790c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -57,7 +57,9 @@ drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
drm_scdc_helper.o drm_gem_atomic_helper.o \
drm_gem_framebuffer_helper.o \
drm_atomic_state_helper.o drm_damage_helper.o \
-   drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
+   drm_format_helper.o drm_self_refresh_helper.o drm_rect.o \
+   drm_suballoc.o
+


I think we should put that into a separate module like we now do with 
other helpers as well.



  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
  
diff --git a/drivers/gpu/drm/drm_suballoc.c b/drivers/gpu/drm/drm_suballoc.c

new file mode 100644
index ..e0bb35367b71
--- /dev/null
+++ b/drivers/gpu/drm/drm_suballoc.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *Jerome Glisse 
+ */


That is hopelessly outdated. IIRC I completely rewrote that stuff in ~2012.


+/* Algorithm:
+ *
+ * We store the last allocated bo in "hole", we always try to allocate
+ * after the last allocated bo. Principle is that in a linear GPU ring
+ * progression was is after last is the oldest bo we allocated and thus
+ * the first one that should no longer be in use by the GPU.
+ *
+ * If it's not the case we skip over the bo after last to the closest
+ * done bo if such one exist. If none exist and we are not asked to
+ * block we report failure to allocate.
+ *
+ * If we are asked to block we wait on all the oldest fence of all
+ * rings. We just wait for any of those fence to complete.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void drm_suballoc_remove_locked(struct drm_suballoc *sa);
+static void drm_suballoc_try_free(struct drm_suballoc_manager *sa_manager);
+
+/**
+ * drm_suballoc_manager_init - Initialise the drm_suballoc_manager
+ *
+ * @sa_manager: pointer to the sa_manager
+ * @size: number of bytes we want to suballocate
+ * @align: alignment for each suballocated chunk
+ *
+ * Prepares the suballocation manager for suballocations.
+ */
+void drm_suballoc_manager_init(struct drm_suballoc_manager *sa_manager,
+  u32 size, u32 align)
+{
+   u32 i;
+
+   if (!align)
+   align = 1;
+
+   /* alignment must be a power of 2 */
+   BUG_ON(align & (align - 1));


When we move that I think we should cleanup the code once more, e.g. use 
is_power_of_2() function here for example.


There are also a bunch of places with extra {} and constructs like "if 
() return true; else return false;" which could certainly be simplified.


Apart from that really great idea.

Regards,
Christian.


+
+   init_waitqueue_head(&sa_manager->wq);
+   sa_manager->size = size;
+   sa_manager->align = align;
+   sa_manager->hole = &sa_manager->olist;
+   INIT_LIST_HEAD(&sa_manager->olist);
+   for (i = 0; i < DRM_SUBALLOC_MAX_QUEUES; ++i)
+   INIT_LIST_HEAD(&sa_manager->flist[i]);
+}
+EXPORT_SYMBOL(drm_

[PATCH] drm/nouveau/backlight: Fix LVDS backlight detection on some laptops

2022-02-04 Thread Lyude Paul
It seems that some laptops will report having both an eDP and LVDS
connector, even though only the LVDS connector is actually hooked up. This
can lead to issues with backlight registration if the eDP connector ends up
getting registered before the LVDS connector, as the backlight device will
then be registered to the eDP connector instead of the LVDS connector.

So, fix this by only registering the backlight on connectors that are
reported as being connected.

Signed-off-by: Lyude Paul 
Fixes: 6eca310e8924 ("drm/nouveau/kms/nv50-: Add basic DPCD backlight support 
for nouveau")
Bugzilla: https://gitlab.freedesktop.org/drm/nouveau/-/issues/137
Cc:  # v5.15+
---
 drivers/gpu/drm/nouveau/nouveau_backlight.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c 
b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index ae2f2abc8f5a..6af12dc99d7f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -294,7 +294,8 @@ nv50_backlight_init(struct nouveau_backlight *bl,
struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
struct nvif_object *device = &drm->client.device.object;
 
-   if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) 
- 1)))
+   if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) 
- 1)) ||
+   nv_conn->base.status != connector_status_connected)
return -ENODEV;
 
if (nv_conn->type == DCB_CONNECTOR_eDP) {
-- 
2.34.1



[RFC PATCH 1/3] drm: Extract amdgpu_sa.c as a generic suballocation helper

2022-02-04 Thread Maarten Lankhorst
Suballocating a buffer object is something that is not driver
generic, and is useful for other drivers as well.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/Makefile   |   4 +-
 drivers/gpu/drm/drm_suballoc.c | 424 +
 include/drm/drm_suballoc.h |  78 ++
 3 files changed, 505 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_suballoc.c
 create mode 100644 include/drm/drm_suballoc.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 8675c2af7ae1..b848bcf8790c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -57,7 +57,9 @@ drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
drm_scdc_helper.o drm_gem_atomic_helper.o \
drm_gem_framebuffer_helper.o \
drm_atomic_state_helper.o drm_damage_helper.o \
-   drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
+   drm_format_helper.o drm_self_refresh_helper.o drm_rect.o \
+   drm_suballoc.o
+
 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 
diff --git a/drivers/gpu/drm/drm_suballoc.c b/drivers/gpu/drm/drm_suballoc.c
new file mode 100644
index ..e0bb35367b71
--- /dev/null
+++ b/drivers/gpu/drm/drm_suballoc.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *Jerome Glisse 
+ */
+/* Algorithm:
+ *
+ * We store the last allocated bo in "hole", we always try to allocate
+ * after the last allocated bo. Principle is that in a linear GPU ring
+ * progression was is after last is the oldest bo we allocated and thus
+ * the first one that should no longer be in use by the GPU.
+ *
+ * If it's not the case we skip over the bo after last to the closest
+ * done bo if such one exist. If none exist and we are not asked to
+ * block we report failure to allocate.
+ *
+ * If we are asked to block we wait on all the oldest fence of all
+ * rings. We just wait for any of those fence to complete.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void drm_suballoc_remove_locked(struct drm_suballoc *sa);
+static void drm_suballoc_try_free(struct drm_suballoc_manager *sa_manager);
+
+/**
+ * drm_suballoc_manager_init - Initialise the drm_suballoc_manager
+ *
+ * @sa_manager: pointer to the sa_manager
+ * @size: number of bytes we want to suballocate
+ * @align: alignment for each suballocated chunk
+ *
+ * Prepares the suballocation manager for suballocations.
+ */
+void drm_suballoc_manager_init(struct drm_suballoc_manager *sa_manager,
+  u32 size, u32 align)
+{
+   u32 i;
+
+   if (!align)
+   align = 1;
+
+   /* alignment must be a power of 2 */
+   BUG_ON(align & (align - 1));
+
+   init_waitqueue_head(&sa_manager->wq);
+   sa_manager->size = size;
+   sa_manager->align = align;
+   sa_manager->hole = &sa_manager->olist;
+   INIT_LIST_HEAD(&sa_manager->olist);
+   for (i = 0; i < DRM_SUBALLOC_MAX_QUEUES; ++i)
+   INIT_LIST_HEAD(&sa_manager->flist[i]);
+}
+EXPORT_SYMBOL(drm_suballoc_manager_init);
+
+/**
+ * drm_suballoc_manager_fini - Destroy the drm_suballoc_manager
+ *
+ * @sa_manager: pointer to the sa_manager
+ *
+ * Cleans up the suballocation manager after use. All fences added
+ * with drm_suballoc_free() must be signaled, or we cannot clean up
+ * the entire manager.
+ */
+void drm_suballoc_manager_fini(struct drm_suballoc_manager *sa_manager)
+{
+   struct drm_suballoc *sa, *tmp;
+
+   if (!sa_manager->size)
+   return;
+
+   if (!list_empty(&sa_manager->olist)) {
+   sa_manager->hole = &sa_manager->olist,
+   drm

[RFC PATCH 2/3] drm/amd: Convert amdgpu to use suballocation helper.

2022-02-04 Thread Maarten Lankhorst
Now that the suballocation helper is generic, we can use it in amdgpu.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h|  29 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.h |  21 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 320 ++---
 4 files changed, 39 insertions(+), 336 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 9a53a4de2bb7..a8c7a7ef480c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -61,6 +61,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include "dm_pp_interface.h"
@@ -417,29 +418,11 @@ struct amdgpu_clock {
  * alignment).
  */
 
-#define AMDGPU_SA_NUM_FENCE_LISTS  32
-
 struct amdgpu_sa_manager {
-   wait_queue_head_t   wq;
-   struct amdgpu_bo*bo;
-   struct list_head*hole;
-   struct list_headflist[AMDGPU_SA_NUM_FENCE_LISTS];
-   struct list_headolist;
-   unsignedsize;
-   uint64_tgpu_addr;
-   void*cpu_ptr;
-   uint32_tdomain;
-   uint32_talign;
-};
-
-/* sub-allocation buffer */
-struct amdgpu_sa_bo {
-   struct list_headolist;
-   struct list_headflist;
-   struct amdgpu_sa_manager*manager;
-   unsignedsoffset;
-   unsignedeoffset;
-   struct dma_fence*fence;
+   struct drm_suballoc_manager base;
+   struct amdgpu_bo*bo;
+   uint64_tgpu_addr;
+   void*cpu_ptr;
 };
 
 int amdgpu_fence_slab_init(void);
@@ -470,7 +453,7 @@ struct amdgpu_flip_work {
  */
 
 struct amdgpu_ib {
-   struct amdgpu_sa_bo *sa_bo;
+   struct drm_suballoc *sa_bo;
uint32_tlength_dw;
uint64_tgpu_addr;
uint32_t*ptr;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index bc1297dcdf97..883828a4988c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -69,7 +69,7 @@ int amdgpu_ib_get(struct amdgpu_device *adev, struct 
amdgpu_vm *vm,
 
if (size) {
r = amdgpu_sa_bo_new(&adev->ib_pools[pool_type],
- &ib->sa_bo, size, 256);
+ &ib->sa_bo, size);
if (r) {
dev_err(adev->dev, "failed to get a new IB (%d)\n", r);
return r;
@@ -307,8 +307,7 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev)
 
for (i = 0; i < AMDGPU_IB_POOL_MAX; i++) {
r = amdgpu_sa_bo_manager_init(adev, &adev->ib_pools[i],
- AMDGPU_IB_POOL_SIZE,
- AMDGPU_GPU_PAGE_SIZE,
+ AMDGPU_IB_POOL_SIZE, 256,
  AMDGPU_GEM_DOMAIN_GTT);
if (r)
goto error;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index 4c9cbdc66995..7db4fe1bc1d6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -337,15 +337,20 @@ uint32_t amdgpu_bo_get_preferred_domain(struct 
amdgpu_device *adev,
 /*
  * sub allocation
  */
+static inline struct amdgpu_sa_manager *
+to_amdgpu_sa_manager(struct drm_suballoc_manager *manager)
+{
+   return container_of(manager, struct amdgpu_sa_manager, base);
+}
 
-static inline uint64_t amdgpu_sa_bo_gpu_addr(struct amdgpu_sa_bo *sa_bo)
+static inline uint64_t amdgpu_sa_bo_gpu_addr(struct drm_suballoc *sa_bo)
 {
-   return sa_bo->manager->gpu_addr + sa_bo->soffset;
+   return to_amdgpu_sa_manager(sa_bo->manager)->gpu_addr + sa_bo->soffset;
 }
 
-static inline void * amdgpu_sa_bo_cpu_addr(struct amdgpu_sa_bo *sa_bo)
+static inline void * amdgpu_sa_bo_cpu_addr(struct drm_suballoc *sa_bo)
 {
-   return sa_bo->manager->cpu_ptr + sa_bo->soffset;
+   return to_amdgpu_sa_manager(sa_bo->manager)->cpu_ptr + sa_bo->soffset;
 }
 
 int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev,
@@ -356,11 +361,11 @@ void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev,
 int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
  struct amdgpu_sa_manager *sa_manager);
 int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
-struct amdgpu_sa_bo **sa_bo,
-unsigned size, unsigned align);
+struct drm_suballoc **sa_bo,
+unsigned siz

[RFC PATCH 3/3] drm/radeon: Use the drm suballocation manager implementation.

2022-02-04 Thread Maarten Lankhorst
Use the generic suballocation helper lifted from amdgpu.
Note that the generic suballocator only allows a single alignment,
so we may waste a few more bytes for radeon_semaphore, shouldn't
be a big deal, could be re-added if needed.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/radeon/radeon.h   |  55 +---
 drivers/gpu/drm/radeon/radeon_ib.c|  10 +-
 drivers/gpu/drm/radeon/radeon_object.h|  23 +-
 drivers/gpu/drm/radeon/radeon_sa.c| 314 ++
 drivers/gpu/drm/radeon/radeon_semaphore.c |   6 +-
 5 files changed, 51 insertions(+), 357 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 895776c421d4..a6339c9e7c47 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -79,6 +79,7 @@
 #include 
 
 #include 
+#include 
 
 #include "radeon_family.h"
 #include "radeon_mode.h"
@@ -512,52 +513,12 @@ struct radeon_bo {
 };
 #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, tbo.base)
 
-/* sub-allocation manager, it has to be protected by another lock.
- * By conception this is an helper for other part of the driver
- * like the indirect buffer or semaphore, which both have their
- * locking.
- *
- * Principe is simple, we keep a list of sub allocation in offset
- * order (first entry has offset == 0, last entry has the highest
- * offset).
- *
- * When allocating new object we first check if there is room at
- * the end total_size - (last_object_offset + last_object_size) >=
- * alloc_size. If so we allocate new object there.
- *
- * When there is not enough room at the end, we start waiting for
- * each sub object until we reach object_offset+object_size >=
- * alloc_size, this object then become the sub object we return.
- *
- * Alignment can't be bigger than page size.
- *
- * Hole are not considered for allocation to keep things simple.
- * Assumption is that there won't be hole (all object on same
- * alignment).
- */
 struct radeon_sa_manager {
-   wait_queue_head_t   wq;
-   struct radeon_bo*bo;
-   struct list_head*hole;
-   struct list_headflist[RADEON_NUM_RINGS];
-   struct list_headolist;
-   unsignedsize;
-   uint64_tgpu_addr;
-   void*cpu_ptr;
-   uint32_tdomain;
-   uint32_talign;
-};
-
-struct radeon_sa_bo;
-
-/* sub-allocation buffer */
-struct radeon_sa_bo {
-   struct list_headolist;
-   struct list_headflist;
-   struct radeon_sa_manager*manager;
-   unsignedsoffset;
-   unsignedeoffset;
-   struct radeon_fence *fence;
+   struct drm_suballoc_manager base;
+   struct radeon_bo*bo;
+   uint64_tgpu_addr;
+   void*cpu_ptr;
+   u32 domain;
 };
 
 /*
@@ -588,7 +549,7 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
  * Semaphores.
  */
 struct radeon_semaphore {
-   struct radeon_sa_bo *sa_bo;
+   struct drm_suballoc *sa_bo;
signed  waiters;
uint64_tgpu_addr;
 };
@@ -817,7 +778,7 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, 
unsigned hpd_mask);
  */
 
 struct radeon_ib {
-   struct radeon_sa_bo *sa_bo;
+   struct drm_suballoc *sa_bo;
uint32_tlength_dw;
uint64_tgpu_addr;
uint32_t*ptr;
diff --git a/drivers/gpu/drm/radeon/radeon_ib.c 
b/drivers/gpu/drm/radeon/radeon_ib.c
index 62b116727b4f..bca2cbd27abf 100644
--- a/drivers/gpu/drm/radeon/radeon_ib.c
+++ b/drivers/gpu/drm/radeon/radeon_ib.c
@@ -61,7 +61,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
 {
int r;
 
-   r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256);
+   r = radeon_sa_bo_new(&rdev->ring_tmp_bo, &ib->sa_bo, size);
if (r) {
dev_err(rdev->dev, "failed to get a new IB (%d)\n", r);
return r;
@@ -97,7 +97,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
 void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
 {
radeon_sync_free(rdev, &ib->sync, ib->fence);
-   radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence);
+   radeon_sa_bo_free(&ib->sa_bo, ib->fence);
radeon_fence_unref(&ib->fence);
 }
 
@@ -201,8 +201,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
 
if (rdev->family >= CHIP_BONAIRE) {
r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo,
- RADEON_IB_POOL_SIZE*64*1024,
- RADEON_GPU_PAGE_SIZE,
+ RADEON_IB_POOL_SIZE*6

[RFC PATCH 0/3] drm/helpers: Make the suballocation manager drm generic.

2022-02-04 Thread Maarten Lankhorst
The suballocation manager itself is not dependent on any implementation detail,
and can be made generic. I want to potentially use it inside i915, as it looks
like a clean implementation to do so. :)

Looking for feedback and some testing, as I don't have a amdgpu/radeon myself.
Only compile tested so far, so some stupid bugs may remain.

Maarten Lankhorst (3):
  drm: Extract amdgpu_sa.c as a generic suballocation helper
  drm/amd: Convert amdgpu to use suballocation helper.
  drm/radeon: Use the drm suballocation manager implementation.

 drivers/gpu/drm/Makefile   |   4 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu.h|  29 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c |   5 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.h |  21 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 320 +---
 drivers/gpu/drm/drm_suballoc.c | 424 +
 drivers/gpu/drm/radeon/radeon.h|  55 +--
 drivers/gpu/drm/radeon/radeon_ib.c |  10 +-
 drivers/gpu/drm/radeon/radeon_object.h |  23 +-
 drivers/gpu/drm/radeon/radeon_sa.c | 314 ++-
 drivers/gpu/drm/radeon/radeon_semaphore.c  |   6 +-
 include/drm/drm_suballoc.h |  78 
 12 files changed, 595 insertions(+), 694 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_suballoc.c
 create mode 100644 include/drm/drm_suballoc.h

-- 
2.34.1



[PATCH 11/19] drm/i915/guc: Convert golden context prep to iosys_map

2022-02-04 Thread Lucas De Marchi
Use the saved ads_map to prepare the golden context. One difference from
the init context is that this function can be called before there is a
gem object (and thus the guc->ads_map) to calculare the size of the
golden context that should be allocated for that object.

So in this case the function needs to be prepared for not having the
system_info with enabled engines filled out. To accomplish that an
info_map is prepared on the side to point either to the gem object
or the local variable on the stack. This allows making
fill_engine_enable_masks() operate always with a iosys_map
argument.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 52 +-
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 973762ce2196..80fbab831536 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -67,6 +67,12 @@ struct __guc_ads_blob {
iosys_map_wr_field(&(guc_)->ads_map, struct __guc_ads_blob, \
   field_, val_)
 
+#define info_map_write(map_, field_, val_) \
+   iosys_map_wr_field(map_, struct guc_gt_system_info, field_, val_)
+
+#define info_map_read(map_, field_) \
+   iosys_map_rd_field(map_, struct guc_gt_system_info, field_)
+
 static u32 guc_ads_regset_size(struct intel_guc *guc)
 {
GEM_BUG_ON(!guc->ads_regset_size);
@@ -378,24 +384,24 @@ static void guc_mmio_reg_state_init(struct intel_guc *guc,
 }
 
 static void fill_engine_enable_masks(struct intel_gt *gt,
-struct guc_gt_system_info *info)
+struct iosys_map *info_map)
 {
-   info->engine_enabled_masks[GUC_RENDER_CLASS] = 1;
-   info->engine_enabled_masks[GUC_BLITTER_CLASS] = 1;
-   info->engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt);
-   info->engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt);
+   info_map_write(info_map, engine_enabled_masks[GUC_RENDER_CLASS], 1);
+   info_map_write(info_map, engine_enabled_masks[GUC_BLITTER_CLASS], 1);
+   info_map_write(info_map, engine_enabled_masks[GUC_VIDEO_CLASS], 
VDBOX_MASK(gt));
+   info_map_write(info_map, engine_enabled_masks[GUC_VIDEOENHANCE_CLASS], 
VEBOX_MASK(gt));
 }
 
 #define LR_HW_CONTEXT_SIZE (80 * sizeof(u32))
 #define LRC_SKIP_SIZE (LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE)
-static int guc_prep_golden_context(struct intel_guc *guc,
-  struct __guc_ads_blob *blob)
+static int guc_prep_golden_context(struct intel_guc *guc)
 {
struct intel_gt *gt = guc_to_gt(guc);
u32 addr_ggtt, offset;
u32 total_size = 0, alloc_size, real_size;
u8 engine_class, guc_class;
-   struct guc_gt_system_info *info, local_info;
+   struct guc_gt_system_info local_info;
+   struct iosys_map info_map;
 
/*
 * Reserve the memory for the golden contexts and point GuC at it but
@@ -409,14 +415,15 @@ static int guc_prep_golden_context(struct intel_guc *guc,
 * GuC will also validate that the LRC base + size fall within the
 * allowed GGTT range.
 */
-   if (blob) {
+   if (!iosys_map_is_null(&guc->ads_map)) {
offset = guc_ads_golden_ctxt_offset(guc);
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
-   info = &blob->system_info;
+   info_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map,
+offsetof(struct 
__guc_ads_blob, system_info));
} else {
memset(&local_info, 0, sizeof(local_info));
-   info = &local_info;
-   fill_engine_enable_masks(gt, info);
+   iosys_map_set_vaddr(&info_map, &local_info);
+   fill_engine_enable_masks(gt, &info_map);
}
 
for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; 
++engine_class) {
@@ -425,14 +432,14 @@ static int guc_prep_golden_context(struct intel_guc *guc,
 
guc_class = engine_class_to_guc_class(engine_class);
 
-   if (!info->engine_enabled_masks[guc_class])
+   if (!info_map_read(&info_map, engine_enabled_masks[guc_class]))
continue;
 
real_size = intel_engine_context_size(gt, engine_class);
alloc_size = PAGE_ALIGN(real_size);
total_size += alloc_size;
 
-   if (!blob)
+   if (iosys_map_is_null(&guc->ads_map))
continue;
 
/*
@@ -446,12 +453,15 @@ static int guc_prep_golden_context(struct intel_guc *guc,
 * what comes before it in the context image (which is identical
 

[PATCH 15/19] drm/i915/guc: Prepare for error propagation

2022-02-04 Thread Lucas De Marchi
Currently guc_mmio_reg_add() relies on having enough memory available in
the array to add a new slot. It uses
`GEM_BUG_ON(count >= regset->size);` to protect going above the
threshold.

In order to allow guc_mmio_reg_add() to handle the memory allocation by
itself, it must return an error in case of failures.  Adjust return code
so this error can be propagated to the callers of guc_mmio_reg_add() and
guc_mmio_regset_init().

No intended change in behavior.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 31 +-
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 245b703568ff..3a4558948c31 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -244,8 +244,8 @@ static int guc_mmio_reg_cmp(const void *a, const void *b)
return (int)ra->offset - (int)rb->offset;
 }
 
-static void guc_mmio_reg_add(struct temp_regset *regset,
-u32 offset, u32 flags)
+static long __must_check guc_mmio_reg_add(struct temp_regset *regset,
+ u32 offset, u32 flags)
 {
u32 count = regset->used;
struct guc_mmio_reg reg = {
@@ -264,7 +264,7 @@ static void guc_mmio_reg_add(struct temp_regset *regset,
 */
if (bsearch(®, regset->registers, count,
sizeof(reg), guc_mmio_reg_cmp))
-   return;
+   return 0;
 
slot = ®set->registers[count];
regset->used++;
@@ -277,6 +277,8 @@ static void guc_mmio_reg_add(struct temp_regset *regset,
 
swap(slot[1], slot[0]);
}
+
+   return 0;
 }
 
 #define GUC_MMIO_REG_ADD(regset, reg, masked) \
@@ -284,32 +286,35 @@ static void guc_mmio_reg_add(struct temp_regset *regset,
 i915_mmio_reg_offset((reg)), \
 (masked) ? GUC_REGSET_MASKED : 0)
 
-static void guc_mmio_regset_init(struct temp_regset *regset,
-struct intel_engine_cs *engine)
+static int guc_mmio_regset_init(struct temp_regset *regset,
+   struct intel_engine_cs *engine)
 {
const u32 base = engine->mmio_base;
struct i915_wa_list *wal = &engine->wa_list;
struct i915_wa *wa;
unsigned int i;
+   int ret = 0;
 
regset->used = 0;
 
-   GUC_MMIO_REG_ADD(regset, RING_MODE_GEN7(base), true);
-   GUC_MMIO_REG_ADD(regset, RING_HWS_PGA(base), false);
-   GUC_MMIO_REG_ADD(regset, RING_IMR(base), false);
+   ret |= GUC_MMIO_REG_ADD(regset, RING_MODE_GEN7(base), true);
+   ret |= GUC_MMIO_REG_ADD(regset, RING_HWS_PGA(base), false);
+   ret |= GUC_MMIO_REG_ADD(regset, RING_IMR(base), false);
 
for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
-   GUC_MMIO_REG_ADD(regset, wa->reg, wa->masked_reg);
+   ret |= GUC_MMIO_REG_ADD(regset, wa->reg, wa->masked_reg);
 
/* Be extra paranoid and include all whitelist registers. */
for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++)
-   GUC_MMIO_REG_ADD(regset,
-RING_FORCE_TO_NONPRIV(base, i),
-false);
+   ret |= GUC_MMIO_REG_ADD(regset,
+   RING_FORCE_TO_NONPRIV(base, i),
+   false);
 
/* add in local MOCS registers */
for (i = 0; i < GEN9_LNCFCMOCS_REG_COUNT; i++)
-   GUC_MMIO_REG_ADD(regset, GEN9_LNCFCMOCS(i), false);
+   ret |= GUC_MMIO_REG_ADD(regset, GEN9_LNCFCMOCS(i), false);
+
+   return ret ? -1 : 0;
 }
 
 static int guc_mmio_reg_state_query(struct intel_guc *guc)
-- 
2.35.1



[PATCH 18/19] drm/i915/guc: Convert __guc_ads_init to iosys_map

2022-02-04 Thread Lucas De Marchi
Now that all the called functions from __guc_ads_init() are converted to
use ads_map, stop using ads_blob in __guc_ads_init().

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 25 --
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index cf6fafa1024c..6262fd4e0d4a 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -613,7 +613,6 @@ static void __guc_ads_init(struct intel_guc *guc)
 {
struct intel_gt *gt = guc_to_gt(guc);
struct drm_i915_private *i915 = gt->i915;
-   struct __guc_ads_blob *blob = guc->ads_blob;
struct iosys_map info_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map,
offsetof(struct __guc_ads_blob, system_info));
u32 base;
@@ -624,17 +623,18 @@ static void __guc_ads_init(struct intel_guc *guc)
/* System info */
fill_engine_enable_masks(gt, &info_map);
 
-   
blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED] =
-   hweight8(gt->info.sseu.slice_mask);
-   
blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK]
 =
-   gt->info.vdbox_sfc_access;
+   ads_blob_write(guc, 
system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED],
+  hweight8(gt->info.sseu.slice_mask));
+   ads_blob_write(guc, 
system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK],
+  gt->info.vdbox_sfc_access);
 
if (GRAPHICS_VER(i915) >= 12 && !IS_DGFX(i915)) {
u32 distdbreg = intel_uncore_read(gt->uncore,
  GEN12_DIST_DBS_POPULATED);
-   
blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI]
 =
-   ((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT) &
-GEN12_DOORBELLS_PER_SQIDI) + 1;
+   ads_blob_write(guc,
+  
system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI],
+  ((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT)
+   & GEN12_DOORBELLS_PER_SQIDI) + 1);
}
 
/* Golden contexts for re-initialising after a watchdog reset */
@@ -648,14 +648,17 @@ static void __guc_ads_init(struct intel_guc *guc)
guc_capture_list_init(guc);
 
/* ADS */
-   blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
-   blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
+   ads_blob_write(guc, ads.scheduler_policies, base +
+  offsetof(struct __guc_ads_blob, policies));
+   ads_blob_write(guc, ads.gt_system_info, base +
+  offsetof(struct __guc_ads_blob, system_info));
 
/* MMIO save/restore list */
guc_mmio_reg_state_init(guc);
 
/* Private Data */
-   blob->ads.private_data = base + guc_ads_private_data_offset(guc);
+   ads_blob_write(guc, ads.private_data, base +
+  guc_ads_private_data_offset(guc));
 
i915_gem_object_flush_map(guc->ads_vma->obj);
 }
-- 
2.35.1



[PATCH 14/19] drm/i915/guc: Convert capture list to iosys_map

2022-02-04 Thread Lucas De Marchi
Use iosys_map to write the fields ads.capture_*.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 9e96a44a6bbc..245b703568ff 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -544,7 +544,7 @@ static void guc_init_golden_context(struct intel_guc *guc)
GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
 }
 
-static void guc_capture_list_init(struct intel_guc *guc, struct __guc_ads_blob 
*blob)
+static void guc_capture_list_init(struct intel_guc *guc)
 {
int i, j;
u32 addr_ggtt, offset;
@@ -556,11 +556,11 @@ static void guc_capture_list_init(struct intel_guc *guc, 
struct __guc_ads_blob *
 
for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; i++) {
for (j = 0; j < GUC_MAX_ENGINE_CLASSES; j++) {
-   blob->ads.capture_instance[i][j] = addr_ggtt;
-   blob->ads.capture_class[i][j] = addr_ggtt;
+   ads_blob_write(guc, ads.capture_instance[i][j], 
addr_ggtt);
+   ads_blob_write(guc, ads.capture_class[i][j], addr_ggtt);
}
 
-   blob->ads.capture_global[i] = addr_ggtt;
+   ads_blob_write(guc, ads.capture_global[i], addr_ggtt);
}
 }
 
@@ -600,7 +600,7 @@ static void __guc_ads_init(struct intel_guc *guc)
base = intel_guc_ggtt_offset(guc, guc->ads_vma);
 
/* Capture list for hang debug */
-   guc_capture_list_init(guc, blob);
+   guc_capture_list_init(guc);
 
/* ADS */
blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
-- 
2.35.1



[PATCH 17/19] drm/i915/guc: Convert guc_mmio_reg_state_init to iosys_map

2022-02-04 Thread Lucas De Marchi
Now that the regset list is prepared, convert guc_mmio_reg_state_init()
to use iosys_map to copy the array to the final location and
initialize additional fields in ads.reg_state_list.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 30 +-
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index c040d8d8d7a4..cf6fafa1024c 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -383,40 +383,46 @@ static long guc_mmio_reg_state_create(struct intel_guc 
*guc)
return ret;
 }
 
-static void guc_mmio_reg_state_init(struct intel_guc *guc,
-   struct __guc_ads_blob *blob)
+static void guc_mmio_reg_state_init(struct intel_guc *guc)
 {
+   struct iosys_map ads_regset_map;
struct intel_gt *gt = guc_to_gt(guc);
struct intel_engine_cs *engine;
-   struct guc_mmio_reg *ads_registers;
enum intel_engine_id id;
u32 addr_ggtt, offset;
 
offset = guc_ads_regset_offset(guc);
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
-   ads_registers = (struct guc_mmio_reg *)(((u8 *)blob) + offset);
+   ads_regset_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);
 
-   memcpy(ads_registers, guc->ads_regset, guc->ads_regset_size);
+   iosys_map_memcpy_to(&ads_regset_map, 0, guc->ads_regset,
+   guc->ads_regset_size);
 
for_each_engine(engine, gt, id) {
u32 count = guc->ads_regset_count[id];
-   struct guc_mmio_reg_set *ads_reg_set;
u8 guc_class;
 
/* Class index is checked in class converter */
GEM_BUG_ON(engine->instance >= GUC_MAX_INSTANCES_PER_CLASS);
 
guc_class = engine_class_to_guc_class(engine->class);
-   ads_reg_set = 
&blob->ads.reg_state_list[guc_class][engine->instance];
 
if (!count) {
-   ads_reg_set->address = 0;
-   ads_reg_set->count = 0;
+   ads_blob_write(guc,
+  
ads.reg_state_list[guc_class][engine->instance].address,
+  0);
+   ads_blob_write(guc,
+  
ads.reg_state_list[guc_class][engine->instance].count,
+  0);
continue;
}
 
-   ads_reg_set->address = addr_ggtt;
-   ads_reg_set->count = count;
+   ads_blob_write(guc,
+  
ads.reg_state_list[guc_class][engine->instance].address,
+  addr_ggtt);
+   ads_blob_write(guc,
+  
ads.reg_state_list[guc_class][engine->instance].count,
+  count);
 
addr_ggtt += count * sizeof(struct guc_mmio_reg);
}
@@ -646,7 +652,7 @@ static void __guc_ads_init(struct intel_guc *guc)
blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
 
/* MMIO save/restore list */
-   guc_mmio_reg_state_init(guc, blob);
+   guc_mmio_reg_state_init(guc);
 
/* Private Data */
blob->ads.private_data = base + guc_ads_private_data_offset(guc);
-- 
2.35.1



[PATCH 10/19] drm/i915/guc: Convert guc_ads_private_data_reset to iosys_map

2022-02-04 Thread Lucas De Marchi
Use iosys_map_memset() to zero the private data as ADS may be either
on system or IO memory.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 1d21a2d457e0..973762ce2196 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -674,8 +674,8 @@ static void guc_ads_private_data_reset(struct intel_guc 
*guc)
if (!size)
return;
 
-   memset((void *)guc->ads_blob + guc_ads_private_data_offset(guc), 0,
-  size);
+   iosys_map_memset(&guc->ads_map, guc_ads_private_data_offset(guc),
+0, size);
 }
 
 /**
-- 
2.35.1



[PATCH 19/19] drm/i915/guc: Remove plain ads_blob pointer

2022-02-04 Thread Lucas De Marchi
Now we have the access to content of GuC ADS either using iosys_map
API or using a temporary buffer. Remove guc->ads_blob as there shouldn't
be updates using the bare pointer anymore.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc.h | 3 +--
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 8 
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index f857e9190750..bf7079480d47 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -147,8 +147,7 @@ struct intel_guc {
 
/** @ads_vma: object allocated to hold the GuC ADS */
struct i915_vma *ads_vma;
-   /** @ads_blob: contents of the GuC ADS */
-   struct __guc_ads_blob *ads_blob;
+   /** @ads_map: contents of the GuC ADS */
struct iosys_map ads_map;
/** @ads_regset_size: size of the save/restore regsets in the ADS */
u32 ads_regset_size;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 6262fd4e0d4a..7dd44b6d76da 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -672,6 +672,7 @@ static void __guc_ads_init(struct intel_guc *guc)
  */
 int intel_guc_ads_create(struct intel_guc *guc)
 {
+   void *ads_blob;
u32 size;
int ret;
 
@@ -696,14 +697,14 @@ int intel_guc_ads_create(struct intel_guc *guc)
size = guc_ads_blob_size(guc);
 
ret = intel_guc_allocate_and_map_vma(guc, size, &guc->ads_vma,
-(void **)&guc->ads_blob);
+&ads_blob);
if (ret)
return ret;
 
if (i915_gem_object_is_lmem(guc->ads_vma->obj))
-   iosys_map_set_vaddr_iomem(&guc->ads_map, (void __iomem 
*)guc->ads_blob);
+   iosys_map_set_vaddr_iomem(&guc->ads_map, (void __iomem 
*)ads_blob);
else
-   iosys_map_set_vaddr(&guc->ads_map, guc->ads_blob);
+   iosys_map_set_vaddr(&guc->ads_map, ads_blob);
 
__guc_ads_init(guc);
 
@@ -725,7 +726,6 @@ void intel_guc_ads_init_late(struct intel_guc *guc)
 void intel_guc_ads_destroy(struct intel_guc *guc)
 {
i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP);
-   guc->ads_blob = NULL;
iosys_map_clear(&guc->ads_map);
kfree(guc->ads_regset);
 }
-- 
2.35.1



[PATCH 12/19] drm/i915/guc: Replace check for golden context size

2022-02-04 Thread Lucas De Marchi
In the other places in this function, guc->ads_map is being protected
from access when it's not yet set. However the last check is actually
about guc->ads_golden_ctxt_size been set before.  These checks should
always match as the size is initialized on the first call to
guc_prep_golden_context(), but it's clearer if we have a single return
and check for guc->ads_golden_ctxt_size.

This is just a readability improvement, no change in behavior.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 80fbab831536..098a4756e8c5 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -461,10 +461,10 @@ static int guc_prep_golden_context(struct intel_guc *guc)
addr_ggtt += alloc_size;
}
 
-   if (iosys_map_is_null(&guc->ads_map))
-   return total_size;
+   /* Make sure current size matches what we calculated previously */
+   if (guc->ads_golden_ctxt_size)
+   GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
 
-   GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
return total_size;
 }
 
-- 
2.35.1



[PATCH 09/19] drm/i915/guc: Convert engine record to iosys_map

2022-02-04 Thread Lucas De Marchi
Use iosys_map to read fields from the dma_blob so access to IO and
system memory is abstracted away.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c  | 14 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h  |  3 ++-
 .../gpu/drm/i915/gt/uc/intel_guc_submission.c   | 17 ++---
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 6311b9da87e4..1d21a2d457e0 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -698,18 +698,16 @@ void intel_guc_ads_reset(struct intel_guc *guc)
 
 u32 intel_guc_engine_usage_offset(struct intel_guc *guc)
 {
-   struct __guc_ads_blob *blob = guc->ads_blob;
-   u32 base = intel_guc_ggtt_offset(guc, guc->ads_vma);
-   u32 offset = base + ptr_offset(blob, engine_usage);
-
-   return offset;
+   return intel_guc_ggtt_offset(guc, guc->ads_vma) +
+   offsetof(struct __guc_ads_blob, engine_usage);
 }
 
-struct guc_engine_usage_record *intel_guc_engine_usage(struct intel_engine_cs 
*engine)
+struct iosys_map intel_guc_engine_usage_record_map(struct intel_engine_cs 
*engine)
 {
struct intel_guc *guc = &engine->gt->uc.guc;
-   struct __guc_ads_blob *blob = guc->ads_blob;
u8 guc_class = engine_class_to_guc_class(engine->class);
+   size_t offset = offsetof(struct __guc_ads_blob,
+
engine_usage.engines[guc_class][ilog2(engine->logical_mask)]);
 
-   return 
&blob->engine_usage.engines[guc_class][ilog2(engine->logical_mask)];
+   return IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);
 }
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
index e74c110facff..1c64f4d6ea21 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.h
@@ -7,6 +7,7 @@
 #define _INTEL_GUC_ADS_H_
 
 #include 
+#include 
 
 struct intel_guc;
 struct drm_printer;
@@ -18,7 +19,7 @@ void intel_guc_ads_init_late(struct intel_guc *guc);
 void intel_guc_ads_reset(struct intel_guc *guc);
 void intel_guc_ads_print_policy_info(struct intel_guc *guc,
 struct drm_printer *p);
-struct guc_engine_usage_record *intel_guc_engine_usage(struct intel_engine_cs 
*engine);
+struct iosys_map intel_guc_engine_usage_record_map(struct intel_engine_cs 
*engine);
 u32 intel_guc_engine_usage_offset(struct intel_guc *guc);
 
 #endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index b3a429a92c0d..6d34842f68b4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -1139,6 +1139,9 @@ __extend_last_switch(struct intel_guc *guc, u64 
*prev_start, u32 new_start)
*prev_start = ((u64)gt_stamp_hi << 32) | new_start;
 }
 
+#define record_read(map_, field_) \
+   iosys_map_rd_field(map_, struct guc_engine_usage_record, field_)
+
 /*
  * GuC updates shared memory and KMD reads it. Since this is not synchronized,
  * we run into a race where the value read is inconsistent. Sometimes the
@@ -1153,17 +1156,17 @@ __extend_last_switch(struct intel_guc *guc, u64 
*prev_start, u32 new_start)
 static void __get_engine_usage_record(struct intel_engine_cs *engine,
  u32 *last_in, u32 *id, u32 *total)
 {
-   struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
+   struct iosys_map rec_map = intel_guc_engine_usage_record_map(engine);
int i = 0;
 
do {
-   *last_in = READ_ONCE(rec->last_switch_in_stamp);
-   *id = READ_ONCE(rec->current_context_index);
-   *total = READ_ONCE(rec->total_runtime);
+   *last_in = record_read(&rec_map, last_switch_in_stamp);
+   *id = record_read(&rec_map, current_context_index);
+   *total = record_read(&rec_map, total_runtime);
 
-   if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&
-   READ_ONCE(rec->current_context_index) == *id &&
-   READ_ONCE(rec->total_runtime) == *total)
+   if (record_read(&rec_map, last_switch_in_stamp) == *last_in &&
+   record_read(&rec_map, current_context_index) == *id &&
+   record_read(&rec_map, total_runtime) == *total)
break;
} while (++i < 6);
 }
-- 
2.35.1



[PATCH 16/19] drm/i915/guc: Use a single pass to calculate regset

2022-02-04 Thread Lucas De Marchi
The ADS initialitazion was using 2 passes to calculate the regset sent
to GuC to initialize each engine: the first pass to just have the final
object size and the second to set each register in place in the final
gem object.

However in order to maintain an ordered set of registers to pass to guc,
each register needs to be added and moved in the final array. The second
phase may actually happen in IO memory rather than system memory and
accessing IO memory by simply dereferencing the pointer doesn't work on
all architectures. Other places of the ADS initializaition were
converted to use the iosys_map API, but here there may be a lot more
accesses to IO memory. So, instead of following that same approach,
convert the regset initialization to calculate the final array in 1
pass and in the second pass that array is just copied to its final
location, updating the pointers for each engine written to the ADS blob.

One important thing is that struct temp_regset now have
different semantics: `registers` continues to track the registers of a
single engine, however the other fields are updated together, according
to the newly added `storage`, which tracks the memory allocated for
all the registers. So rename some of these fields and add a
__mmio_reg_add(): this function (possibly) allocates memory and operates
on the storage pointer while guc_mmio_reg_add() continues to manage the
registers pointer.

On a Tiger Lake system using enable_guc=3, the following log message is
now seen:

[  187.334310] i915 :00:02.0: [drm:intel_guc_ads_create [i915]] 
Used 4 KB for temporary ADS regset

This change has also been tested on an ARM64 host with DG2 and other
discrete graphics cards.

v2 (Daniele):
  - Fix leaking tempset on error path
  - Add comments on struct temp_regset to document the meaning of each
field

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc.h |   7 ++
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 128 +
 2 files changed, 90 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 9b9ba79f7594..f857e9190750 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -152,6 +152,13 @@ struct intel_guc {
struct iosys_map ads_map;
/** @ads_regset_size: size of the save/restore regsets in the ADS */
u32 ads_regset_size;
+   /**
+* @ads_regset_count: number of save/restore registers in the ADS for
+* each engine
+*/
+   u32 ads_regset_count[I915_NUM_ENGINES];
+   /** @ads_regset: save/restore regsets in the ADS */
+   struct guc_mmio_reg *ads_regset;
/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
u32 ads_golden_ctxt_size;
/** @ads_engine_usage_size: size of engine usage in the ADS */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 3a4558948c31..c040d8d8d7a4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -226,14 +226,18 @@ static void guc_mapping_table_init(struct intel_gt *gt,
 
 /*
  * The save/restore register list must be pre-calculated to a temporary
- * buffer of driver defined size before it can be generated in place
- * inside the ADS.
+ * buffer before it can be copied inside the ADS.
  */
-#define MAX_MMIO_REGS  128 /* Arbitrary size, increase as needed */
 struct temp_regset {
+   /*
+* ptr to the section of the storage for the engine currently being
+* worked on
+*/
struct guc_mmio_reg *registers;
-   u32 used;
-   u32 size;
+   /* ptr to the base of the allocated storage for all engines */
+   struct guc_mmio_reg *storage;
+   u32 storage_used;
+   u32 storage_max;
 };
 
 static int guc_mmio_reg_cmp(const void *a, const void *b)
@@ -244,18 +248,44 @@ static int guc_mmio_reg_cmp(const void *a, const void *b)
return (int)ra->offset - (int)rb->offset;
 }
 
+static struct guc_mmio_reg * __must_check
+__mmio_reg_add(struct temp_regset *regset, struct guc_mmio_reg *reg)
+{
+   u32 pos = regset->storage_used;
+   struct guc_mmio_reg *slot;
+
+   if (pos >= regset->storage_max) {
+   size_t size = ALIGN((pos + 1) * sizeof(*slot), PAGE_SIZE);
+   struct guc_mmio_reg *r = krealloc(regset->storage,
+ size, GFP_KERNEL);
+   if (!r) {
+   WARN_ONCE(1, "Incomplete regset list: can't add 
register (%d)\n",
+ -ENOMEM);
+   return ERR_PTR(-ENOMEM);
+   }
+
+   regset->registers = r + (regset->registers - regset->storage);
+

[PATCH 13/19] drm/i915/guc: Convert mapping table to iosys_map

2022-02-04 Thread Lucas De Marchi
Use iosys_map to write the fields system_info.mapping_table[][].
Since we already have the info_map around where needed, just use it
instead of going through guc->ads_map.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 098a4756e8c5..9e96a44a6bbc 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -204,7 +204,7 @@ int intel_guc_global_policies_update(struct intel_guc *guc)
 }
 
 static void guc_mapping_table_init(struct intel_gt *gt,
-  struct guc_gt_system_info *system_info)
+  struct iosys_map *info_map)
 {
unsigned int i, j;
struct intel_engine_cs *engine;
@@ -213,14 +213,14 @@ static void guc_mapping_table_init(struct intel_gt *gt,
/* Table must be set to invalid values for entries not used */
for (i = 0; i < GUC_MAX_ENGINE_CLASSES; ++i)
for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; ++j)
-   system_info->mapping_table[i][j] =
-   GUC_MAX_INSTANCES_PER_CLASS;
+   info_map_write(info_map, mapping_table[i][j],
+  GUC_MAX_INSTANCES_PER_CLASS);
 
for_each_engine(engine, gt, id) {
u8 guc_class = engine_class_to_guc_class(engine->class);
 
-   
system_info->mapping_table[guc_class][ilog2(engine->logical_mask)] =
-   engine->instance;
+   info_map_write(info_map, 
mapping_table[guc_class][ilog2(engine->logical_mask)],
+  engine->instance);
}
 }
 
@@ -595,7 +595,7 @@ static void __guc_ads_init(struct intel_guc *guc)
/* Golden contexts for re-initialising after a watchdog reset */
guc_prep_golden_context(guc);
 
-   guc_mapping_table_init(guc_to_gt(guc), &blob->system_info);
+   guc_mapping_table_init(guc_to_gt(guc), &info_map);
 
base = intel_guc_ggtt_offset(guc, guc->ads_vma);
 
-- 
2.35.1



[PATCH 07/19] drm/i915/guc: Convert golden context init to iosys_map

2022-02-04 Thread Lucas De Marchi
Now the map is saved during creation, so use it to initialize the
golden context, reading from shmem and writing to either system or IO
memory.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 25 +++---
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 3a0afce7564e..d32b407a2d25 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -473,18 +473,17 @@ static struct intel_engine_cs *find_engine_state(struct 
intel_gt *gt, u8 engine_
 
 static void guc_init_golden_context(struct intel_guc *guc)
 {
-   struct __guc_ads_blob *blob = guc->ads_blob;
struct intel_engine_cs *engine;
struct intel_gt *gt = guc_to_gt(guc);
+   struct iosys_map golden_context_map;
u32 addr_ggtt, offset;
u32 total_size = 0, alloc_size, real_size;
u8 engine_class, guc_class;
-   u8 *ptr;
 
if (!intel_uc_uses_guc_submission(>->uc))
return;
 
-   GEM_BUG_ON(!blob);
+   GEM_BUG_ON(iosys_map_is_null(&guc->ads_map));
 
/*
 * Go back and fill in the golden context data now that it is
@@ -492,15 +491,15 @@ static void guc_init_golden_context(struct intel_guc *guc)
 */
offset = guc_ads_golden_ctxt_offset(guc);
addr_ggtt = intel_guc_ggtt_offset(guc, guc->ads_vma) + offset;
-   ptr = ((u8 *)blob) + offset;
+
+   golden_context_map = IOSYS_MAP_INIT_OFFSET(&guc->ads_map, offset);
 
for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; 
++engine_class) {
if (engine_class == OTHER_CLASS)
continue;
 
guc_class = engine_class_to_guc_class(engine_class);
-
-   if (!blob->system_info.engine_enabled_masks[guc_class])
+   if (!ads_blob_read(guc, 
system_info.engine_enabled_masks[guc_class]))
continue;
 
real_size = intel_engine_context_size(gt, engine_class);
@@ -511,18 +510,20 @@ static void guc_init_golden_context(struct intel_guc *guc)
if (!engine) {
drm_err(>->i915->drm, "No engine state recorded for 
class %d!\n",
engine_class);
-   blob->ads.eng_state_size[guc_class] = 0;
-   blob->ads.golden_context_lrca[guc_class] = 0;
+   ads_blob_write(guc, ads.eng_state_size[guc_class], 0);
+   ads_blob_write(guc, ads.golden_context_lrca[guc_class], 
0);
continue;
}
 
-   GEM_BUG_ON(blob->ads.eng_state_size[guc_class] !=
+   GEM_BUG_ON(ads_blob_read(guc, ads.eng_state_size[guc_class]) !=
   real_size - LRC_SKIP_SIZE);
-   GEM_BUG_ON(blob->ads.golden_context_lrca[guc_class] != 
addr_ggtt);
+   GEM_BUG_ON(ads_blob_read(guc, 
ads.golden_context_lrca[guc_class]) != addr_ggtt);
+
addr_ggtt += alloc_size;
 
-   shmem_read(engine->default_state, 0, ptr, real_size);
-   ptr += alloc_size;
+   shmem_read_to_iosys_map(engine->default_state, 0,
+   &golden_context_map, real_size);
+   iosys_map_incr(&golden_context_map, alloc_size);
}
 
GEM_BUG_ON(guc->ads_golden_ctxt_size != total_size);
-- 
2.35.1



[PATCH 08/19] drm/i915/guc: Convert policies update to iosys_map

2022-02-04 Thread Lucas De Marchi
Use iosys_map to write the policies update so access to IO and system
memory is abstracted away.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 41 --
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index d32b407a2d25..6311b9da87e4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -130,33 +130,37 @@ static u32 guc_ads_blob_size(struct intel_guc *guc)
   guc_ads_private_data_size(guc);
 }
 
-static void guc_policies_init(struct intel_guc *guc, struct guc_policies 
*policies)
+static void guc_policies_init(struct intel_guc *guc)
 {
struct intel_gt *gt = guc_to_gt(guc);
struct drm_i915_private *i915 = gt->i915;
+   u32 global_flags = 0;
 
-   policies->dpc_promote_time = GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
-   policies->max_num_work_items = GLOBAL_POLICY_MAX_NUM_WI;
+   ads_blob_write(guc, policies.dpc_promote_time,
+  GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US);
+   ads_blob_write(guc, policies.max_num_work_items,
+  GLOBAL_POLICY_MAX_NUM_WI);
 
-   policies->global_flags = 0;
if (i915->params.reset < 2)
-   policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET;
+   global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET;
 
-   policies->is_valid = 1;
+   ads_blob_write(guc, policies.global_flags, global_flags);
+   ads_blob_write(guc, policies.is_valid, 1);
 }
 
 void intel_guc_ads_print_policy_info(struct intel_guc *guc,
 struct drm_printer *dp)
 {
-   struct __guc_ads_blob *blob = guc->ads_blob;
-
-   if (unlikely(!blob))
+   if (unlikely(iosys_map_is_null(&guc->ads_map)))
return;
 
drm_printf(dp, "Global scheduling policies:\n");
-   drm_printf(dp, "  DPC promote time   = %u\n", 
blob->policies.dpc_promote_time);
-   drm_printf(dp, "  Max num work items = %u\n", 
blob->policies.max_num_work_items);
-   drm_printf(dp, "  Flags  = %u\n", 
blob->policies.global_flags);
+   drm_printf(dp, "  DPC promote time   = %u\n",
+  ads_blob_read(guc, policies.dpc_promote_time));
+   drm_printf(dp, "  Max num work items = %u\n",
+  ads_blob_read(guc, policies.max_num_work_items));
+   drm_printf(dp, "  Flags  = %u\n",
+  ads_blob_read(guc, policies.global_flags));
 }
 
 static int guc_action_policies_update(struct intel_guc *guc, u32 policy_offset)
@@ -171,23 +175,24 @@ static int guc_action_policies_update(struct intel_guc 
*guc, u32 policy_offset)
 
 int intel_guc_global_policies_update(struct intel_guc *guc)
 {
-   struct __guc_ads_blob *blob = guc->ads_blob;
struct intel_gt *gt = guc_to_gt(guc);
+   u32 scheduler_policies;
intel_wakeref_t wakeref;
int ret;
 
-   if (!blob)
+   if (iosys_map_is_null(&guc->ads_map))
return -EOPNOTSUPP;
 
-   GEM_BUG_ON(!blob->ads.scheduler_policies);
+   scheduler_policies = ads_blob_read(guc, ads.scheduler_policies);
+   GEM_BUG_ON(!scheduler_policies);
 
-   guc_policies_init(guc, &blob->policies);
+   guc_policies_init(guc);
 
if (!intel_guc_is_ready(guc))
return 0;
 
with_intel_runtime_pm(>->i915->runtime_pm, wakeref)
-   ret = guc_action_policies_update(guc, 
blob->ads.scheduler_policies);
+   ret = guc_action_policies_update(guc, scheduler_policies);
 
return ret;
 }
@@ -557,7 +562,7 @@ static void __guc_ads_init(struct intel_guc *guc)
u32 base;
 
/* GuC scheduling policies */
-   guc_policies_init(guc, &blob->policies);
+   guc_policies_init(guc);
 
/* System info */
fill_engine_enable_masks(gt, &blob->system_info);
-- 
2.35.1



[PATCH 06/19] drm/i915/guc: Add read/write helpers for ADS blob

2022-02-04 Thread Lucas De Marchi
Add helpers on top of iosys_map_read_field() /
iosys_map_write_field() functions so they always use the right
arguments and make code easier to read.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index 13671b186908..3a0afce7564e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -60,6 +60,13 @@ struct __guc_ads_blob {
struct guc_mmio_reg regset[0];
 } __packed;
 
+#define ads_blob_read(guc_, field_)\
+   iosys_map_rd_field(&(guc_)->ads_map, struct __guc_ads_blob, field_)
+
+#define ads_blob_write(guc_, field_, val_) \
+   iosys_map_wr_field(&(guc_)->ads_map, struct __guc_ads_blob, \
+  field_, val_)
+
 static u32 guc_ads_regset_size(struct intel_guc *guc)
 {
GEM_BUG_ON(!guc->ads_regset_size);
-- 
2.35.1



[PATCH 01/19] dma-buf-map: Rename to iosys-map

2022-02-04 Thread Lucas De Marchi
Rename struct dma_buf_map to struct iosys_map and corresponding APIs.
Over time dma-buf-map grew up to more functionality than the one used by
dma-buf: in fact it's just a shim layer to abstract system memory, that
can be accessed via regular load and store, from IO memory that needs to
be acessed via arch helpers.

The idea is to extend this API so it can fulfill other needs, internal
to a single driver. Example: in the i915 driver it's desired to share
the implementation for integrated graphics, which uses mostly system
memory, with discrete graphics, which may need to access IO memory.

The conversion was mostly done with the following semantic patch:

@r1@
@@
- struct dma_buf_map
+ struct iosys_map

@r2@
@@
(
- DMA_BUF_MAP_INIT_VADDR
+ IOSYS_MAP_INIT_VADDR
|
- dma_buf_map_set_vaddr
+ iosys_map_set_vaddr
|
- dma_buf_map_set_vaddr_iomem
+ iosys_map_set_vaddr_iomem
|
- dma_buf_map_is_equal
+ iosys_map_is_equal
|
- dma_buf_map_is_null
+ iosys_map_is_null
|
- dma_buf_map_is_set
+ iosys_map_is_set
|
- dma_buf_map_clear
+ iosys_map_clear
|
- dma_buf_map_memcpy_to
+ iosys_map_memcpy_to
|
- dma_buf_map_incr
+ iosys_map_incr
)

@@
@@
- #include 
+ #include 

Then some files had their includes adjusted and some comments were
update to remove mentions to dma-buf-map.

Since this is not specific to dma-buf anymore, move the documentation to
the "Bus-Independent Device Accesses" section.

v2:
  - Squash patches

v3:
  - Fix wrong removal of dma-buf.h from MAINTAINERS
  - Move documentation from dma-buf.rst to device-io.rst

v4:
  - Change documentation tile and level

Signed-off-by: Lucas De Marchi 
Acked-by: Christian König 
Acked-by: Sumit Semwal 
Acked-by: Thomas Zimmermann 
---
 Documentation/driver-api/device-io.rst|   9 +
 Documentation/driver-api/dma-buf.rst  |   9 -
 Documentation/gpu/todo.rst|  20 +-
 MAINTAINERS   |   9 +-
 drivers/dma-buf/dma-buf.c |  22 +-
 drivers/dma-buf/heaps/cma_heap.c  |  10 +-
 drivers/dma-buf/heaps/system_heap.c   |  10 +-
 drivers/gpu/drm/ast/ast_drv.h |   2 +-
 drivers/gpu/drm/ast/ast_mode.c|   8 +-
 drivers/gpu/drm/drm_cache.c   |  18 +-
 drivers/gpu/drm/drm_client.c  |   9 +-
 drivers/gpu/drm/drm_fb_helper.c   |  12 +-
 drivers/gpu/drm/drm_gem.c |  12 +-
 drivers/gpu/drm/drm_gem_cma_helper.c  |   9 +-
 drivers/gpu/drm/drm_gem_framebuffer_helper.c  |  16 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c|  15 +-
 drivers/gpu/drm/drm_gem_ttm_helper.c  |   4 +-
 drivers/gpu/drm/drm_gem_vram_helper.c |  25 +-
 drivers/gpu/drm/drm_internal.h|   6 +-
 drivers/gpu/drm/drm_mipi_dbi.c|   8 +-
 drivers/gpu/drm/drm_prime.c   |   4 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |   2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c   |   8 +-
 drivers/gpu/drm/gud/gud_pipe.c|   4 +-
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c   |   5 +-
 drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c|   8 +-
 .../drm/i915/gem/selftests/i915_gem_dmabuf.c  |   6 +-
 .../gpu/drm/i915/gem/selftests/mock_dmabuf.c  |   6 +-
 drivers/gpu/drm/lima/lima_gem.c   |   3 +-
 drivers/gpu/drm/lima/lima_sched.c |   4 +-
 drivers/gpu/drm/mediatek/mtk_drm_gem.c|   7 +-
 drivers/gpu/drm/mediatek/mtk_drm_gem.h|   5 +-
 drivers/gpu/drm/mgag200/mgag200_mode.c|   4 +-
 drivers/gpu/drm/msm/msm_drv.h |   4 +-
 drivers/gpu/drm/msm/msm_gem_prime.c   |   6 +-
 drivers/gpu/drm/panfrost/panfrost_perfcnt.c   |  13 +-
 drivers/gpu/drm/qxl/qxl_display.c |   8 +-
 drivers/gpu/drm/qxl/qxl_draw.c|   6 +-
 drivers/gpu/drm/qxl/qxl_drv.h |  10 +-
 drivers/gpu/drm/qxl/qxl_object.c  |   8 +-
 drivers/gpu/drm/qxl/qxl_object.h  |   4 +-
 drivers/gpu/drm/qxl/qxl_prime.c   |   4 +-
 drivers/gpu/drm/radeon/radeon_gem.c   |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c   |   9 +-
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h   |   5 +-
 drivers/gpu/drm/tegra/gem.c   |  10 +-
 drivers/gpu/drm/tiny/cirrus.c |   8 +-
 drivers/gpu/drm/tiny/gm12u320.c   |   7 +-
 drivers/gpu/drm/ttm/ttm_bo_util.c |  16 +-
 drivers/gpu/drm/ttm/ttm_resource.c|  42 +--
 drivers/gpu/drm/ttm/ttm_tt.c  |   8 +-
 drivers/gpu/drm/udl/udl_modeset.c |   3 +-
 drivers/gpu/drm/vboxvideo/vbox_mode.c |   4 +-
 drivers/gpu/drm/vkms/vkms_c

[PATCH 05/19] drm/i915/guc: Keep iosys_map of ads_blob around

2022-02-04 Thread Lucas De Marchi
Convert intel_guc_ads_create() and initialization to use iosys_map
rather than plain pointer and save it in the guc struct. This will help
with additional updates to the ads_blob after the
creation/initialization by abstracting the IO vs system memory.

Cc: Matt Roper 
Cc: Thomas Hellström 
Cc: Daniel Vetter 
Cc: John Harrison 
Cc: Matthew Brost 
Cc: Daniele Ceraolo Spurio 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/uc/intel_guc.h | 4 +++-
 drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c | 6 ++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h 
b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 697d9d66acef..9b9ba79f7594 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -6,8 +6,9 @@
 #ifndef _INTEL_GUC_H_
 #define _INTEL_GUC_H_
 
-#include 
 #include 
+#include 
+#include 
 
 #include "intel_uncore.h"
 #include "intel_guc_fw.h"
@@ -148,6 +149,7 @@ struct intel_guc {
struct i915_vma *ads_vma;
/** @ads_blob: contents of the GuC ADS */
struct __guc_ads_blob *ads_blob;
+   struct iosys_map ads_map;
/** @ads_regset_size: size of the save/restore regsets in the ADS */
u32 ads_regset_size;
/** @ads_golden_ctxt_size: size of the golden contexts in the ADS */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c 
b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index e61150adcbe9..13671b186908 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -624,6 +624,11 @@ int intel_guc_ads_create(struct intel_guc *guc)
if (ret)
return ret;
 
+   if (i915_gem_object_is_lmem(guc->ads_vma->obj))
+   iosys_map_set_vaddr_iomem(&guc->ads_map, (void __iomem 
*)guc->ads_blob);
+   else
+   iosys_map_set_vaddr(&guc->ads_map, guc->ads_blob);
+
__guc_ads_init(guc);
 
return 0;
@@ -645,6 +650,7 @@ void intel_guc_ads_destroy(struct intel_guc *guc)
 {
i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP);
guc->ads_blob = NULL;
+   iosys_map_clear(&guc->ads_map);
 }
 
 static void guc_ads_private_data_reset(struct intel_guc *guc)
-- 
2.35.1



[PATCH 04/19] drm/i915/gt: Add helper for shmem copy to iosys_map

2022-02-04 Thread Lucas De Marchi
Add a variant of shmem_read() that takes a iosys_map pointer rather
than a plain pointer as argument. It's mostly a copy __shmem_rw() but
adapting the api and removing the write support since there's currently
only need to use iosys_map as destination.

Reworking __shmem_rw() to share the implementation was tempting, but
finding a good balance between reuse and clarity pushed towards a little
code duplication. Since the function is small, just add the similar
function with a copy/paste/adapt approach.

Cc: Matt Roper 
Cc: Joonas Lahtinen 
Cc: Tvrtko Ursulin 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: Matthew Auld 
Cc: Thomas Hellström 
Cc: Maarten Lankhorst 
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/i915/gt/shmem_utils.c | 33 +++
 drivers/gpu/drm/i915/gt/shmem_utils.h |  3 +++
 2 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c 
b/drivers/gpu/drm/i915/gt/shmem_utils.c
index 0683b27a3890..764adefdb4be 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.c
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
@@ -3,6 +3,7 @@
  * Copyright © 2020 Intel Corporation
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -123,6 +124,38 @@ static int __shmem_rw(struct file *file, loff_t off,
return 0;
 }
 
+int shmem_read_to_iosys_map(struct file *file, loff_t off,
+   struct iosys_map *map, size_t len)
+{
+   struct iosys_map map_iter = *map;
+   unsigned long pfn;
+
+   for (pfn = off >> PAGE_SHIFT; len; pfn++) {
+   unsigned int this =
+   min_t(size_t, PAGE_SIZE - offset_in_page(off), len);
+   struct page *page;
+   void *vaddr;
+
+   page = shmem_read_mapping_page_gfp(file->f_mapping, pfn,
+  GFP_KERNEL);
+   if (IS_ERR(page))
+   return PTR_ERR(page);
+
+   vaddr = kmap(page);
+   iosys_map_memcpy_to(&map_iter, 0, vaddr + offset_in_page(off),
+   this);
+   mark_page_accessed(page);
+   kunmap(page);
+   put_page(page);
+
+   len -= this;
+   iosys_map_incr(&map_iter, this);
+   off = 0;
+   }
+
+   return 0;
+}
+
 int shmem_read(struct file *file, loff_t off, void *dst, size_t len)
 {
return __shmem_rw(file, off, dst, len, false);
diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.h 
b/drivers/gpu/drm/i915/gt/shmem_utils.h
index c1669170c351..e1784999faee 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.h
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.h
@@ -8,6 +8,7 @@
 
 #include 
 
+struct iosys_map;
 struct drm_i915_gem_object;
 struct file;
 
@@ -17,6 +18,8 @@ struct file *shmem_create_from_object(struct 
drm_i915_gem_object *obj);
 void *shmem_pin_map(struct file *file);
 void shmem_unpin_map(struct file *file, void *ptr);
 
+int shmem_read_to_iosys_map(struct file *file, loff_t off,
+   struct iosys_map *map, size_t len);
 int shmem_read(struct file *file, loff_t off, void *dst, size_t len);
 int shmem_write(struct file *file, loff_t off, void *src, size_t len);
 
-- 
2.35.1



[PATCH 02/19] iosys-map: Add offset to iosys_map_memcpy_to()

2022-02-04 Thread Lucas De Marchi
In certain situations it's useful to be able to write to an
offset of the mapping. Add a dst_offset to iosys_map_memcpy_to().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
 drivers/gpu/drm/drm_cache.c |  2 +-
 drivers/gpu/drm/drm_fb_helper.c |  2 +-
 include/linux/iosys-map.h   | 17 +
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 66597e411764..c3e6e615bf09 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -218,7 +218,7 @@ static void memcpy_fallback(struct iosys_map *dst,
if (!dst->is_iomem && !src->is_iomem) {
memcpy(dst->vaddr, src->vaddr, len);
} else if (!src->is_iomem) {
-   iosys_map_memcpy_to(dst, src->vaddr, len);
+   iosys_map_memcpy_to(dst, 0, src->vaddr, len);
} else if (!dst->is_iomem) {
memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
} else {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 238f815cb2a0..bf5cc9a42e5a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -385,7 +385,7 @@ static void drm_fb_helper_damage_blit_real(struct 
drm_fb_helper *fb_helper,
iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
 
for (y = clip->y1; y < clip->y2; y++) {
-   iosys_map_memcpy_to(dst, src, len);
+   iosys_map_memcpy_to(dst, 0, src, len);
iosys_map_incr(dst, fb->pitches[0]);
src += fb->pitches[0];
}
diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index f4186f91caa6..edd7fa3be9e9 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -220,22 +220,23 @@ static inline void iosys_map_clear(struct iosys_map *map)
 }
 
 /**
- * iosys_map_memcpy_to - Memcpy into iosys mapping
+ * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map
  * @dst:   The iosys_map structure
+ * @dst_offset:The offset from which to copy
  * @src:   The source buffer
  * @len:   The number of byte in src
  *
- * Copies data into a iosys mapping. The source buffer is in system
- * memory. Depending on the buffer's location, the helper picks the correct
- * method of accessing the memory.
+ * Copies data into a iosys_map with an offset. The source buffer is in
+ * system memory. Depending on the buffer's location, the helper picks the
+ * correct method of accessing the memory.
  */
-static inline void iosys_map_memcpy_to(struct iosys_map *dst, const void *src,
-  size_t len)
+static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t 
dst_offset,
+  const void *src, size_t len)
 {
if (dst->is_iomem)
-   memcpy_toio(dst->vaddr_iomem, src, len);
+   memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
else
-   memcpy(dst->vaddr, src, len);
+   memcpy(dst->vaddr + dst_offset, src, len);
 }
 
 /**
-- 
2.35.1



[PATCH 03/19] iosys-map: Add a few more helpers

2022-02-04 Thread Lucas De Marchi
First the simplest ones:

- iosys_map_memset(): when abstracting system and I/O memory,
  just like the memcpy() use case, memset() also has dedicated
  functions to be called for using IO memory.
- iosys_map_memcpy_from(): we may need to copy data from I/O
  memory, not only to.

In certain situations it's useful to be able to read or write to an
offset that is calculated by having the memory layout given by a struct
declaration. Usually we are going to read/write a u8, u16, u32 or u64.

As a pre-requisite for the implementation, add iosys_map_memcpy_from()
to be the equivalent of iosys_map_memcpy_to(), but in the other
direction. Then add 2 pairs of macros:

- iosys_map_rd() / iosys_map_wr()
- iosys_map_rd_field() / iosys_map_wr_field()

The first pair takes the C-type and offset to read/write. The second
pair uses a struct describing the layout of the mapping in order to
calculate the offset and size being read/written.

We could use readb, readw, readl, readq and the write* counterparts,
however due to alignment issues this may not work on all architectures.
If alignment needs to be checked to call the right function, it's not
possible to decide at compile-time which function to call: so just leave
the decision to the memcpy function that will do exactly that.

Finally, in order to use the above macros with a map derived from
another, add another initializer: IOSYS_MAP_INIT_OFFSET().

Cc: Sumit Semwal 
Cc: Christian König 
Cc: Thomas Zimmermann 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-ker...@vger.kernel.org
Signed-off-by: Lucas De Marchi 
---
 include/linux/iosys-map.h | 154 +-
 1 file changed, 153 insertions(+), 1 deletion(-)

diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h
index edd7fa3be9e9..96f8b61ac6fb 100644
--- a/include/linux/iosys-map.h
+++ b/include/linux/iosys-map.h
@@ -6,6 +6,7 @@
 #ifndef __IOSYS_MAP_H__
 #define __IOSYS_MAP_H__
 
+#include 
 #include 
 #include 
 
@@ -133,6 +134,45 @@ static inline void iosys_map_set_vaddr(struct iosys_map 
*map, void *vaddr)
map->is_iomem = false;
 }
 
+/**
+ * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
+ * @map_:  The dma-buf mapping structure to copy from
+ * @offset_:   Offset to add to the other mapping
+ *
+ * Initializes a new iosys_map struct based on another passed as argument. It
+ * does a shallow copy of the struct so it's possible to update the back 
storage
+ * without changing where the original map points to. It is the equivalent of
+ * doing:
+ *
+ * .. code-block: c
+ *
+ * iosys_map map = other_map;
+ * iosys_map_incr(&map, &offset);
+ *
+ * Example usage:
+ *
+ * .. code-block: c
+ *
+ * void foo(struct device *dev, struct iosys_map *base_map)
+ * {
+ * ...
+ * struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, 
FIELD_OFFSET);
+ * ...
+ * }
+ *
+ * The advantage of using the initializer over just increasing the offset with
+ * ``iosys_map_incr()`` like above is that the new map will always point to the
+ * right place of the buffer during  its scope. It reduces the risk of updating
+ * the wrong part of the buffer and having no compiler warning about that. If
+ * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can 
warn
+ * using a uninitialized variable.
+ */
+#define IOSYS_MAP_INIT_OFFSET(map_, offset_)   (struct iosys_map)  \
+   {   \
+   .vaddr = (map_)->vaddr + (offset_), \
+   .is_iomem = (map_)->is_iomem,   \
+   }
+
 /**
  * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address in 
I/O memory
  * @map:   The iosys_map structure
@@ -220,7 +260,7 @@ static inline void iosys_map_clear(struct iosys_map *map)
 }
 
 /**
- * iosys_map_memcpy_to_offset - Memcpy into offset of iosys_map
+ * iosys_map_memcpy_to - Memcpy into iosys_map
  * @dst:   The iosys_map structure
  * @dst_offset:The offset from which to copy
  * @src:   The source buffer
@@ -239,6 +279,26 @@ static inline void iosys_map_memcpy_to(struct iosys_map 
*dst, size_t dst_offset,
memcpy(dst->vaddr + dst_offset, src, len);
 }
 
+/**
+ * iosys_map_memcpy_from - Memcpy from iosys_map into system memory
+ * @dst:   Destination in system memory
+ * @src:   The iosys_map structure
+ * @src_offset:The offset from which to copy
+ * @len:   The number of byte in src
+ *
+ * Copies data from a iosys_map with an offset. The dest buffer is in
+ * system memory. Depending on the mapping location, the helper picks the
+ * correct method of accessing the memory.
+ */
+static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map 
*src,
+size_t src_offset, size_t len)
+{
+ 

[PATCH 00/19] drm/i915/guc: Refactor ADS access to use iosys_map

2022-02-04 Thread Lucas De Marchi
2nd version of https://patchwork.freedesktop.org/series/99378/

As first patch I'm including the dma-buf-map rename to iosys-map for
completeness and to allow the other patches to be reviewed. However the
first patch was also sent by itself.

I think all the feedback from v1 was incorporated in this version. All
the new helpers in iosys-map were squashed in a single patch as
requested.

Original cover letter:

While porting i915 to arm64 we noticed some issues accessing lmem.
Some writes were getting corrupted and the final state of the buffer
didn't have exactly what we wrote. This became evident when enabling
GuC submission: depending on the number of engines the ADS struct was
being corrupted and GuC would reject it, refusin to initialize.

>From Documentation/core-api/bus-virt-phys-mapping.rst:

This memory is called "PCI memory" or "shared memory" or "IO memory" or
whatever, and there is only one way to access it: the readb/writeb and
related functions. You should never take the address of such memory, 
because
there is really nothing you can do with such an address: it's not
conceptually in the same memory space as "real memory" at all, so you 
cannot
just dereference a pointer. (Sadly, on x86 it **is** in the same memory 
space,
so on x86 it actually works to just deference a pointer, but it's not
portable).

When reading or writing words directly to IO memory, in order to be portable
the Linux kernel provides the abstraction detailed in section "Differences
between I/O access functions" of Documentation/driver-api/device-io.rst.

This limits our ability to simply overlay our structs on top a buffer
and directly access it since that buffer may come from IO memory rather than
system memory. Hence the approach taken in intel_guc_ads.c needs to be
refactored. This is not the only place in i915 that neeed to be changed, but
the one causing the most problems, with a real reproducer. This first set of
patch focuses on fixing the gem object to pass the ADS

After the addition of a few helpers in the dma_buf_map API, most of
intel_guc_ads.c can be converted to use it. The exception is the regset
initialization: we'd incur into a lot of extra indirection when
reading/writting each register. So the regset is converted to use a
temporary buffer allocated on probe, which is then copied to its
final location when finishing the initialization or on gt reset.

Testing on some discrete cards, after this change we can correctly pass the
ADS struct to GuC and have it initialized correctly.

thanks,
Lucas De Marchi

Lucas De Marchi (19):
  dma-buf-map: Rename to iosys-map
  iosys-map: Add offset to iosys_map_memcpy_to()
  iosys-map: Add a few more helpers
  drm/i915/gt: Add helper for shmem copy to iosys_map
  drm/i915/guc: Keep iosys_map of ads_blob around
  drm/i915/guc: Add read/write helpers for ADS blob
  drm/i915/guc: Convert golden context init to iosys_map
  drm/i915/guc: Convert policies update to iosys_map
  drm/i915/guc: Convert engine record to iosys_map
  drm/i915/guc: Convert guc_ads_private_data_reset to iosys_map
  drm/i915/guc: Convert golden context prep to iosys_map
  drm/i915/guc: Replace check for golden context size
  drm/i915/guc: Convert mapping table to iosys_map
  drm/i915/guc: Convert capture list to iosys_map
  drm/i915/guc: Prepare for error propagation
  drm/i915/guc: Use a single pass to calculate regset
  drm/i915/guc: Convert guc_mmio_reg_state_init to iosys_map
  drm/i915/guc: Convert __guc_ads_init to iosys_map
  drm/i915/guc: Remove plain ads_blob pointer

 Documentation/driver-api/device-io.rst|   9 +
 Documentation/driver-api/dma-buf.rst  |   9 -
 Documentation/gpu/todo.rst|  20 +-
 MAINTAINERS   |   9 +-
 drivers/dma-buf/dma-buf.c |  22 +-
 drivers/dma-buf/heaps/cma_heap.c  |  10 +-
 drivers/dma-buf/heaps/system_heap.c   |  10 +-
 drivers/gpu/drm/ast/ast_drv.h |   2 +-
 drivers/gpu/drm/ast/ast_mode.c|   8 +-
 drivers/gpu/drm/drm_cache.c   |  18 +-
 drivers/gpu/drm/drm_client.c  |   9 +-
 drivers/gpu/drm/drm_fb_helper.c   |  12 +-
 drivers/gpu/drm/drm_gem.c |  12 +-
 drivers/gpu/drm/drm_gem_cma_helper.c  |   9 +-
 drivers/gpu/drm/drm_gem_framebuffer_helper.c  |  16 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c|  15 +-
 drivers/gpu/drm/drm_gem_ttm_helper.c  |   4 +-
 drivers/gpu/drm/drm_gem_vram_helper.c |  25 +-
 drivers/gpu/drm/drm_internal.h|   6 +-
 drivers/gpu/drm/drm_mipi_dbi.c|   8 +-
 drivers/gpu/drm/drm_prime.c   |   4 +-
 drivers/gpu/drm/etnaviv/etnaviv_drv.h |   2 +-
 drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c   |   8 +-
 drivers/gpu/drm/gud/gud_pipe.c|   4 +-
 drivers/gpu/drm/hyperv/hyperv_drm_modeset.c   |

[Important!] 2022 X.Org Foundation Membership deadline for voting in the election

2022-02-04 Thread Lyude Paul
The 2022 X.Org Foundation elections are rapidly approaching. We will be
forwarding instructions on the nomination process to membership in the
near future.

Please note that only current members can vote in the upcoming election,
and that the deadline for new memberships or renewals to vote in the
upcoming election is March 17th 2022 at 23:59 UTC.

If you are interested in joining the X.Org Foundation or in renewing
your membership, please visit the membership system site at:

https://members.x.org/

You can find the current election schedule here:

https://www.x.org/wiki/BoardOfDirectors/Elections/2022/

    Lyude Paul,
    On behalf of the X.Org elections committee




  1   2   >