Re: [RFC PATCH v2 2/3] accel: add dedicated minor for accelerator devices
On Wed, Nov 2, 2022 at 11:17 PM Jeffrey Hugo wrote: > > On 11/2/2022 2:34 PM, Oded Gabbay wrote: > > @@ -24,16 +33,6 @@ static char *accel_devnode(struct device *dev, umode_t > > *mode) > > > > static CLASS_ATTR_STRING(accel_version, 0444, "accel 1.0.0 20221018"); > > > > -/** > > - * accel_sysfs_init - initialize sysfs helpers > > - * > > - * This is used to create the ACCEL class, which is the implicit parent of > > any > > - * other top-level ACCEL sysfs objects. > > - * > > - * You must call accel_sysfs_destroy() to release the allocated resources. > > - * > > - * Return: 0 on success, negative error code on failure. > > - */ > > Why are we removing this? It should have been removed at the first patch, and will be fixed in v3. I'm removing it as it is a static function. We don't document every static function. > > > static int accel_sysfs_init(void) > > { > > int err; > > @@ -54,11 +53,6 @@ static int accel_sysfs_init(void) > > return 0; > > } > > > > -/** > > - * accel_sysfs_destroy - destroys ACCEL class > > - * > > - * Destroy the ACCEL device class. > > - */ > > Again, why remove this? Adding it in one patch than immediately > removing it in the next patch seems wasteful. Correct, will be removed from the first patch in the next version. > > > static void accel_sysfs_destroy(void) > > { > > if (IS_ERR_OR_NULL(accel_class)) > > @@ -68,11 +62,185 @@ static void accel_sysfs_destroy(void) > > accel_class = NULL; > > } > > > > +static void accel_minor_release(struct drm_minor *minor) > > +{ > > + drm_dev_put(minor->dev); > > +} > > + > > +/** > > + * accel_open - open method for ACCEL file > > + * @inode: device inode > > + * @filp: file pointer. > > + * > > + * This function must be used by drivers as their &file_operations.open > > method. > > Feels like it would be helpful to have an accel version of > DEFINE_DRM_GEM_FOPS() which helps accel drivers to get this right Yeah, I also thought about it. I'll add it. thanks, oded > > > + * It looks up the correct ACCEL device and instantiates all the per-file > > + * resources for it. It also calls the &drm_driver.open driver callback. > > + * > > + * Return: 0 on success or negative errno value on failure. > > + */ > > +int accel_open(struct inode *inode, struct file *filp) > > +{ > > + struct drm_device *dev; > > + struct drm_minor *minor; > > + int retcode; > > + > > + minor = accel_minor_acquire(iminor(inode)); > > + if (IS_ERR(minor)) > > + return PTR_ERR(minor); > > + > > + dev = minor->dev; > > + > > + atomic_fetch_inc(&dev->open_count); > > + > > + /* share address_space across all char-devs of a single device */ > > + filp->f_mapping = dev->anon_inode->i_mapping; > > + > > + retcode = drm_open_helper(filp, minor); > > + if (retcode) > > + goto err_undo; > > + > > + return 0; > > + > > +err_undo: > > + atomic_dec(&dev->open_count); > > + accel_minor_release(minor); > > + return retcode; > > +} > > +EXPORT_SYMBOL_GPL(accel_open);
Re: [RFC PATCH v2 2/3] accel: add dedicated minor for accelerator devices
On Thu, Nov 3, 2022 at 7:26 AM Jiho Chu wrote: > > On Wed, 2 Nov 2022 22:34:04 +0200 > Oded Gabbay wrote: > > > +/** > > + * accel_open - open method for ACCEL file > > + * @inode: device inode > > + * @filp: file pointer. > > + * > > + * This function must be used by drivers as their &file_operations.open > > method. > > + * It looks up the correct ACCEL device and instantiates all the per-file > > + * resources for it. It also calls the &drm_driver.open driver callback. > > + * > > + * Return: 0 on success or negative errno value on failure. > > + */ > > +int accel_open(struct inode *inode, struct file *filp) > > +{ > > + struct drm_device *dev; > > + struct drm_minor *minor; > > + int retcode; > > + > > + minor = accel_minor_acquire(iminor(inode)); > > + if (IS_ERR(minor)) > > + return PTR_ERR(minor); > > + > > + dev = minor->dev; > > + > > + atomic_fetch_inc(&dev->open_count); > > + > > Hi, > It needs to consider drm_global_mutex to access open_count. > please check doxy of open_count. Now that I'm changing the code back to be part of drm.ko, I can return all the code that is in drm_copy which I removed for this to compile. > > > > + /* share address_space across all char-devs of a single device */ > > + filp->f_mapping = dev->anon_inode->i_mapping; > > + > > + retcode = drm_open_helper(filp, minor); > > + if (retcode) > > + goto err_undo; > > + > > + return 0; > > + > > +err_undo: > > + atomic_dec(&dev->open_count); > > + accel_minor_release(minor); > > + return retcode; > > +} > > +EXPORT_SYMBOL_GPL(accel_open); > > + > > static int accel_stub_open(struct inode *inode, struct file *filp) > > { > > - DRM_DEBUG("Operation not supported"); > > + const struct file_operations *new_fops; > > + struct drm_minor *minor; > > + int err; > > + > > + DRM_DEBUG("\n"); > > It seems useless. Correct, I removed it in v3. Thanks, Oded > > Thanks. > Jiho Chu
Re: [RFC PATCH v2 3/3] drm: initialize accel framework
On Wed, Nov 2, 2022 at 11:30 PM Jeffrey Hugo wrote: > > On 11/2/2022 2:34 PM, Oded Gabbay wrote: > > @@ -163,7 +174,11 @@ static int drm_minor_register(struct drm_device *dev, > > unsigned int type) > > > > ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); > > if (ret) { > > - DRM_ERROR("DRM: Failed to initialize > > /sys/kernel/debug/dri.\n"); > > + if (minor->type == DRM_MINOR_ACCEL) > > + DRM_ERROR("DRM: Failed to initialize > > /sys/kernel/debug/accel.\n"); > > + else > > + DRM_ERROR("DRM: Failed to initialize > > /sys/kernel/debug/dri.\n"); > > + > > goto err_debugfs; > > } > > > > This doesn't look right. Don't you need to call drm_debugfs_init() with > accel_debugfs_root for the case - minor->type == DRM_MINOR_ACCEL? > Unless I fail to understand something, this will put all the accel > devices under /sys/kernel/debug/dri ofc, you are correct. Will be fixed in v3. Thanks, Oded
How is the progress for removing flush_scheduled_work() callers?
Like commit c4f135d643823a86 ("workqueue: Wrap flush_workqueue() using a macro") says, flush_scheduled_work() is dangerous and will be forbidden. We are on the way for removing all flush_scheduled_work() callers from the kernel, and there are only 4 callers remaining as of linux-20221104. drivers/gpu/drm/i915/display/intel_display.c:8997: flush_scheduled_work(); drivers/gpu/drm/i915/gt/selftest_execlists.c:88: flush_scheduled_work(); drivers/md/dm.c:234:flush_scheduled_work(); drivers/message/fusion/mptscsih.c:1234: flush_scheduled_work(); I'm planning to start emitting runtime messages in linux-next.git tree.
Re: [PATCH v6 10/23] drm/modes: Fill drm_cmdline mode from named modes
Den 26.10.2022 17.33, skrev max...@cerno.tech: > The current code to deal with named modes will only set the mode name, and > then it's up to drivers to try to match that name to whatever mode or > configuration they see fit. > I couldn't find any driver that does that, all I could find that cares about named modes are drm_client. Did I miss something here? Apart from that: Reviewed-by: Noralf Trønnes > The plan is to remove that need and move the named mode handling out of > drivers and into the core, and only rely on modes and properties. Let's > start by properly filling drm_cmdline_mode from a named mode. > > Signed-off-by: Maxime Ripard > --- > drivers/gpu/drm/drm_modes.c | 18 -- > 1 file changed, 16 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c > index 7594b657f86a..acee23e1a8b7 100644 > --- a/drivers/gpu/drm/drm_modes.c > +++ b/drivers/gpu/drm/drm_modes.c > @@ -2226,11 +2226,22 @@ static int drm_mode_parse_cmdline_options(const char > *str, > > struct drm_named_mode { > const char *name; > + unsigned int xres; > + unsigned int yres; > + unsigned int flags; > }; > > +#define NAMED_MODE(_name, _x, _y, _flags)\ > + { \ > + .name = _name, \ > + .xres = _x, \ > + .yres = _y, \ > + .flags = _flags,\ > + } > + > static const struct drm_named_mode drm_named_modes[] = { > - { "NTSC", }, > - { "PAL", }, > + NAMED_MODE("NTSC", 720, 480, DRM_MODE_FLAG_INTERLACE), > + NAMED_MODE("PAL", 720, 576, DRM_MODE_FLAG_INTERLACE), > }; > > static int drm_mode_parse_cmdline_named_mode(const char *name, > @@ -2271,6 +2282,9 @@ static int drm_mode_parse_cmdline_named_mode(const char > *name, > continue; > > strcpy(cmdline_mode->name, mode->name); > + cmdline_mode->xres = mode->xres; > + cmdline_mode->yres = mode->yres; > + cmdline_mode->interlace = !!(mode->flags & > DRM_MODE_FLAG_INTERLACE); > cmdline_mode->specified = true; > > return 1; >
Re: [PATCH v6 11/23] drm/connector: Add pixel clock to cmdline mode
Den 26.10.2022 17.33, skrev max...@cerno.tech: > We'll need to get the pixel clock to generate proper display modes for > all the current named modes. Let's add it to struct drm_cmdline_mode and > fill it when parsing the named mode. > > Signed-off-by: Maxime Ripard > --- I would just squash this with the previous patch, either way: Reviewed-by: Noralf Trønnes > drivers/gpu/drm/drm_modes.c | 9 ++--- > include/drm/drm_connector.h | 7 +++ > 2 files changed, 13 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c > index acee23e1a8b7..c826f9583a1d 100644 > --- a/drivers/gpu/drm/drm_modes.c > +++ b/drivers/gpu/drm/drm_modes.c > @@ -2226,22 +2226,24 @@ static int drm_mode_parse_cmdline_options(const char > *str, > > struct drm_named_mode { > const char *name; > + unsigned int pixel_clock_khz; > unsigned int xres; > unsigned int yres; > unsigned int flags; > }; > > -#define NAMED_MODE(_name, _x, _y, _flags)\ > +#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \ > { \ > .name = _name, \ > + .pixel_clock_khz = _pclk, \ > .xres = _x, \ > .yres = _y, \ > .flags = _flags,\ > } > > static const struct drm_named_mode drm_named_modes[] = { > - NAMED_MODE("NTSC", 720, 480, DRM_MODE_FLAG_INTERLACE), > - NAMED_MODE("PAL", 720, 576, DRM_MODE_FLAG_INTERLACE), > + NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE), > + NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE), > }; > > static int drm_mode_parse_cmdline_named_mode(const char *name, > @@ -2282,6 +2284,7 @@ static int drm_mode_parse_cmdline_named_mode(const char > *name, > continue; > > strcpy(cmdline_mode->name, mode->name); > + cmdline_mode->pixel_clock = mode->pixel_clock_khz; > cmdline_mode->xres = mode->xres; > cmdline_mode->yres = mode->yres; > cmdline_mode->interlace = !!(mode->flags & > DRM_MODE_FLAG_INTERLACE); > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h > index 96b2e4e12334..5c5e67de2296 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -1273,6 +1273,13 @@ struct drm_cmdline_mode { >*/ > bool bpp_specified; > > + /** > + * @pixel_clock: > + * > + * Pixel Clock in kHz. Optional. > + */ > + unsigned int pixel_clock; > + > /** >* @xres: >* >
Re: [PATCH v6 13/23] drm/modes: Introduce the tv_mode property as a command-line option
Den 26.10.2022 17.33, skrev max...@cerno.tech: > Our new tv mode option allows to specify the TV mode from a property. > However, it can still be useful, for example to avoid any boot time > artifact, to set that property directly from the kernel command line. > > Let's add some code to allow it, and some unit tests to exercise that code. > > Signed-off-by: Maxime Ripard > > --- I would have just squashed the named mode part of this patch together with the 2 other named mode patches and keep just the video= option part here, but up to you: Reviewed-by: Noralf Trønnes
Re: [RFC PATCH v2 2/3] accel: add dedicated minor for accelerator devices
On Sun, Nov 6, 2022 at 12:54 PM Oded Gabbay wrote: > > On Thu, Nov 3, 2022 at 7:26 AM Jiho Chu wrote: > > > > On Wed, 2 Nov 2022 22:34:04 +0200 > > Oded Gabbay wrote: > > > > > +/** > > > + * accel_open - open method for ACCEL file > > > + * @inode: device inode > > > + * @filp: file pointer. > > > + * > > > + * This function must be used by drivers as their &file_operations.open > > > method. > > > + * It looks up the correct ACCEL device and instantiates all the per-file > > > + * resources for it. It also calls the &drm_driver.open driver callback. > > > + * > > > + * Return: 0 on success or negative errno value on failure. > > > + */ > > > +int accel_open(struct inode *inode, struct file *filp) > > > +{ > > > + struct drm_device *dev; > > > + struct drm_minor *minor; > > > + int retcode; > > > + > > > + minor = accel_minor_acquire(iminor(inode)); > > > + if (IS_ERR(minor)) > > > + return PTR_ERR(minor); > > > + > > > + dev = minor->dev; > > > + > > > + atomic_fetch_inc(&dev->open_count); > > > + > > > > Hi, > > It needs to consider drm_global_mutex to access open_count. > > please check doxy of open_count. > Now that I'm changing the code back to be part of drm.ko, I can return > all the code that is in drm_copy which I removed for this to compile. I take it back. All the code that I omitted was for legacy drivers. If you look inside drm_dev_needs_global_mutex(), you will see 3 cases where you need to take the global mutex, and all 3 are only relevant for legacy drivers and/or drivers that use deprecated features. So, I disagree with your original comment here. Moreover, open_count is atomic, so I don't need to take the mutex to increment it, and as you can see in drm_open(), the function increments it regardless of whether it takes drm_dev_needs_global_mutex. Oded > > > > > > > > + /* share address_space across all char-devs of a single device */ > > > + filp->f_mapping = dev->anon_inode->i_mapping; > > > + > > > + retcode = drm_open_helper(filp, minor); > > > + if (retcode) > > > + goto err_undo; > > > + > > > + return 0; > > > + > > > +err_undo: > > > + atomic_dec(&dev->open_count); > > > + accel_minor_release(minor); > > > + return retcode; > > > +} > > > +EXPORT_SYMBOL_GPL(accel_open); > > > + > > > static int accel_stub_open(struct inode *inode, struct file *filp) > > > { > > > - DRM_DEBUG("Operation not supported"); > > > + const struct file_operations *new_fops; > > > + struct drm_minor *minor; > > > + int err; > > > + > > > + DRM_DEBUG("\n"); > > > > It seems useless. > Correct, I removed it in v3. > Thanks, > Oded > > > > Thanks. > > Jiho Chu
Re: [PATCH v5 1/3] drm: Use XArray instead of IDR for minors
On Wed, Nov 2, 2022 at 4:23 PM Oded Gabbay wrote: > > On Mon, Sep 12, 2022 at 12:17 AM Michał Winiarski > wrote: > > > > IDR is deprecated, and since XArray manages its own state with internal > > locking, it simplifies the locking on DRM side. > > Additionally, don't use the IRQ-safe variant, since operating on drm > > minor is not done in IRQ context. > > > > Signed-off-by: Michał Winiarski > > Suggested-by: Matthew Wilcox > > --- > > drivers/gpu/drm/drm_drv.c | 51 ++- > > 1 file changed, 18 insertions(+), 33 deletions(-) > > > > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c > > index 8214a0b1ab7f..61d24cdcd0f8 100644 > > --- a/drivers/gpu/drm/drm_drv.c > > +++ b/drivers/gpu/drm/drm_drv.c > > @@ -34,6 +34,7 @@ > > #include > > #include > > #include > > +#include > > > > #include > > #include > > @@ -53,8 +54,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, > > Jon Smirl"); > > MODULE_DESCRIPTION("DRM shared core routines"); > > MODULE_LICENSE("GPL and additional rights"); > > > > -static DEFINE_SPINLOCK(drm_minor_lock); > > -static struct idr drm_minors_idr; > > +static DEFINE_XARRAY_ALLOC(drm_minors_xa); > > > > /* > > * If the drm core fails to init for whatever reason, > > @@ -98,21 +98,19 @@ static struct drm_minor **drm_minor_get_slot(struct > > drm_device *dev, > > static void drm_minor_alloc_release(struct drm_device *dev, void *data) > > { > > struct drm_minor *minor = data; > > - unsigned long flags; > > > > WARN_ON(dev != minor->dev); > > > > put_device(minor->kdev); > > > > - spin_lock_irqsave(&drm_minor_lock, flags); > > - idr_remove(&drm_minors_idr, minor->index); > > - spin_unlock_irqrestore(&drm_minor_lock, flags); > > + xa_erase(&drm_minors_xa, minor->index); > > } > > > > +#define DRM_MINOR_LIMIT(t) ({ typeof(t) _t = (t); XA_LIMIT(64 * _t, 64 * > > _t + 63); }) > > + > > static int drm_minor_alloc(struct drm_device *dev, unsigned int type) > > { > > struct drm_minor *minor; > > - unsigned long flags; > > int r; > > > > minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL); > > @@ -122,21 +120,10 @@ static int drm_minor_alloc(struct drm_device *dev, > > unsigned int type) > > minor->type = type; > > minor->dev = dev; > > > > - idr_preload(GFP_KERNEL); > > - spin_lock_irqsave(&drm_minor_lock, flags); > > - r = idr_alloc(&drm_minors_idr, > > - NULL, > > - 64 * type, > > - 64 * (type + 1), > > - GFP_NOWAIT); > > - spin_unlock_irqrestore(&drm_minor_lock, flags); > > - idr_preload_end(); > > - > > + r = xa_alloc(&drm_minors_xa, &minor->index, NULL, > > DRM_MINOR_LIMIT(type), GFP_KERNEL); This was GFP_NOWAIT in the original code. > > if (r < 0) > > return r; > > > > - minor->index = r; > > - > > r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor); > > if (r) > > return r; > > @@ -152,7 +139,7 @@ static int drm_minor_alloc(struct drm_device *dev, > > unsigned int type) > > static int drm_minor_register(struct drm_device *dev, unsigned int type) > > { > > struct drm_minor *minor; > > - unsigned long flags; > > + void *entry; > > int ret; > > > > DRM_DEBUG("\n"); > > @@ -172,9 +159,12 @@ static int drm_minor_register(struct drm_device *dev, > > unsigned int type) > > goto err_debugfs; > > > > /* replace NULL with @minor so lookups will succeed from now on */ > > - spin_lock_irqsave(&drm_minor_lock, flags); > > - idr_replace(&drm_minors_idr, minor, minor->index); > > - spin_unlock_irqrestore(&drm_minor_lock, flags); > > + entry = xa_cmpxchg(&drm_minors_xa, minor->index, NULL, &minor, > > GFP_KERNEL); > I believe we should pass in "minor", without the &, as &minor will > give you the address of the local pointer. > > Oded > > > + if (xa_is_err(entry)) { > > + ret = xa_err(entry); > > + goto err_debugfs; > > + } > > + WARN_ON(entry); > > > > DRM_DEBUG("new minor registered %d\n", minor->index); > > return 0; > > @@ -187,16 +177,13 @@ static int drm_minor_register(struct drm_device *dev, > > unsigned int type) > > static void drm_minor_unregister(struct drm_device *dev, unsigned int type) > > { > > struct drm_minor *minor; > > - unsigned long flags; > > > > minor = *drm_minor_get_slot(dev, type); > > if (!minor || !device_is_registered(minor->kdev)) > > return; > > > > /* replace @minor with NULL so lookups will fail from now on */ > > - spin_lock_irqsave(&drm_minor_lock, flags); > > - idr_replace(&drm_minors_idr, NULL, minor->index); > > - spin_unlock_irqrestore(&drm_minor_lock, flags); > >
Re: [PATCH] drm/edid/firmware: stop using throwaway platform device
Hi, Can you tell me what are we waiting for? Maybe I can help. Thanks. Matthieu On Wed, Oct 12 2022 at 07:16:29 PM +0200, Matthieu CHARETTE wrote: By crash, I mean that an error is returned here: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux.git/+/refs/heads/master/drivers/gpu/drm/drm_edid_load.c#195 I don't really know what happens next, but on my machine the built-in screen and the external remains dark. Also the kernel seems to freeze. I suspect a kernel panic, but I'm not sure. Anyway, the error is definitely not well handled, and a fix would be great. Also, request_firmware() will crash if called for the first time on the resume path because the file system isn't reachable on the resume process. And no cache is available for this firmware. So I guess that in this case, request_firmware() returns an error. Suspend-plug-resume case is not my priority nether as long as it doesn't make the system crash (Which is currently the case). On Wed, Oct 12 2022 at 11:25:59 AM +0300, Jani Nikula wrote: On Tue, 11 Oct 2022, Matthieu CHARETTE wrote: Currently the EDID is requested during the resume. But since it's requested too early, this means before the filesystem is mounted, the firmware request fails. This make the DRM driver crash when resuming. This kind of issue should be prevented by the firmware caching process which cache every firmware requested for the next resume. But since we are using a temporary device, the firmware isn't cached on suspend since the device doesn't work anymore. When using a non temporary device to get the EDID, the firmware will be cached on suspend for the next resume. So requesting the firmware during resume will succeed. But if the firmware has never been requested since the boot, this means that the monitor isn't plugged since the boot. The kernel will not be caching the EDID. So if we plug the monitor while the machine is suspended. The resume will fail to load the firmware. And the DRM driver will crash. So basically, your fix should solve the issue except for the case where the monitor hasn't been plugged since boot and is plugged while the machine is suspended. I hope I was clear. Tell me if I wasn't. I'm not really good at explaining. That was a pretty good explanation. The only thing I'm missing is what the failure mode is exactly when you claim the driver will crash. Why would request_firmware() "crash" if called for the first time on the resume path? I'm not sure I care much about not being able to load the firmware EDID in the suspend-plug-resume case (as this can be remedied with a subsequent modeset), but obviously any errors need to be handled gracefully, without crashing. BR, Jani. -- Jani Nikula, Intel Open Source Graphics Center
[PATCH v2] drm/vmwgfx: Protect pin_user_pages with mmap_lock
This patch includes changes below: 1) pin_user_pages() is unsafe without protection of mmap_lock, fix it by calling mmap_read_lock() & mmap_read_unlock(). 2) fix & refactor the incorrect exception handling procedure in vmw_mksstat_add_ioctl(). Fixes: 7a7a933edd6c ("drm/vmwgfx: Introduce VMware mks-guest-stats") Signed-off-by: Dawei Li --- v1: https://lore.kernel.org/all/tycp286mb23235c9a9fcf85c045f95ea7ca...@tycp286mb2323.jpnp286.prod.outlook.com/ v1->v2: Rebased to latest vmwgfx/drm-misc-fixes --- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 23 ++- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 089046fa21be..ec40a3364e0a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -1020,9 +1020,9 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, const size_t num_pages_info = PFN_UP(arg->info_len); const size_t num_pages_strs = PFN_UP(arg->strs_len); long desc_len; - long nr_pinned_stat; - long nr_pinned_info; - long nr_pinned_strs; + long nr_pinned_stat = 0; + long nr_pinned_info = 0; + long nr_pinned_strs = 0; struct page *pages_stat[ARRAY_SIZE(pdesc->statPPNs)]; struct page *pages_info[ARRAY_SIZE(pdesc->infoPPNs)]; struct page *pages_strs[ARRAY_SIZE(pdesc->strsPPNs)]; @@ -1084,28 +1084,33 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, reset_ppn_array(pdesc->infoPPNs, ARRAY_SIZE(pdesc->infoPPNs)); reset_ppn_array(pdesc->strsPPNs, ARRAY_SIZE(pdesc->strsPPNs)); + /* pin_user_pages() needs protection of mmap_lock */ + mmap_read_lock(current->mm); + /* Pin mksGuestStat user pages and store those in the instance descriptor */ nr_pinned_stat = pin_user_pages(arg->stat, num_pages_stat, FOLL_LONGTERM, pages_stat, NULL); if (num_pages_stat != nr_pinned_stat) - goto err_pin_stat; + goto __err_pin_pages; for (i = 0; i < num_pages_stat; ++i) pdesc->statPPNs[i] = page_to_pfn(pages_stat[i]); nr_pinned_info = pin_user_pages(arg->info, num_pages_info, FOLL_LONGTERM, pages_info, NULL); if (num_pages_info != nr_pinned_info) - goto err_pin_info; + goto __err_pin_pages; for (i = 0; i < num_pages_info; ++i) pdesc->infoPPNs[i] = page_to_pfn(pages_info[i]); nr_pinned_strs = pin_user_pages(arg->strs, num_pages_strs, FOLL_LONGTERM, pages_strs, NULL); if (num_pages_strs != nr_pinned_strs) - goto err_pin_strs; + goto __err_pin_pages; for (i = 0; i < num_pages_strs; ++i) pdesc->strsPPNs[i] = page_to_pfn(pages_strs[i]); + mmap_read_unlock(current->mm); + /* Send the descriptor to the host via a hypervisor call. The mksGuestStat pages will remain in use until the user requests a matching remove stats or a stats reset occurs. */ @@ -1120,15 +1125,15 @@ int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data, return 0; -err_pin_strs: +__err_pin_pages: + mmap_read_unlock(current->mm); + if (nr_pinned_strs > 0) unpin_user_pages(pages_strs, nr_pinned_strs); -err_pin_info: if (nr_pinned_info > 0) unpin_user_pages(pages_info, nr_pinned_info); -err_pin_stat: if (nr_pinned_stat > 0) unpin_user_pages(pages_stat, nr_pinned_stat); -- 2.25.1
Re: [PATCH v6 16/23] drm/probe-helper: Provide a TV get_modes helper
Den 26.10.2022 17.33, skrev max...@cerno.tech: > Most of the TV connectors will need a similar get_modes implementation > that will, depending on the drivers' capabilities, register the 480i and > 576i modes. > > That implementation will also need to set the preferred flag and order > the modes based on the driver and users preferrence. > > This is especially important to guarantee that a userspace stack such as > Xorg can start and pick up the preferred mode while maintaining a > working output. > > Signed-off-by: Maxime Ripard > > --- > Changes in v6: > - New patch > --- > drivers/gpu/drm/drm_probe_helper.c | 97 > ++ > include/drm/drm_probe_helper.h | 1 + > 2 files changed, 98 insertions(+) > > diff --git a/drivers/gpu/drm/drm_probe_helper.c > b/drivers/gpu/drm/drm_probe_helper.c > index 69b0b2b9cc1c..4a60575f5c66 100644 > --- a/drivers/gpu/drm/drm_probe_helper.c > +++ b/drivers/gpu/drm/drm_probe_helper.c > @@ -1147,3 +1147,100 @@ int drm_connector_helper_get_modes(struct > drm_connector *connector) > return count; > } > EXPORT_SYMBOL(drm_connector_helper_get_modes); > + > +static bool tv_mode_supported(struct drm_connector *connector, > + enum drm_connector_tv_mode mode) > +{ > + struct drm_device *dev = connector->dev; > + struct drm_property *property = dev->mode_config.tv_mode_property; > + Superfluous linebreak > + unsigned int i; > + > + for (i = 0; i < property->num_values; i++) > + if (property->values[i] == mode) > + return true; > + > + return false; > +} > + > +/** > + * drm_connector_helper_tv_get_modes - Fills the modes availables to a TV > connector availables -> available > + * @connector: The connector > + * > + * Fills the available modes for a TV connector based on the supported > + * TV modes, and the default mode expressed by the kernel command line. > + * > + * This can be used as the default TV connector helper .get_modes() hook > + * if the driver does not need any special processing. > + * > + * Returns: > + * The number of modes added to the connector. > + */ > +int drm_connector_helper_tv_get_modes(struct drm_connector *connector) > +{ > + struct drm_device *dev = connector->dev; > + struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; > + struct drm_display_mode *tv_modes[2] = {}; > + struct drm_display_mode *mode; > + unsigned int first_mode_idx; > + unsigned int count = 0; > + uint64_t default_mode; > + int ret; > + > + if (!dev->mode_config.tv_mode_property) > + return 0; > + > + if (tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC) || > + tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC_443) || > + tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC_J) || > + tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL_M)) { > + mode = drm_mode_analog_ntsc_480i(connector->dev); Nit: You can use the dev variable here and below. > + if (!mode) > + return 0; > + > + tv_modes[count++] = mode; > + } > + > + if (tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL) || > + tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL_N) || > + tv_mode_supported(connector, DRM_MODE_TV_MODE_SECAM)) { > + mode = drm_mode_analog_pal_576i(connector->dev); > + if (!mode) > + return 0; You leak the ntsc mode when returning (possibly). > + > + tv_modes[count++] = mode; > + } > + Maybe check for count being zero here? > + if (count == 1) { > + mode->type |= DRM_MODE_TYPE_PREFERRED; > + drm_mode_probed_add(connector, mode); > + return count; > + } > + > + ret = drm_object_property_get_default_value(&connector->base, > + > dev->mode_config.tv_mode_property, > + &default_mode); > + if (ret) > + return 0; You leak both modes when returning here. Maybe move this up before allocation to simplify error handling. > + > + if (cmdline->tv_mode_specified) > + default_mode = cmdline->tv_mode; I realised that we don't verify tv_mode coming from the command line, not here and not in the reset helper. Should we do that? A driver should be programmed defensively to handle an illegal/unsupported value, but it doesn't feel right to allow an illegal enum value coming through the core/helpers. > + > + if ((default_mode == DRM_MODE_TV_MODE_NTSC) || > + (default_mode == DRM_MODE_TV_MODE_NTSC_443) || > + (default_mode == DRM_MODE_TV_MODE_NTSC_J) || > + (default_mode == DRM_MODE_TV_MODE_PAL_M)) > + first_mode_idx = 0; > + else > + first_mode_idx = 1; > + > + mode = tv_modes[first_mode_idx]; > + mode->type |= DRM_MODE_TYPE_PRE
Re: [PATCH v6 16/23] drm/probe-helper: Provide a TV get_modes helper
Den 27.10.2022 00.02, skrev Mateusz Kwiatkowski: > Hi Maxime, > > First of all, nice idea with the helper function that can be reused by > different > drivers. This is neat! > > But looking at this function, it feels a bit overcomplicated. You're creating > the two modes, then checking which one is the default, then set the preferred > one and possibly reorder them. Maybe it can be simplified somehow? > > Although when I tried to refactor it myself, I ended up with something that's > not better at all. Maybe it needs to be complicated, after all :( > I also thought that the function was complicated/difficult to read, in particular the index stuff at the end, but I also failed in finding a "better" solution, just a different one ;) Noralf. My version: int drm_connector_helper_tv_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_property *tv_mode_property = dev->mode_config.tv_mode_property; struct drm_cmdline_mode *cmdline = &connector->cmdline_mode; unsigned int ntsc_modes = BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_NTSC_443) | BIT(DRM_MODE_TV_MODE_NTSC_J) | BIT(DRM_MODE_TV_MODE_PAL_M); unsigned int pal_modes = BIT(DRM_MODE_TV_MODE_PAL) | BIT(DRM_MODE_TV_MODE_PAL_N) | BIT(DRM_MODE_TV_MODE_SECAM); unsigned int tv_modes[2] = { UINT_MAX, UINT_MAX }; unsigned int i, supported_tv_modes = 0; if (!tv_mode_property) return 0; for (i = 0; i < tv_mode_property->num_values; i++) supported_tv_modes |= BIT(tv_mode_property->values[i]); if ((supported_tv_modes & ntsc_modes) && (supported_tv_modes & pal_modes)) { uint64_t default_mode; if (drm_object_property_get_default_value(&connector->base, tv_mode_property, &default_mode)) return 0; if (cmdline->tv_mode_specified) default_mode = cmdline->tv_mode; if (BIT(default_mode) & ntsc_modes) { tv_modes[0] = DRM_MODE_TV_MODE_NTSC; tv_modes[1] = DRM_MODE_TV_MODE_PAL; } else { tv_modes[0] = DRM_MODE_TV_MODE_PAL; tv_modes[1] = DRM_MODE_TV_MODE_NTSC; } } else if (supported_tv_modes & ntsc_modes) { tv_modes[0] = DRM_MODE_TV_MODE_NTSC; } else if (supported_tv_modes & pal_modes) { tv_modes[0] = DRM_MODE_TV_MODE_PAL; } else { return 0; } for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { struct drm_display_mode *mode; if (tv_modes[i] == DRM_MODE_TV_MODE_NTSC) mode = drm_mode_analog_ntsc_480i(dev); else if (tv_modes[i] == DRM_MODE_TV_MODE_PAL) mode = drm_mode_analog_pal_576i(dev); else break; if (!mode) return i; if (!i) mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); } return i; }
[PATCH AUTOSEL 6.0 01/30] drm/msm/gpu: Fix crash during system suspend after unbind
From: Akhil P Oommen [ Upstream commit 76efc2453d0e8e5d6692ef69981b183ad674edea ] In adreno_unbind, we should clean up gpu device's drvdata to avoid accessing a stale pointer during system suspend. Also, check for NULL ptr in both system suspend/resume callbacks. Signed-off-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/505075/ Link: https://lore.kernel.org/r/20220928124830.2.I5ee0ac073ccdeb81961e5ec0cce5f741a7207a71@changeid Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/adreno_device.c | 10 +- drivers/gpu/drm/msm/msm_gpu.c | 2 ++ drivers/gpu/drm/msm/msm_gpu.h | 4 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 24b489b6129a..628806423f7d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -679,6 +679,9 @@ static int adreno_system_suspend(struct device *dev) struct msm_gpu *gpu = dev_to_gpu(dev); int remaining, ret; + if (!gpu) + return 0; + suspend_scheduler(gpu); remaining = wait_event_timeout(gpu->retire_event, @@ -700,7 +703,12 @@ static int adreno_system_suspend(struct device *dev) static int adreno_system_resume(struct device *dev) { - resume_scheduler(dev_to_gpu(dev)); + struct msm_gpu *gpu = dev_to_gpu(dev); + + if (!gpu) + return 0; + + resume_scheduler(gpu); return pm_runtime_force_resume(dev); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c2bfcf3f1f40..01aae792ffa9 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -993,4 +993,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) } msm_devfreq_cleanup(gpu); + + platform_set_drvdata(gpu->pdev, NULL); } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 4d935fedd2ac..fd22cf4041af 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -282,6 +282,10 @@ struct msm_gpu { static inline struct msm_gpu *dev_to_gpu(struct device *dev) { struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev); + + if (!adreno_smmu) + return NULL; + return container_of(adreno_smmu, struct msm_gpu, adreno_smmu); } -- 2.35.1
[PATCH AUTOSEL 6.0 24/30] drm/amdgpu: Adjust MES polling timeout for sriov
From: Yiqing Yao [ Upstream commit 226dcfad349f23f7744d02b24f8ec3bc4f6198ac ] [why] MES response time in sriov may be longer than default value due to reset or init in other VF. A timeout value specific to sriov is needed. [how] When in sriov, adjust the timeout value to calculated worst case scenario. Signed-off-by: Yiqing Yao Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index f92744b8d79d..e758b4083874 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -96,7 +96,14 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, struct amdgpu_device *adev = mes->adev; struct amdgpu_ring *ring = &mes->ring; unsigned long flags; + signed long timeout = adev->usec_timeout; + if (amdgpu_emu_mode) { + timeout *= 100; + } else if (amdgpu_sriov_vf(adev)) { + /* Worst case in sriov where all other 15 VF timeout, each VF needs about 600ms */ + timeout = 15 * 600 * 1000; + } BUG_ON(size % 4 != 0); spin_lock_irqsave(&mes->ring_lock, flags); @@ -116,7 +123,7 @@ static int mes_v11_0_submit_pkt_and_poll_completion(struct amdgpu_mes *mes, DRM_DEBUG("MES msg=%d was emitted\n", x_pkt->header.opcode); r = amdgpu_fence_wait_polling(ring, ring->fence_drv.sync_seq, - adev->usec_timeout * (amdgpu_emu_mode ? 100 : 1)); + timeout); if (r < 1) { DRM_ERROR("MES failed to response msg=%d\n", x_pkt->header.opcode); -- 2.35.1
[PATCH AUTOSEL 6.0 27/30] drm/amd/display: Remove wrong pipe control lock
From: Rodrigo Siqueira [ Upstream commit ca08a1725d0d78efca8d2dbdbce5ea70355da0f2 ] When using a device based on DCN32/321, we have an issue where a second 4k@60Hz display does not light up, and the system becomes unresponsive for a few minutes. In the debug process, it was possible to see a hang in the function dcn20_post_unlock_program_front_end in this part: for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) mdelay(1); } The hubp_is_flip_pending always returns positive for waiting pending flips which is a symptom of pipe hang. Additionally, the dmesg log shows this message after a few minutes: BUG: soft lockup - CPU#4 stuck for 26s! ... [ +0.03] dcn20_post_unlock_program_front_end+0x112/0x340 [amdgpu] [ +0.000171] dc_commit_state_no_check+0x63d/0xbf0 [amdgpu] [ +0.000155] ? dc_validate_global_state+0x358/0x3d0 [amdgpu] [ +0.000154] dc_commit_state+0xe2/0xf0 [amdgpu] This confirmed the hypothesis that we had a pipe hanging somewhere. Next, after checking the ftrace entries, we have the below weird sequence: [..] 2) |dcn10_lock_all_pipes [amdgpu]() { 2) 0.120 us| optc1_is_tg_enabled [amdgpu](); 2) | dcn20_pipe_control_lock [amdgpu]() { 2) |dc_dmub_srv_clear_inbox0_ack [amdgpu]() { 2) 0.121 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.551 us|} 2) |dc_dmub_srv_send_inbox0_cmd [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.511 us|} 2) |dc_dmub_srv_wait_for_inbox0_ack [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); [..] We are not expected to read from dmub register so many times and for so long. From the trace log, it was possible to identify that the function dcn20_pipe_control_lock was triggering the dmub operation when it was unnecessary and causing the hang issue. This commit drops the unnecessary dmub code and, consequently, fixes the second display not lighting up the issue. Tested-by: Daniel Wheeler Acked-by: Qingqing Zhuo Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 12 +--- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 598ce872a8d7..0f30df523fdf 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1262,16 +1262,6 @@ void dcn20_pipe_control_lock( lock, &hw_locks, &inst_flags); - } else if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 }; - hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK; - hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER; - hw_lock_cmd.bits.lock_pipe = 1; - hw_lock_cmd.bits.otg_inst = pipe->stream_res.tg->inst; - hw_lock_cmd.bits.lock = lock; - if (!lock) - hw_lock_cmd.bits.should_release = 1; - dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd); } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { if (lock) pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); @@ -1848,7 +1838,7 @@ void dcn20_post_unlock_program_front_end( for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) - mdelay(1); + udelay(1); } } -- 2.35.1
[PATCH AUTOSEL 6.0 28/30] drm/amd/display: Don't return false if no stream
From: Alvin Lee [ Upstream commit abe4d9f03fae76c9650b0d942faf6990b35c377b ] pipe_ctx[i] exists even if the pipe is not in use. If the pipe is not in use it will always have a null stream, so don't return false in this case. Tested-by: Daniel Wheeler Reviewed-by: Rodrigo Siqueira Acked-by: Qingqing Zhuo Signed-off-by: Alvin Lee Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c index 1f195c5b3377..13cd1f2e50ca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c @@ -187,7 +187,7 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc, struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->stream) - return false; + continue; if (!pipe->plane_state) return false; -- 2.35.1
[PATCH AUTOSEL 6.0 29/30] drm/scheduler: fix fence ref counting
From: Christian König [ Upstream commit b3af84383e7abdc5e63435817bb73a268e7c3637 ] We leaked dependency fences when processes were beeing killed. Additional to that grab a reference to the last scheduled fence. Signed-off-by: Christian König Reviewed-by: Andrey Grodzovsky Link: https://patchwork.freedesktop.org/patch/msgid/20220929180151.139751-1-christian.koe...@amd.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/scheduler/sched_entity.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 6b25b2f4f5a3..7ef1a086a6fb 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -207,6 +207,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, struct drm_sched_job *job = container_of(cb, struct drm_sched_job, finish_cb); + dma_fence_put(f); INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); schedule_work(&job->work); } @@ -234,8 +235,10 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) struct drm_sched_fence *s_fence = job->s_fence; /* Wait for all dependencies to avoid data corruptions */ - while ((f = drm_sched_job_dependency(job, entity))) + while ((f = drm_sched_job_dependency(job, entity))) { dma_fence_wait(f, false); + dma_fence_put(f); + } drm_sched_fence_scheduled(s_fence); dma_fence_set_error(&s_fence->finished, -ESRCH); @@ -250,6 +253,7 @@ static void drm_sched_entity_kill_jobs(struct drm_sched_entity *entity) continue; } + dma_fence_get(entity->last_scheduled); r = dma_fence_add_callback(entity->last_scheduled, &job->finish_cb, drm_sched_entity_kill_jobs_cb); -- 2.35.1
[PATCH AUTOSEL 5.15 17/18] drm/amd/display: Remove wrong pipe control lock
From: Rodrigo Siqueira [ Upstream commit ca08a1725d0d78efca8d2dbdbce5ea70355da0f2 ] When using a device based on DCN32/321, we have an issue where a second 4k@60Hz display does not light up, and the system becomes unresponsive for a few minutes. In the debug process, it was possible to see a hang in the function dcn20_post_unlock_program_front_end in this part: for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) mdelay(1); } The hubp_is_flip_pending always returns positive for waiting pending flips which is a symptom of pipe hang. Additionally, the dmesg log shows this message after a few minutes: BUG: soft lockup - CPU#4 stuck for 26s! ... [ +0.03] dcn20_post_unlock_program_front_end+0x112/0x340 [amdgpu] [ +0.000171] dc_commit_state_no_check+0x63d/0xbf0 [amdgpu] [ +0.000155] ? dc_validate_global_state+0x358/0x3d0 [amdgpu] [ +0.000154] dc_commit_state+0xe2/0xf0 [amdgpu] This confirmed the hypothesis that we had a pipe hanging somewhere. Next, after checking the ftrace entries, we have the below weird sequence: [..] 2) |dcn10_lock_all_pipes [amdgpu]() { 2) 0.120 us| optc1_is_tg_enabled [amdgpu](); 2) | dcn20_pipe_control_lock [amdgpu]() { 2) |dc_dmub_srv_clear_inbox0_ack [amdgpu]() { 2) 0.121 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.551 us|} 2) |dc_dmub_srv_send_inbox0_cmd [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.511 us|} 2) |dc_dmub_srv_wait_for_inbox0_ack [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); [..] We are not expected to read from dmub register so many times and for so long. From the trace log, it was possible to identify that the function dcn20_pipe_control_lock was triggering the dmub operation when it was unnecessary and causing the hang issue. This commit drops the unnecessary dmub code and, consequently, fixes the second display not lighting up the issue. Tested-by: Daniel Wheeler Acked-by: Qingqing Zhuo Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 0de1bbbabf9a..58eea3aa3bfc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1765,7 +1765,7 @@ void dcn20_post_unlock_program_front_end( for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) - mdelay(1); + udelay(1); } } -- 2.35.1
[PATCH AUTOSEL 5.10 16/16] drm/amd/display: Remove wrong pipe control lock
From: Rodrigo Siqueira [ Upstream commit ca08a1725d0d78efca8d2dbdbce5ea70355da0f2 ] When using a device based on DCN32/321, we have an issue where a second 4k@60Hz display does not light up, and the system becomes unresponsive for a few minutes. In the debug process, it was possible to see a hang in the function dcn20_post_unlock_program_front_end in this part: for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) mdelay(1); } The hubp_is_flip_pending always returns positive for waiting pending flips which is a symptom of pipe hang. Additionally, the dmesg log shows this message after a few minutes: BUG: soft lockup - CPU#4 stuck for 26s! ... [ +0.03] dcn20_post_unlock_program_front_end+0x112/0x340 [amdgpu] [ +0.000171] dc_commit_state_no_check+0x63d/0xbf0 [amdgpu] [ +0.000155] ? dc_validate_global_state+0x358/0x3d0 [amdgpu] [ +0.000154] dc_commit_state+0xe2/0xf0 [amdgpu] This confirmed the hypothesis that we had a pipe hanging somewhere. Next, after checking the ftrace entries, we have the below weird sequence: [..] 2) |dcn10_lock_all_pipes [amdgpu]() { 2) 0.120 us| optc1_is_tg_enabled [amdgpu](); 2) | dcn20_pipe_control_lock [amdgpu]() { 2) |dc_dmub_srv_clear_inbox0_ack [amdgpu]() { 2) 0.121 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.551 us|} 2) |dc_dmub_srv_send_inbox0_cmd [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_write [amdgpu](); 2) 0.511 us|} 2) |dc_dmub_srv_wait_for_inbox0_ack [amdgpu]() { 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); 2) 0.110 us| amdgpu_dm_dmub_reg_read [amdgpu](); [..] We are not expected to read from dmub register so many times and for so long. From the trace log, it was possible to identify that the function dcn20_pipe_control_lock was triggering the dmub operation when it was unnecessary and causing the hang issue. This commit drops the unnecessary dmub code and, consequently, fixes the second display not lighting up the issue. Tested-by: Daniel Wheeler Acked-by: Qingqing Zhuo Signed-off-by: Rodrigo Siqueira Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 8f66eef0c683..c6c4888c6665 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1746,7 +1746,7 @@ void dcn20_post_unlock_program_front_end( for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000 && hubp->funcs->hubp_is_flip_pending(hubp); j++) - mdelay(1); + udelay(1); } } -- 2.35.1
[RFC PATCH v3 0/3] new subsystem for compute accelerator devices
This is the third version of the RFC following the comments given on the second version, but more importantly, following testing done by the VPU driver people and myself. We found out that there is a circular dependency between DRM and accel. DRM calls accel exported symbols during init and when accel devices are registering (all the minor handling), then accel calls DRM exported symbols. Therefore, if the two components are compiled as modules, there is a circular dependency. To overcome this, I have decided to compile the accel core code as part of the DRM kernel module (drm.ko). IMO, this is inline with the spirit of the design choice to have accel reuse the DRM core code and avoid code duplication. Another important change is that I have reverted back to use IDR for minor handling instead of xarray. This is because I have found that xarray doesn't handle well the scenario where you allocate a NULL entry and then exchange it with a real pointer. It appears xarray still considers that entry a "zero" entry. This is unfortunate because DRM works that way (first allocates a NULL entry and then replaces the entry with a real pointer). I decided to revert to IDR because I don't want to hold up these patches, as many people are blocked until the support for accel is merged. The xarray issue should be fixed as a separate patch by either fixing the xarray code or changing how DRM + ACCEL do minor id handling. The patches are in the following repo: https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git/log/?h=accel_v3 As in v2, The HEAD of that branch is a commit adding a dummy driver that registers an accel device using the new framework. This can be served as a simple reference. I have checked inserting and removing the dummy driver, and opening and closing /dev/accel/accel0 and nothing got broken :) v1 cover letter: https://lkml.org/lkml/2022/10/22/544 v2 cover letter: https://lore.kernel.org/lkml/20221102203405.1797491-1-ogab...@kernel.org/T/ Thanks, Oded. Oded Gabbay (3): drivers/accel: define kconfig and register a new major accel: add dedicated minor for accelerator devices drm: initialize accel framework Documentation/admin-guide/devices.txt | 5 + MAINTAINERS | 8 + drivers/Kconfig | 2 + drivers/accel/Kconfig | 24 ++ drivers/accel/drm_accel.c | 322 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_drv.c | 102 +--- drivers/gpu/drm/drm_file.c| 2 +- drivers/gpu/drm/drm_sysfs.c | 24 +- include/drm/drm_accel.h | 97 include/drm/drm_device.h | 3 + include/drm/drm_drv.h | 8 + include/drm/drm_file.h| 21 +- 13 files changed, 582 insertions(+), 37 deletions(-) create mode 100644 drivers/accel/Kconfig create mode 100644 drivers/accel/drm_accel.c create mode 100644 include/drm/drm_accel.h -- 2.25.1
[RFC PATCH v3 1/3] drivers/accel: define kconfig and register a new major
Add a new Kconfig for the accel subsystem. The Kconfig currently contains only the basic CONFIG_DRM_ACCEL option that will be used to decide whether to compile the accel registration code. Therefore, the kconfig option is defined as bool. The accel code will be compiled as part of drm.ko and will be called directly from the DRM core code. The reason we compile it as part of drm.ko and not as a separate module is because of cyclic dependency between drm.ko and the separate module (if it would have existed). This is due to the fact that DRM core code calls accel functions and vice-versa. The accelerator devices will be exposed to the user space with a new, dedicated major number - 261. The accel init function registers the new major number as a char device and create corresponding sysfs and debugfs root entries, similar to what is done in DRM init function. I added a new header called drm_accel.h to include/drm/, that will hold the prototypes of the drm_accel.c functions. In case CONFIG_DRM_ACCEL is set to 'N', that header will contain empty inline implementations of those functions, to allow DRM core code to compile successfully without dependency on CONFIG_DRM_ACCEL. I Updated the MAINTAINERS file accordingly with the newly added folder and I have taken the liberty to appropriate the dri-devel mailing list and the dri-devel IRC channel for the accel subsystem. Signed-off-by: Oded Gabbay --- Changes in v3: - Remove accel kernel module and build the code as part of drm.ko. - Rename CONFIG_ACCEL to CONFIG_DRM_ACCEL as the code is built as part of drm.ko. - Rename accel_drv.c to drm_accel.c - Change kconfig option to be bool instead of tristate - Add . at end of help text in kconfig Documentation/admin-guide/devices.txt | 5 ++ MAINTAINERS | 8 +++ drivers/Kconfig | 2 + drivers/accel/Kconfig | 24 drivers/accel/drm_accel.c | 82 +++ drivers/gpu/drm/Makefile | 1 + include/drm/drm_accel.h | 31 ++ 7 files changed, 153 insertions(+) create mode 100644 drivers/accel/Kconfig create mode 100644 drivers/accel/drm_accel.c create mode 100644 include/drm/drm_accel.h diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index 9764d6edb189..06c525e01ea5 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -3080,6 +3080,11 @@ ... 255 = /dev/osd255 256th OSD Device + 261 char Compute Acceleration Devices + 0 = /dev/accel/accel0 First acceleration device + 1 = /dev/accel/accel1 Second acceleration device + ... + 384-511 char RESERVED FOR DYNAMIC ASSIGNMENT Character devices that request a dynamic allocation of major number will take numbers starting from 511 and downward, diff --git a/MAINTAINERS b/MAINTAINERS index 30e3df70daec..5b07d81c985e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6825,6 +6825,14 @@ F: include/drm/drm* F: include/linux/vga* F: include/uapi/drm/drm* +DRM COMPUTE ACCELERATORS DRIVERS AND FRAMEWORK +M: Oded Gabbay +L: dri-devel@lists.freedesktop.org +S: Maintained +C: irc://irc.oftc.net/dri-devel +T: git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/accel.git +F: drivers/accel/ + DRM DRIVERS FOR ALLWINNER A10 M: Maxime Ripard M: Chen-Yu Tsai diff --git a/drivers/Kconfig b/drivers/Kconfig index 19ee995bd0ae..968bd0a6fd78 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -99,6 +99,8 @@ source "drivers/media/Kconfig" source "drivers/video/Kconfig" +source "drivers/accel/Kconfig" + source "sound/Kconfig" source "drivers/hid/Kconfig" diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig new file mode 100644 index ..c9ce849b2984 --- /dev/null +++ b/drivers/accel/Kconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Compute Acceleration device configuration +# +# This framework provides support for compute acceleration devices, such +# as, but not limited to, Machine-Learning and Deep-Learning acceleration +# devices +# +menuconfig DRM_ACCEL + bool "Compute Acceleration Framework" + depends on DRM + help + Framework for device drivers of compute acceleration devices, such + as, but not limited to, Machine-Learning and Deep-Learning + acceleration devices. + If you say Y here, you need to select the module that's right for + your acceleration device from the list below. + This framework is integrated with the DRM subsystem as compute + accelerators and GPUs share a lot in common and can use almost the + same infrastructure code. + Having said that, acceleration devices will have a different + major number than GPUs, and will be e
[RFC PATCH v3 3/3] drm: initialize accel framework
Now that we have the accel framework code ready, let's call the accel functions from all the appropriate places. These places are the drm module init/exit functions, and all the drm_minor handling functions. Signed-off-by: Oded Gabbay --- Changes in v3: - Call the new accel_debugfs_init() to initalize debugfs per minor. - accel_minor_replace() is void so no need to check return value. drivers/gpu/drm/drm_drv.c | 102 ++-- drivers/gpu/drm/drm_sysfs.c | 24 ++--- 2 files changed, 91 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 8214a0b1ab7f..1aec019f6389 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,8 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, return &dev->primary; case DRM_MINOR_RENDER: return &dev->render; + case DRM_MINOR_ACCEL: + return &dev->accel; default: BUG(); } @@ -104,9 +107,13 @@ static void drm_minor_alloc_release(struct drm_device *dev, void *data) put_device(minor->kdev); - spin_lock_irqsave(&drm_minor_lock, flags); - idr_remove(&drm_minors_idr, minor->index); - spin_unlock_irqrestore(&drm_minor_lock, flags); + if (minor->type == DRM_MINOR_ACCEL) { + accel_minor_remove(minor->index); + } else { + spin_lock_irqsave(&drm_minor_lock, flags); + idr_remove(&drm_minors_idr, minor->index); + spin_unlock_irqrestore(&drm_minor_lock, flags); + } } static int drm_minor_alloc(struct drm_device *dev, unsigned int type) @@ -123,13 +130,17 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type) minor->dev = dev; idr_preload(GFP_KERNEL); - spin_lock_irqsave(&drm_minor_lock, flags); - r = idr_alloc(&drm_minors_idr, - NULL, - 64 * type, - 64 * (type + 1), - GFP_NOWAIT); - spin_unlock_irqrestore(&drm_minor_lock, flags); + if (type == DRM_MINOR_ACCEL) { + r = accel_minor_alloc(); + } else { + spin_lock_irqsave(&drm_minor_lock, flags); + r = idr_alloc(&drm_minors_idr, + NULL, + 64 * type, + 64 * (type + 1), + GFP_NOWAIT); + spin_unlock_irqrestore(&drm_minor_lock, flags); + } idr_preload_end(); if (r < 0) @@ -161,10 +172,14 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) if (!minor) return 0; - ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); - if (ret) { - DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); - goto err_debugfs; + if (minor->type == DRM_MINOR_ACCEL) { + accel_debugfs_init(minor, minor->index); + } else { + ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root); + if (ret) { + DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n"); + goto err_debugfs; + } } ret = device_add(minor->kdev); @@ -172,9 +187,13 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type) goto err_debugfs; /* replace NULL with @minor so lookups will succeed from now on */ - spin_lock_irqsave(&drm_minor_lock, flags); - idr_replace(&drm_minors_idr, minor, minor->index); - spin_unlock_irqrestore(&drm_minor_lock, flags); + if (minor->type == DRM_MINOR_ACCEL) { + accel_minor_replace(minor, minor->index); + } else { + spin_lock_irqsave(&drm_minor_lock, flags); + idr_replace(&drm_minors_idr, minor, minor->index); + spin_unlock_irqrestore(&drm_minor_lock, flags); + } DRM_DEBUG("new minor registered %d\n", minor->index); return 0; @@ -194,9 +213,13 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type) return; /* replace @minor with NULL so lookups will fail from now on */ - spin_lock_irqsave(&drm_minor_lock, flags); - idr_replace(&drm_minors_idr, NULL, minor->index); - spin_unlock_irqrestore(&drm_minor_lock, flags); + if (minor->type == DRM_MINOR_ACCEL) { + accel_minor_replace(NULL, minor->index); + } else { + spin_lock_irqsave(&drm_minor_lock, flags); + idr_replace(&drm_minors_idr, NULL, minor->index); + spin_unlock_irqrestore(&drm_minor_lock, flags); + } device_del(minor->kdev); dev_set_drvdata(minor->kdev, NULL)
[RFC PATCH v3 2/3] accel: add dedicated minor for accelerator devices
The accelerator devices are exposed to user-space using a dedicated major. In addition, they are represented in /dev with new, dedicated device char names: /dev/accel/accel*. This is done to make sure any user-space software that tries to open a graphic card won't open the accelerator device by mistake. The above implies that the minor numbering should be separated from the rest of the DRM devices. However, to avoid code duplication, we want the drm_minor structure to be able to represent the accelerator device. To achieve this, we add a new drm_minor* to drm_device that represents the accelerator device. This pointer is initialized for drivers that declare they handle compute accelerator, using a new driver feature flag called DRIVER_COMPUTE_ACCEL. It is important to note that this driver feature is mutually exclusive with DRIVER_RENDER. Devices that want to expose both graphics and compute device char files should be handled by two drivers that are connected using the auxiliary bus framework. In addition, we define a different IDR to handle the accelerators minors. This is done to make the minor's index be identical to the device index in /dev/. Any access to the IDR is done solely by functions in accel_drv.c, as the IDR is define as static. The DRM core functions call those functions in case they detect the minor's type is DRM_MINOR_ACCEL. We define a separate accel_open function (from drm_open) that the accel drivers should set as their open callback function. Both these functions eventually call the same drm_open_helper(), which had to be changed to be non-static so it can be called from accel_drv.c. accel_open() only partially duplicates drm_open as I removed some code from it that handles legacy devices. To help new drivers, I defined DEFINE_DRM_ACCEL_FOPS macro to easily set the required function operations pointers structure. Signed-off-by: Oded Gabbay --- Changes in v3: - Remove useless DRM_DEBUG("\n") at accel_stub_open() - Add function of accel_debugfs_init() as accel_debugfs_root is static member in drm_accel.c - Add DRM_ACCEL_FOPS and DEFINE_DRM_ACCEL_FOPS macros - Replace minor handling from xarray back to idr, as xarray doesn't handle well exchanging content of a NULL entry to non-NULL. This should be handled in a different patch that will either fix xarray code or change DRM minor init flow. - Make accel_minor_replace() to return void. drivers/accel/drm_accel.c | 242 - drivers/gpu/drm/drm_file.c | 2 +- include/drm/drm_accel.h| 68 ++- include/drm/drm_device.h | 3 + include/drm/drm_drv.h | 8 ++ include/drm/drm_file.h | 21 +++- 6 files changed, 340 insertions(+), 4 deletions(-) diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index 943d960ddefc..05167c929866 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -8,14 +8,25 @@ #include #include +#include #include +#include +#include +#include #include #include +static DEFINE_SPINLOCK(accel_minor_lock); +static struct idr accel_minors_idr; + static struct dentry *accel_debugfs_root; static struct class *accel_class; +static struct device_type accel_sysfs_device_minor = { + .name = "accel_minor" +}; + static char *accel_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "accel/%s", dev_name(dev)); @@ -40,9 +51,235 @@ static void accel_sysfs_destroy(void) accel_class = NULL; } +static int accel_name_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_minor *minor = node->minor; + struct drm_device *dev = minor->dev; + struct drm_master *master; + + mutex_lock(&dev->master_mutex); + master = dev->master; + seq_printf(m, "%s", dev->driver->name); + if (dev->dev) + seq_printf(m, " dev=%s", dev_name(dev->dev)); + if (master && master->unique) + seq_printf(m, " master=%s", master->unique); + if (dev->unique) + seq_printf(m, " unique=%s", dev->unique); + seq_puts(m, "\n"); + mutex_unlock(&dev->master_mutex); + + return 0; +} + +static const struct drm_info_list accel_debugfs_list[] = { + {"name", accel_name_info, 0} +}; +#define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list) + +/** + * accel_debugfs_init() - Initialize debugfs for accel minor + * @minor: Pointer to the drm_minor instance. + * @minor_id: The minor's id + * + * This function initializes the drm minor's debugfs members and creates + * a root directory for the minor in debugfs. It also creates common files + * for accelerators and calls the driver's debugfs init callback. + */ +void accel_debugfs_init(struct drm_minor *minor, int minor_id) +{ + struct drm_device *dev = minor->dev; + char name[64]; + + INIT_LIST_HEAD(&minor->debugfs_list); + mutex_init(&minor->debug
[PATCH v6a 0/5] timers: Use timer_shutdown*() before freeing timers
del_timer_sync() is often called before the object that owns the timer is freed. But sometimes there's a race that enables the timer again before it is freed and causes a use after free when that timer triggers. This patch set adds a new "shutdown" timer state, which is set on the new timer_shutdown() API. Once a timer is in this state, it can not be re-armed and if it is, it will warn. The first three patches change existing timer_shutdown() functions used locally in ARM and some drivers to better namespace names. The fourth patch implements the new API. The fifth patch is now a treewide patch that uses a coccinelle script to convert the trivial locations where a del_timer*() is called on a timer of an object that is freed immediately afterward (or at least in the same function). Changes since v5a: https://lore.kernel.org/all/20221106054535.709068...@goodmis.org/ - Updated the script to make ptr and slab into expressions instead of using identifiers (Julia Lawall and Linus Torvalds) Steven Rostedt (Google) (5): ARM: spear: Do not use timer namespace for timer_shutdown() function clocksource/drivers/arm_arch_timer: Do not use timer namespace for timer_shutdown() function clocksource/drivers/sp804: Do not use timer namespace for timer_shutdown() function timers: Add timer_shutdown_sync() and timer_shutdown() to be called before freeing timers treewide: Convert del_timer*() to timer_shutdown*() .../RCU/Design/Requirements/Requirements.rst | 2 +- Documentation/core-api/local_ops.rst | 2 +- Documentation/kernel-hacking/locking.rst | 5 ++ arch/arm/mach-spear/time.c | 8 +-- arch/sh/drivers/push-switch.c | 2 +- block/blk-iocost.c | 2 +- block/blk-iolatency.c | 2 +- block/kyber-iosched.c | 2 +- drivers/acpi/apei/ghes.c | 2 +- drivers/atm/idt77252.c | 6 +- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/loop.c | 2 +- drivers/bluetooth/hci_bcsp.c | 2 +- drivers/bluetooth/hci_qca.c| 4 +- drivers/clocksource/arm_arch_timer.c | 12 ++-- drivers/clocksource/timer-sp804.c | 6 +- drivers/gpu/drm/i915/i915_sw_fence.c | 2 +- drivers/hid/hid-wiimote-core.c | 2 +- drivers/input/keyboard/locomokbd.c | 2 +- drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/mouse/alps.c | 2 +- drivers/isdn/mISDN/l1oip_core.c| 4 +- drivers/isdn/mISDN/timerdev.c | 4 +- drivers/leds/trigger/ledtrig-activity.c| 2 +- drivers/leds/trigger/ledtrig-heartbeat.c | 2 +- drivers/leds/trigger/ledtrig-pattern.c | 2 +- drivers/leds/trigger/ledtrig-transient.c | 2 +- drivers/media/pci/ivtv/ivtv-driver.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.c| 16 +++--- drivers/media/usb/s2255/s2255drv.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_main.c| 6 +- drivers/net/ethernet/marvell/sky2.c| 2 +- drivers/net/ethernet/sun/sunvnet.c | 2 +- drivers/net/usb/sierra_net.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_ap.c | 2 +- drivers/net/wireless/marvell/mwifiex/main.c| 2 +- drivers/net/wireless/microchip/wilc1000/hif.c | 6 +- drivers/nfc/pn533/pn533.c | 2 +- drivers/nfc/pn533/uart.c | 2 +- drivers/pcmcia/bcm63xx_pcmcia.c| 2 +- drivers/pcmcia/electra_cf.c| 2 +- drivers/pcmcia/omap_cf.c | 2 +- drivers/pcmcia/pd6729.c| 4 +- drivers/pcmcia/yenta_socket.c | 4 +- drivers/scsi/qla2xxx/qla_edif.c| 4 +- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 2 +- drivers/tty/n_gsm.c| 2 +- drivers/tty/sysrq.c| 2 +- drivers/usb/gadget/udc/m66592-udc.c| 2 +- drivers/usb/serial/garmin_gps.c| 2 +- drivers/usb/serial/mos7840.c | 4 +- fs/ext4/super.c| 2 +- fs/nilfs2/segment.c| 2 +- include/linux/timer.h | 62 +++-- kernel/time/timer.c| 64 -- net/80
[PATCH] drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
Like the Acer Switch One 10 S1003, for which there already is a quirk, the Acer Switch V 10 (SW5-017) has a 800x1280 portrait screen mounted in the tablet part of a landscape oriented 2-in-1. Add a quirk for this. Cc: Rudolf Polzer Signed-off-by: Hans de Goede --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index f0f6fa306521..52d8800a8ab8 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -134,6 +134,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"), }, .driver_data = (void *)&lcd800x1280_rightside_up, + }, {/* Acer Switch V 10 (SW5-017) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, }, {/* Anbernic Win600 */ .matches = { DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic"), -- 2.37.3
Re: [Intel-gfx] [PATCH v5 5/7] drm/i915/gt: Create per-tile RC6 sysfs interface
On Tue, 22 Feb 2022 00:57:02 -0800, Andi Shyti wrote: > Old thread, new comment below at the bottom. Please take a look. Thanks. > Hi Tvrtko and Joonas, > > > > > > > Now tiles have their own sysfs interfaces under the gt/ > > > > > > directory. Because RC6 is a property that can be configured on a > > > > > > tile basis, then each tile should have its own interface > > > > > > > > > > > > The new sysfs structure will have a similar layout for the 4 tile > > > > > > case: > > > > > > > > > > > > /sys/.../card0 > > > > > >\u251c\u2500\u2500 gt > > > > > >\u2502 \u251c\u2500\u2500 gt0 > > > > > >\u2502 \u2502 \u251c\u2500\u2500 id > > > > > >\u2502 \u2502 \u251c\u2500\u2500 rc6_enable > > > > > >\u2502 \u2502 \u251c\u2500\u2500 rc6_residency_ms > > > > > >. . . > > > > > >. . . > > > > > >. . > > > > > >\u2502 \u2514\u2500\u2500 gtN > > > > > >\u2502 \u251c\u2500\u2500 id > > > > > >\u2502 \u251c\u2500\u2500 rc6_enable > > > > > >\u2502 \u251c\u2500\u2500 rc6_residency_ms > > > > > >\u2502 . > > > > > >\u2502 . > > > > > >\u2502 > > > > > >\u2514\u2500\u2500 power/-+ > > > > > > \u251c\u2500\u2500 rc6_enable|Original > > > > > > interface > > > > > > \u251c\u2500\u2500 rc6_residency_ms +-> kept as > > > > > > existing ABI; > > > > > > . |it multiplexes over > > > > > > . |the GTs > > > > > > -+ > > > > > > > > > > > > The existing interfaces have been kept in their original location > > > > > > to preserve the existing ABI. They act on all the GTs: when > > > > > > reading they provide the average value from all the GTs. > > > > > > > > > > Average feels very odd to me. I'd ask if we can get away providing an > > > > > errno > > > > > instead? Or tile zero data? > > > > > > Tile zero data is always wrong, in my opinion. If we have round-robin > > > scaling workloads like some media cases, part of the system load might > > > just disappear when it goes to tile 1. > > > > I was thinking that in conjunction with deprecated log message it wouldn't > > be wrong - I mean if the route take was to eventually retire the legacy > > files altogether. > > that's a good point... do we want to treat the legacy interfaces > as an error or do we want to make them a feature? As the > discussion is turning those interfaces are becoming a feature. > But what are we going to do with the coming interfaces? > > E.g. in the future we will have the rc6_enable/disable that can > be a command, so that we will add the "_store" interface per > tile. What are we going to do with the above interfaces? Are we > going to add a multiplexed command as well? > > > > When we have frequency readbacks without control, returning MAX() across > > > tiles would be the logical thing. The fact that parts of the hardware can > > > be clocked lower when one part is fully utilized is the "new feature". > > > > > > After that we're only really left with the rc6_residency_ms. And that is > > > the tough one. I'm inclined that MIN() across tiles would be the right > > > answer. If you are fully utilizing a single tile, you should be able to > > > see it. > > > So we have MIN, AVG or SUM, or errno, or remove the file (which is > > just a different kind of errno?) to choose from. :) > > in this case it would just be MIN and MAX. At the end we have > here only two types of interface: frequencies and residency_ms. > For the first type we would use 'max', for the second 'min'. We have the comment below from Lowren about this about showing MAX for freq. Could someone reply. Thanks. On Sun, 06 Nov 2022 08:54:04 -0800, Lawson, Lowren H wrote: Why show maximum? Wouldn’t average be more accurate to the user experience? As a user, I expect the ‘card’ frequency to be relatively accurate to the entire card. If I see 1.6GHz, but the card is behaving as if it’s running a 1.0 & 1.6GHz on the different compute tiles, I’m going to see a massive decrease in compute workload performance while at ‘maximum’ frequency.
Re: [PATCH 1/2] drm/radeon: Using unsigned long instead of unsigned to fix possible overflow
On 2022/11/5 2:31, Alex Deucher wrote: On Fri, Nov 4, 2022 at 6:05 AM Hanjun Guo wrote: VBIOSImageOffset in struct UEFI_ACPI_VFCT is ULONG (unsigned long), but it will be assigned to "unsigned offset", so use unsigned long instead of unsigned for the offset, to avoid possible overflow. ULONG in atombios is 32 bits so an int should be fine. I saw the typedef in the atombios.h is unsigned long but I missed that the real one is uint32_t in atom-types.h, please drop this patch and take a look at the PATCH 2/2. Thanks for the prompt reply. Thanks Hanjun
Re: (subset) [PATCH 0/2] arm: dts: qcom: rename HDMI PHY nodes
On Sat, 24 Sep 2022 12:43:45 +0300, Dmitry Baryshkov wrote: > Historically HDMI PHY device tree nodes used the hdmi-phy@ names. > Replace them with generic phy@ names. > > While there is no such requirement in the DT schema, it's worth doing > that because: > > 1) The recent qcom DT files already use just phy@ for most of PHY nodes > > [...] Applied, thanks! [1/2] ARM: dts: qcom-apq8064: change HDMI PHY node name to generic one commit: 5743efe0e73e4e1c8d042e982e31bb8145e35baf Best regards, -- Bjorn Andersson
Re: [PATCH] dt-bindings: qcom: add another exception to the device naming rule
On Fri, 4 Nov 2022 16:23:16 +0300, Dmitry Baryshkov wrote: > The 'qcom,dsi-ctrl-6g-qcm2290' compatibility string was added in the > commit ee1f09678f14 ("drm/msm/dsi: Add support for qcm2290 dsi > controller") in February 2022, but was not properly documented in the > bindings. Adding this compatibility string to > display/msm/dsi-controller-main.yaml caused a warning from > qcom-soc.yaml. Fix the warning by adding an exception to the mentioned > file. > > [...] Applied, thanks! [1/1] dt-bindings: qcom: add another exception to the device naming rule commit: 965a6d823a0476f9500216f1855bb8fcc6b73551 Best regards, -- Bjorn Andersson
linux-next: build warning after merge of the drm tree
Hi all, After merging the drm tree, today's linux-next build (KCONFIG_NAME) produced this warning: drivers/gpu/drm/i915/i915_perf_types.h:319: warning: Function parameter or member 'lock' not described in 'i915_perf_stream' Introduced by commit 2db609c01495 ("drm/i915/perf: Replace gt->perf.lock with stream->lock for file ops") -- Cheers, Stephen Rothwell pgpmejOgp0lKx.pgp Description: OpenPGP digital signature
[GIT PULL] treewide: timers: Use timer_shutdown*() before freeing timers
Linus, As discussed here: https://lore.kernel.org/all/20221106212427.739928...@goodmis.org/ Add a "shutdown" state for timers. This is performed by the new timer_shutdown_sync() and timer_shutdown() function calls. When this is called on a timer, it will no longer be able to be re-armed. This should be called before a timer is freed to prevent it from being re-armed after being removed from the timer queue and then causing a crash in the timer code when the timer triggers. This required renaming some functions that were using the name timer_shutdown() statically to something more appropriate. Then a coccinelle script was executed on the entire kernel tree to find the trivial locations that remove the timer and then frees the object that the timer exists on. These changes are not enough to solve all the locations where timers may be of an issue. But by adding the shutdown infrastructure and the obvious cases, the more complex cases can be added after they have been reviewed more closely. Please pull the following tree, which can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git add-timer-shutdown Tag SHA1: 7685328352dfd2908e23048f563e328dbd3526e9 Head SHA1: 870556da63870e01ade9bb8418ac5a21862f2f10 Steven Rostedt (Google) (5): ARM: spear: Do not use timer namespace for timer_shutdown() function clocksource/drivers/arm_arch_timer: Do not use timer namespace for timer_shutdown() function clocksource/drivers/sp804: Do not use timer namespace for timer_shutdown() function timers: Add timer_shutdown_sync() and timer_shutdown() to be called before freeing timers treewide: Convert del_timer*() to timer_shutdown*() .../RCU/Design/Requirements/Requirements.rst | 2 +- Documentation/core-api/local_ops.rst | 2 +- Documentation/kernel-hacking/locking.rst | 5 ++ arch/arm/mach-spear/time.c | 8 +-- arch/sh/drivers/push-switch.c | 2 +- block/blk-iocost.c | 2 +- block/blk-iolatency.c | 2 +- block/kyber-iosched.c | 2 +- drivers/acpi/apei/ghes.c | 2 +- drivers/atm/idt77252.c | 6 +- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/loop.c | 2 +- drivers/bluetooth/hci_bcsp.c | 2 +- drivers/bluetooth/hci_qca.c| 4 +- drivers/clocksource/arm_arch_timer.c | 12 ++-- drivers/clocksource/timer-sp804.c | 6 +- drivers/gpu/drm/i915/i915_sw_fence.c | 2 +- drivers/hid/hid-wiimote-core.c | 2 +- drivers/input/keyboard/locomokbd.c | 2 +- drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/mouse/alps.c | 2 +- drivers/isdn/mISDN/l1oip_core.c| 4 +- drivers/isdn/mISDN/timerdev.c | 4 +- drivers/leds/trigger/ledtrig-activity.c| 2 +- drivers/leds/trigger/ledtrig-heartbeat.c | 2 +- drivers/leds/trigger/ledtrig-pattern.c | 2 +- drivers/leds/trigger/ledtrig-transient.c | 2 +- drivers/media/pci/ivtv/ivtv-driver.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.c| 16 +++--- drivers/media/usb/s2255/s2255drv.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_main.c| 6 +- drivers/net/ethernet/marvell/sky2.c| 2 +- drivers/net/ethernet/sun/sunvnet.c | 2 +- drivers/net/usb/sierra_net.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_ap.c | 2 +- drivers/net/wireless/marvell/mwifiex/main.c| 2 +- drivers/net/wireless/microchip/wilc1000/hif.c | 6 +- drivers/nfc/pn533/pn533.c | 2 +- drivers/nfc/pn533/uart.c | 2 +- drivers/pcmcia/bcm63xx_pcmcia.c| 2 +- drivers/pcmcia/electra_cf.c| 2 +- drivers/pcmcia/omap_cf.c | 2 +- drivers/pcmcia/pd6729.c| 4 +- drivers/pcmcia/yenta_socket.c | 4 +- drivers/scsi/qla2xxx/qla_edif.c| 4 +- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 2 +- drivers/tty/n_gsm.c| 2 +- drivers/tty/sysrq.c| 2 +- drivers/usb/gadget/udc/m66592-udc.c| 2 +- drivers/usb/serial/garmin_gps.c| 2 +- drivers/usb/serial/mos7840.c | 4 +- fs/ext4/super.c
linux-next: build warning after merge of the drm-misc tree
Hi all, After merging the drm-misc tree, today's linux-next build (htmldocs) produced this warning: include/drm/drm_fb_helper.h:204: warning: Function parameter or member 'hint_leak_smem_start' not described in 'drm_fb_helper' Introduced by commit e7c5c29a9eb1 ("drm/fb-helper: Set flag in struct drm_fb_helper for leaking physical addresses") -- Cheers, Stephen Rothwell pgpn_g1Qv_8je.pgp Description: OpenPGP digital signature
Re: [PATCH 1/5] drm/msm/dsi: add support for DSI-PHY on SM8350 and SM8450
On 9/22/2022 4:30 AM, Dmitry Baryshkov wrote: SM8350 and SM8450 use 5nm DSI PHYs, which share register definitions with 7nm DSI PHYs. Rather than duplicating the driver, handle 5nm variants inside the common 5+7nm driver. I do realize that there is common code across PHYs but i am concerned about this type of unification of phy drivers. If we have features which are PHY sequence dependent such as ULPS, this will just complicate things for us. Also some PHY registers might get added some might get removed across chipsets as this is the most frequently changed component. Even in this patch, I see this added to dsi_7nm_phy_disable() > + /* Turn off REFGEN Vote */ > +dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10, 0x0); > +wmb(); > +/* Delay to ensure HW removes vote before PHY shut down */ > +udelay(2); > + What would be the impact of writing this for the existing 7nm PHY? I am having some access issues to check the software interface so wanted to check. Co-developed-by: Robert Foss Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/Kconfig | 6 +- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 + drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 2 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 132 -- 4 files changed, 131 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 4e0cbd682725..e6c5dfbad009 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -140,12 +140,12 @@ config DRM_MSM_DSI_10NM_PHY Choose this option if DSI PHY on SDM845 is used on the platform. config DRM_MSM_DSI_7NM_PHY - bool "Enable DSI 7nm PHY driver in MSM DRM" + bool "Enable DSI 7nm/5nm PHY driver in MSM DRM" depends on DRM_MSM_DSI default y help - Choose this option if DSI PHY on SM8150/SM8250/SC7280 is used on - the platform. + Choose this option if DSI PHY on SM8150/SM8250/SM8350/SM8450/SC7280 + is used on the platform. config DRM_MSM_HDMI bool "Enable HDMI support in MSM DRM driver" diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 7fc0975cb869..97cf6b8b34cc 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -567,6 +567,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_7nm_8150_cfgs }, { .compatible = "qcom,sc7280-dsi-phy-7nm", .data = &dsi_phy_7nm_7280_cfgs }, + { .compatible = "qcom,dsi-phy-5nm-8350", + .data = &dsi_phy_5nm_8350_cfgs }, + { .compatible = "qcom,dsi-phy-5nm-8450", + .data = &dsi_phy_5nm_8450_cfgs }, #endif {} }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 60a99c6525b2..654cbfa14d6e 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -56,6 +56,8 @@ extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs; struct msm_dsi_dphy_timing { u32 clk_zero; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 9e7fa7d88ead..1696ff150b9e 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -39,8 +39,14 @@ #define VCO_REF_CLK_RATE 1920 #define FRAC_BITS 18 +/* Hardware is pre V4.1 */ +#define DSI_PHY_7NM_QUIRK_PRE_V4_1 BIT(0) /* Hardware is V4.1 */ -#define DSI_PHY_7NM_QUIRK_V4_1 BIT(0) +#define DSI_PHY_7NM_QUIRK_V4_1 BIT(1) +/* Hardware is V4.2 */ +#define DSI_PHY_7NM_QUIRK_V4_2 BIT(2) +/* Hardware is V4.3 */ +#define DSI_PHY_7NM_QUIRK_V4_3 BIT(3) struct dsi_pll_config { bool enable_ssc; @@ -116,7 +122,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config dec_multiple = div_u64(pll_freq * multiplier, divider); dec = div_u64_rem(dec_multiple, multiplier, &frac); - if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1)) + if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) config->pll_clock_inverters = 0x28; else if (pll_freq <= 10ULL) config->pll_clock_inverters = 0xa0; @@ -197,16 +203,25 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) void __iomem *base = pll->phy->pll_base; u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00; - if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) { + if (!(pll->phy->cfg->q
[PATCH v2 4/4] drm/sun4i: dsi: Add the A100 variant
The A100 variant of the MIPI DSI controller now gets its module clock from the TCON via the TCON TOP, so the clock rate cannot be set to a fixed value. Otherwise, it appears to be the same as the A31 variant. Reviewed-by: Jernej Skrabec Signed-off-by: Samuel Holland --- (no changes since v1) drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index f22c96cc8408..760ff05eabf4 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -1223,6 +1223,10 @@ static const struct sun6i_dsi_variant sun6i_a31_mipi_dsi_variant = { static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = { }; +static const struct sun6i_dsi_variant sun50i_a100_mipi_dsi_variant = { + .has_mod_clk= true, +}; + static const struct of_device_id sun6i_dsi_of_table[] = { { .compatible = "allwinner,sun6i-a31-mipi-dsi", @@ -1232,6 +1236,10 @@ static const struct of_device_id sun6i_dsi_of_table[] = { .compatible = "allwinner,sun50i-a64-mipi-dsi", .data = &sun50i_a64_mipi_dsi_variant, }, + { + .compatible = "allwinner,sun50i-a100-mipi-dsi", + .data = &sun50i_a100_mipi_dsi_variant, + }, { } }; MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); -- 2.37.3
[PATCH v2 3/4] drm/sun4i: dsi: Add a variant structure
Replace the ad-hoc calls to of_device_is_compatible() with a structure describing the differences between variants. This is in preparation for adding more variants to the driver. Reviewed-by: Jernej Skrabec Signed-off-by: Samuel Holland --- Changes in v2: - Add the variant check to the probe error path drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 53 +- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h | 7 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 34234a144e87..f22c96cc8408 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -1101,12 +1101,16 @@ static const struct component_ops sun6i_dsi_ops = { static int sun6i_dsi_probe(struct platform_device *pdev) { + const struct sun6i_dsi_variant *variant; struct device *dev = &pdev->dev; - const char *bus_clk_name = NULL; struct sun6i_dsi *dsi; void __iomem *base; int ret; + variant = device_get_match_data(dev); + if (!variant) + return -EINVAL; + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; @@ -1114,10 +1118,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev) dsi->dev = dev; dsi->host.ops = &sun6i_dsi_host_ops; dsi->host.dev = dev; - - if (of_device_is_compatible(dev->of_node, - "allwinner,sun6i-a31-mipi-dsi")) - bus_clk_name = "bus"; + dsi->variant = variant; base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) { @@ -1142,7 +1143,7 @@ static int sun6i_dsi_probe(struct platform_device *pdev) return PTR_ERR(dsi->regs); } - dsi->bus_clk = devm_clk_get(dev, bus_clk_name); + dsi->bus_clk = devm_clk_get(dev, variant->has_mod_clk ? "bus" : NULL); if (IS_ERR(dsi->bus_clk)) return dev_err_probe(dev, PTR_ERR(dsi->bus_clk), "Couldn't get the DSI bus clock\n"); @@ -1151,21 +1152,21 @@ static int sun6i_dsi_probe(struct platform_device *pdev) if (ret) return ret; - if (of_device_is_compatible(dev->of_node, - "allwinner,sun6i-a31-mipi-dsi")) { + if (variant->has_mod_clk) { dsi->mod_clk = devm_clk_get(dev, "mod"); if (IS_ERR(dsi->mod_clk)) { dev_err(dev, "Couldn't get the DSI mod clock\n"); ret = PTR_ERR(dsi->mod_clk); goto err_attach_clk; } - } - /* -* In order to operate properly, that clock seems to be always -* set to 297MHz. -*/ - clk_set_rate_exclusive(dsi->mod_clk, 29700); + /* +* In order to operate properly, the module clock on the +* A31 variant always seems to be set to 297MHz. +*/ + if (variant->set_mod_clk) + clk_set_rate_exclusive(dsi->mod_clk, 29700); + } dsi->dphy = devm_phy_get(dev, "dphy"); if (IS_ERR(dsi->dphy)) { @@ -1191,7 +1192,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev) err_remove_dsi_host: mipi_dsi_host_unregister(&dsi->host); err_unprotect_clk: - clk_rate_exclusive_put(dsi->mod_clk); + if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk) + clk_rate_exclusive_put(dsi->mod_clk); err_attach_clk: regmap_mmio_detach_clk(dsi->regs); @@ -1205,16 +1207,31 @@ static int sun6i_dsi_remove(struct platform_device *pdev) component_del(&pdev->dev, &sun6i_dsi_ops); mipi_dsi_host_unregister(&dsi->host); - clk_rate_exclusive_put(dsi->mod_clk); + if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk) + clk_rate_exclusive_put(dsi->mod_clk); regmap_mmio_detach_clk(dsi->regs); return 0; } +static const struct sun6i_dsi_variant sun6i_a31_mipi_dsi_variant = { + .has_mod_clk= true, + .set_mod_clk= true, +}; + +static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = { +}; + static const struct of_device_id sun6i_dsi_of_table[] = { - { .compatible = "allwinner,sun6i-a31-mipi-dsi" }, - { .compatible = "allwinner,sun50i-a64-mipi-dsi" }, + { + .compatible = "allwinner,sun6i-a31-mipi-dsi", + .data = &sun6i_a31_mipi_dsi_variant, + }, + { + .compatible = "allwinner,sun50i-a64-mipi-dsi", + .data = &sun50i_a64_mipi_dsi_variant, + }, { } }; MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table); diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h index c863900ae3b
[PATCH v2 0/4] drm/sun4i: dsi: Support the A100/D1 controller variant
This series adds support for the digital part of the DSI controller found in the A100 and D1 SoCs (plus T7, which is not supported by mainline Linux). There are two changes to the hardware integration: 1) the module clock routes through the TCON TOP, and 2) the separate I/O domain is removed. The actual register interface appears to be the same as before. The register definitions in the D1 BSP exactly match the A64 BSP. The BSP describes this as the "40nm" DSI controller variant. There is also a "28nm" variant with a different register interface; that one is found in a different subset of SoCs (V5 and A50). A100/D1 also come with an updated DPHY, described by the BSP as a "combo" PHY, which is now also used for LVDS channel 0. (LVDS and DSI share the same pins on Port D.) Since that is a different subsystem, I am sending that as a separate series. Changes in v2: - Add the variant check to the probe error path Samuel Holland (4): dt-bindings: display: sun6i-dsi: Fix clock conditional dt-bindings: display: sun6i-dsi: Add the A100 variant drm/sun4i: dsi: Add a variant structure drm/sun4i: dsi: Add the A100 variant .../display/allwinner,sun6i-a31-mipi-dsi.yaml | 30 ++--- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c| 61 +-- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h| 7 +++ 3 files changed, 71 insertions(+), 27 deletions(-) -- 2.37.3
[PATCH v2 2/4] dt-bindings: display: sun6i-dsi: Add the A100 variant
The "40nm" MIPI DSI controller found in the A100 and D1 SoCs has the same register layout as previous SoC integrations. However, its module clock now comes from the TCON, which means it no longer runs at a fixed rate, so this needs to be distinguished in the driver. The controller also now uses pins on Port D instead of dedicated pins, so it drops the separate power domain. Acked-by: Krzysztof Kozlowski Signed-off-by: Samuel Holland --- Removal of the vcc-dsi-supply is maybe a bit questionable. Since there is no "VCC-DSI" pin anymore, it's not obvious which pin actually does power the DSI controller/PHY. Possibly power comes from VCC-PD or VCC-IO or VCC-LVDS. So far, all boards have all of these as always-on supplies, so it is hard to test. (no changes since v1) .../display/allwinner,sun6i-a31-mipi-dsi.yaml | 28 +++ 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml index bf9bfe8f88ae..c731fbdc2fe0 100644 --- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml @@ -12,9 +12,14 @@ maintainers: properties: compatible: -enum: - - allwinner,sun6i-a31-mipi-dsi - - allwinner,sun50i-a64-mipi-dsi +oneOf: + - enum: + - allwinner,sun6i-a31-mipi-dsi + - allwinner,sun50i-a64-mipi-dsi + - allwinner,sun50i-a100-mipi-dsi + - items: + - const: allwinner,sun20i-d1-mipi-dsi + - const: allwinner,sun50i-a100-mipi-dsi reg: maxItems: 1 @@ -59,7 +64,6 @@ required: - phys - phy-names - resets - - vcc-dsi-supply - port allOf: @@ -68,7 +72,9 @@ allOf: properties: compatible: contains: -const: allwinner,sun6i-a31-mipi-dsi +enum: + - allwinner,sun6i-a31-mipi-dsi + - allwinner,sun50i-a100-mipi-dsi then: properties: @@ -83,6 +89,18 @@ allOf: clocks: maxItems: 1 + - if: + properties: +compatible: + contains: +enum: + - allwinner,sun6i-a31-mipi-dsi + - allwinner,sun50i-a64-mipi-dsi + +then: + required: +- vcc-dsi-supply + unevaluatedProperties: false examples: -- 2.37.3
[PATCH v2 1/4] dt-bindings: display: sun6i-dsi: Fix clock conditional
The A64 case should have limited maxItems, instead of duplicating the minItems value from the main binding. While here, simplify the binding by making this an "else" case of the two-clock conditional block. Fixes: fe5040f2843a ("dt-bindings: sun6i-dsi: Document A64 MIPI-DSI controller") Acked-by: Krzysztof Kozlowski Signed-off-by: Samuel Holland --- (no changes since v1) .../bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml | 10 ++ 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml index 7910831fa4b8..bf9bfe8f88ae 100644 --- a/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/allwinner,sun6i-a31-mipi-dsi.yaml @@ -78,16 +78,10 @@ allOf: required: - clock-names - - if: - properties: -compatible: - contains: -const: allwinner,sun50i-a64-mipi-dsi - -then: +else: properties: clocks: - minItems: 1 + maxItems: 1 unevaluatedProperties: false -- 2.37.3
Re: Coverity: kfd_parse_subtype_cache(): Memory - corruptions
Thanks, I will send the fix patch. Regards, Ma Jun On 11/5/2022 4:40 AM, Felix Kuehling wrote: > On 2022-11-04 15:41, coverity-bot wrote: >> Hello! >> >> This is an experimental semi-automated report about issues detected by >> Coverity from a scan of next-20221104 as part of the linux-next scan project: >> https://scan.coverity.com/projects/linux-next-weekly-scan >> >> You're getting this email because you were associated with the identified >> lines of code (noted below) that were touched by commits: >> >>Fri Dec 8 23:08:59 2017 -0500 >> 3a87177eb141 ("drm/amdkfd: Add topology support for dGPUs") >> >> Coverity reported the following: >> >> *** CID 1527133: Memory - corruptions (OVERRUN) >> drivers/gpu/drm/amd/amdkfd/kfd_crat.c:1113 in kfd_parse_subtype_cache() >> 1107 props->cache_size = cache->cache_size; >> 1108 props->cacheline_size = cache->cache_line_size; >> 1109 props->cachelines_per_tag = >> cache->lines_per_tag; >> 1110 props->cache_assoc = cache->associativity; >> props->cache_latency = cache->cache_latency; >> 1112 >> vvv CID 1527133: Memory - corruptions (OVERRUN) >> vvv Overrunning array "cache->sibling_map" of 32 bytes by passing it to >> a function which accesses it at byte offset 63 using argument "64UL". [Note: >> The source code implementation of the function has been overridden by a >> builtin model.] >> 1113 memcpy(props->sibling_map, cache->sibling_map, >> 1114 sizeof(props->sibling_map)); >> 1115 >> 1116 /* set the sibling_map_size as 32 for CRAT from >> ACPI */ >> 1117 props->sibling_map_size = CRAT_SIBLINGMAP_SIZE; >> 1118 >> >> If this is a false positive, please let us know so we can mark it as >> such, or teach the Coverity rules to be smarter. If not, please make >> sure fixes get into linux-next. :) For patches fixing this, please >> include these lines (but double-check the "Fixes" first): >> >> Reported-by: coverity-bot >> Addresses-Coverity-ID: 1527133 ("Memory - corruptions") >> Fixes: 3a87177eb141 ("drm/amdkfd: Add topology support for dGPUs") >> >> I'm not sure why this suddenly appeared after 5 years, but the read >> over-run looks legit: > > > I think this was introduced by a more recent patch that was in fact > meant to fix an array overrun on HW that is outgrowing the CRAT sibling > map size: > >> commit 0938fbeb6f53fc44bc9b19784dee28496e68ba0c >> Author: Ma Jun >> Date: Wed Nov 2 15:53:26 2022 +0800 >> >> drm/amdkfd: Fix the warning of array-index-out-of-bounds >> >> For some GPUs with more CUs, the original sibling_map[32] >> in struct crat_subtype_cache is not enough >> to save the cache information when create the VCRAT table, >> so skip filling the struct crat_subtype_cache info instead >> fill struct kfd_cache_properties directly to fix this problem. >> >> Signed-off-by: Ma Jun >> Reviewed-by: Felix Kuehling >> Signed-off-by: Alex Deucher > I added Ma Jun to the email. > > Regards, > Felix > > >> >> struct crat_subtype_cache { >> ... >> uint8_t sibling_map[CRAT_SIBLINGMAP_SIZE]; >> >> #define CRAT_SIBLINGMAP_SIZE32 >> >> >> struct kfd_cache_properties { >> ... >> uint8_t sibling_map[CACHE_SIBLINGMAP_SIZE]; >> >> #define CACHE_SIBLINGMAP_SIZE 64 >> >> Thanks for your attention! >>
[RFC 00/15] Add support for HDMI2.1 FRL
This set is RFC for adding support for HDMI2.1 FRL Link training. FRL or Fixed Rate Link is defined by HDMI2.1 spec for supporting higher bit-rate. As per HDMI2.1 specification, a new data-channel or lane is added in FRL mode, by repurposing the TMDS clock Channel. This enables HDMI to support 48 Gbps bandwidth (i.e. bit rate of 12 Gbps/lane for 4 lanes). This series is a step for Native HDMI2.1 support for MTL and to begin discussion on the Fixed Rate Link Training part. It adds new structures, registers and functions for facilitating FRL training for HDMI2.1. Basically it provides the support for starting the Link training for a given bit rate and lane count. The appropriate bit rate and lanes need to be computed in the compute config phase for HDMI, for a given video-mode, which is not part of this series, but can be built on the basic structures and new members added in this series. The FRL Training will take place only when we take a decision to go for FRL mode and set the crtc_state parameters appropriately during compute config phase. The first 2 patches are prep work to have helper for getting MAX FRL rate for existing DP-to HDMI2.1 PCON and Native HDMI2.1 from an older series: https://patchwork.freedesktop.org/series/99311/ As HDMI2.1 needs C20 PHY, there is dependency on patch series from Mika: https://patchwork.freedesktop.org/series/109714/ Therefore Patch 3 which adds the C10/C20 registers, is taken from the above series for completeness, and FRL bits are added on top of that. Ankit Nautiyal (13): drm/edid: Add helper to get max FRL rate for an HDMI sink drm/i915/dp: Use the drm helpers for getting max FRL rate drm/i915/hdmi21/mtl: Add new data members for FRL configuration drm/drm_scdc_helper: Add SCDC helper funcs for HDMI2.1 drm/i915/mtl: Add registers for FRL Link Training drm/i915/mtl: Add HDMI2.1 bits in PORT_BUF_CTL_1 drm/i915/mtl: Add port_data/data width for TRANS_DDI_FUNC and DDI_BUF_CTL drm/i915/display/mtl: Add new members in crtc_state for FRL configuration drm/i915/display/mtl: Update Transcoder/DDI registers with the frl bits drm/i915/display/mtl: Reset FRL Transcoder config while disabling HDMI drm/i915/hdmi21/mtl: Enable Scrambling only for FRL mode drm/i915/hdmi21/mtl: Add support for sending uevent to user for FRL training failure drm/i915/display/mtl: Add functions for FRL trainining state machine Mika Kahola (1): drm/i915/mtl: Create separate reg file for PICA registers Vandita Kulkarni (1): drm/i915/hdmi21/mtl: Parse frl max link rate from vbt drivers/gpu/drm/display/drm_scdc_helper.c | 196 drivers/gpu/drm/drm_edid.c| 38 ++ drivers/gpu/drm/i915/display/intel_bios.c | 51 ++ drivers/gpu/drm/i915/display/intel_bios.h | 1 + .../gpu/drm/i915/display/intel_cx0_reg_defs.h | 144 ++ drivers/gpu/drm/i915/display/intel_ddi.c | 63 ++- .../drm/i915/display/intel_display_types.h| 32 ++ drivers/gpu/drm/i915/display/intel_dp.c | 17 +- drivers/gpu/drm/i915/display/intel_hdmi.c | 443 +- drivers/gpu/drm/i915/display/intel_hdmi.h | 2 + drivers/gpu/drm/i915/display/intel_vbt_defs.h | 7 + drivers/gpu/drm/i915/i915_reg.h | 33 +- include/drm/display/drm_scdc.h| 23 + include/drm/display/drm_scdc_helper.h | 21 + include/drm/drm_edid.h| 2 + 15 files changed, 1052 insertions(+), 21 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h -- 2.25.1
[RFC 02/15] drm/i915/dp: Use the drm helpers for getting max FRL rate
Re-use the drm helpers for getting max FRL rate for an HDMI sink. This patch removes the duplicate code and calls the already defined drm helpers for the task. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_dp.c | 17 - 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7400d6b4c587..ef2383ca8d7d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2398,20 +2398,11 @@ static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; struct drm_connector *connector = &intel_connector->base; - int max_frl_rate; - int max_lanes, rate_per_lane; - int max_dsc_lanes, dsc_rate_per_lane; + int max_frl_rate = drm_hdmi_sink_max_frl_rate(connector); + int dsc_max_frl_rate = drm_hdmi_sink_dsc_max_frl_rate(connector); - max_lanes = connector->display_info.hdmi.max_lanes; - rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane; - max_frl_rate = max_lanes * rate_per_lane; - - if (connector->display_info.hdmi.dsc_cap.v_1p2) { - max_dsc_lanes = connector->display_info.hdmi.dsc_cap.max_lanes; - dsc_rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane; - if (max_dsc_lanes && dsc_rate_per_lane) - max_frl_rate = min(max_frl_rate, max_dsc_lanes * dsc_rate_per_lane); - } + if (dsc_max_frl_rate) + return min(max_frl_rate, dsc_max_frl_rate); return max_frl_rate; } -- 2.25.1
[RFC 01/15] drm/edid: Add helper to get max FRL rate for an HDMI sink
Add the helpers for getting the max FRL rate with and without DSC for an HDMI sink. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/drm_edid.c | 38 ++ include/drm/drm_edid.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index b2d61c05f559..5961399c31ba 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -7182,3 +7182,41 @@ static void _drm_update_tile_info(struct drm_connector *connector, connector->tile_group = NULL; } } + +/** + * drm_hdmi_sink_max_frl_rate - get the max frl rate, if supported + * @connector - connector with HDMI sink + * + * RETURNS: + * max frl rate supported by the HDMI sink, 0 if FRL not supported + */ +int drm_hdmi_sink_max_frl_rate(struct drm_connector *connector) +{ + int max_lanes = connector->display_info.hdmi.max_lanes; + int rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane; + + return max_lanes * rate_per_lane; +} +EXPORT_SYMBOL(drm_hdmi_sink_max_frl_rate); + +/** + * drm_hdmi_sink_dsc_max_frl_rate - get the max frl rate from HDMI sink with + * DSC1.2 compression. + * @connector - connector with HDMI sink + * + * RETURNS: + * max frl rate supported by the HDMI sink with DSC1.2, 0 if FRL not supported + */ +int drm_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector) +{ + int max_dsc_lanes, dsc_rate_per_lane; + + if (!connector->display_info.hdmi.dsc_cap.v_1p2) + return 0; + + max_dsc_lanes = connector->display_info.hdmi.dsc_cap.max_lanes; + dsc_rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane; + + return max_dsc_lanes * dsc_rate_per_lane; +} +EXPORT_SYMBOL(drm_hdmi_sink_dsc_max_frl_rate); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 372963600f1d..c567826eee58 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -611,5 +611,7 @@ int drm_edid_connector_update(struct drm_connector *connector, const struct drm_edid *edid); const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index); +int drm_hdmi_sink_max_frl_rate(struct drm_connector *connector); +int drm_hdmi_sink_dsc_max_frl_rate(struct drm_connector *connector); #endif /* __DRM_EDID_H__ */ -- 2.25.1
[RFC 04/15] drm/i915/hdmi21/mtl: Parse frl max link rate from vbt
From: Vandita Kulkarni >From the max_frl_rate field of vbt parse the maxfrl_rate. Signed-off-by: Vandita Kulkarni Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_bios.c | 51 +++ drivers/gpu/drm/i915/display/intel_bios.h | 1 + drivers/gpu/drm/i915/display/intel_vbt_defs.h | 7 +++ 3 files changed, 59 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index c2987f2c2b2e..14008fc4c9bf 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2621,6 +2621,42 @@ static bool is_port_valid(struct drm_i915_private *i915, enum port port) return true; } +static int _intel_bios_hdmi_max_frl_rate(const struct intel_bios_encoder_data *devdata) +{ + struct drm_i915_private *i915 = devdata->i915; + + if (i915->display.vbt.version >= 237 && + devdata->child.hdmi_max_frl_rate_valid) { + switch (devdata->child.hdmi_max_frl_rate) { + default: + case HDMI_MAX_FRL_RATE_PLATFORM: + drm_dbg_kms(&i915->drm, "HDMI2.1 is limited to support only TMDS modes\n"); + return 0; + case HDMI_MAX_FRL_RATE_3G: + return 300; + case HDMI_MAX_FRL_RATE_6G: + return 600; + case HDMI_MAX_FRL_RATE_8G: + return 800; + case HDMI_MAX_FRL_RATE_10G: + return 1000; + case HDMI_MAX_FRL_RATE_12G: + return 1200; + } + } + + /* +* When hdmi_max_frl_rate_valid is 0 +* Don't consider the hdmi_max_frl_rate for +* limiting the FrlRates on HDMI2.1 displays +*/ + if (i915->display.vbt.version >= 237 && + IS_METEORLAKE(i915)) + return 1200; + + return 0; +} + static void print_ddi_port(const struct intel_bios_encoder_data *devdata, enum port port) { @@ -2628,6 +2664,7 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata, const struct child_device_config *child = &devdata->child; bool is_dvi, is_hdmi, is_dp, is_edp, is_crt, supports_typec_usb, supports_tbt; int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock; + int hdmi_max_frl_rate; is_dvi = intel_bios_encoder_supports_dvi(devdata); is_dp = intel_bios_encoder_supports_dp(devdata); @@ -2677,6 +2714,12 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata, "Port %c VBT DP max link rate: %d\n", port_name(port), dp_max_link_rate); + hdmi_max_frl_rate = _intel_bios_hdmi_max_frl_rate(devdata); + if (hdmi_max_frl_rate) + drm_dbg_kms(&i915->drm, + "VBT HDMI max frl rate for port %c: %d\n", + port_name(port), hdmi_max_frl_rate); + /* * FIXME need to implement support for VBT * vswing/preemph tables should this ever trigger. @@ -3679,6 +3722,14 @@ int intel_bios_max_tmds_clock(struct intel_encoder *encoder) return _intel_bios_max_tmds_clock(devdata); } +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_bios_encoder_data *devdata = i915->display.vbt.ports[encoder->port]; + + return _intel_bios_hdmi_max_frl_rate(devdata); +} + /* This is an index in the HDMI/DVI DDI buffer translation table, or -1 */ int intel_bios_hdmi_level_shift(struct intel_encoder *encoder) { diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index e375405a7828..e3a8e8198881 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -273,5 +273,6 @@ bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devdata); int intel_bios_encoder_dp_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_encoder_hdmi_boost_level(const struct intel_bios_encoder_data *devdata); +int intel_bios_hdmi_max_frl_rate(struct intel_encoder *encoder); #endif /* _INTEL_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index a9f44abfc9fc..f7ecb82b0b3f 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -320,6 +320,13 @@ struct bdb_general_features { #define HDMI_MAX_DATA_RATE_340 4 /* 249+ */ #define HDMI_MAX_DATA_RATE_300 5 /* 249+ */ +#de
[RFC 03/15] drm/i915/mtl: Create separate reg file for PICA registers
From: Mika Kahola (Patch is part of the series to add C10/C20 PHY support, which is in review : https://patchwork.freedesktop.org/series/109714/) Create a separate file to store registers for PICA chips C10 and C20. Signed-off-by: Radhakrishna Sripada Signed-off-by: Mika Kahola --- .../gpu/drm/i915/display/intel_cx0_reg_defs.h | 136 ++ 1 file changed, 136 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h diff --git a/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h b/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h new file mode 100644 index ..dfe156141d73 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_CX0_REG_DEFS_H__ +#define __INTEL_CX0_REG_DEFS_H__ + +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A 0x64040 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B 0x64140 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1 0x16F240 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2 0x16F440 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3 0x16F640 +#define _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4 0x16F840 +#define _XELPDP_PORT_M2P_MSGBUS_CTL(port, lane)(_PICK(port, \ +[PORT_A] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_A, \ +[PORT_B] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_B, \ +[PORT_TC1] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC1, \ +[PORT_TC2] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC2, \ +[PORT_TC3] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC3, \ +[PORT_TC4] = _XELPDP_PORT_M2P_MSGBUS_CTL_LN0_USBC4) + ((lane) * 4)) + +#define XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane)) +#define XELPDP_PORT_M2P_TRANSACTION_PENDING REG_BIT(31) +#define XELPDP_PORT_M2P_COMMAND_TYPE_MASK REG_GENMASK(30, 27) +#define XELPDP_PORT_M2P_COMMAND_WRITE_UNCOMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x1) +#define XELPDP_PORT_M2P_COMMAND_WRITE_COMMITTED REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x2) +#define XELPDP_PORT_M2P_COMMAND_READ REG_FIELD_PREP(XELPDP_PORT_M2P_COMMAND_TYPE_MASK, 0x3) +#define XELPDP_PORT_M2P_DATA_MASK REG_GENMASK(23, 16) +#define XELPDP_PORT_M2P_DATA(val) REG_FIELD_PREP(XELPDP_PORT_M2P_DATA_MASK, val) +#define XELPDP_PORT_M2P_TRANSACTION_RESET REG_BIT(15) +#define XELPDP_PORT_M2P_ADDRESS_MASK REG_GENMASK(11, 0) +#define XELPDP_PORT_M2P_ADDRESS(val) REG_FIELD_PREP(XELPDP_PORT_M2P_ADDRESS_MASK, val) + +#define XELPDP_PORT_P2M_MSGBUS_STATUS(port, lane) _MMIO(_XELPDP_PORT_M2P_MSGBUS_CTL(port, lane) + 8) +#define XELPDP_PORT_P2M_RESPONSE_READYREG_BIT(31) +#define XELPDP_PORT_P2M_COMMAND_TYPE_MASK REG_GENMASK(30, 27) +#define XELPDP_PORT_P2M_COMMAND_READ_ACK 0x4 +#define XELPDP_PORT_P2M_COMMAND_WRITE_ACK 0x5 +#define XELPDP_PORT_P2M_DATA_MASK REG_GENMASK(23, 16) +#define XELPDP_PORT_P2M_DATA(val) REG_FIELD_PREP(XELPDP_PORT_P2M_DATA_MASK, val) +#define XELPDP_PORT_P2M_ERROR_SET REG_BIT(15) + +#define XELPDP_MSGBUS_TIMEOUT_SLOW1 +#define XELPDP_MSGBUS_TIMEOUT_FAST_US 2 +#define XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US 3200 +#define XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US 20 +#define XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US 100 +#define XELPDP_PORT_RESET_START_TIMEOUT_US 5 +#define XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US100 +#define XELPDP_PORT_RESET_END_TIMEOUT 15 +#define XELPDP_REFCLK_ENABLE_TIMEOUT_US1 + +#define _XELPDP_PORT_BUF_CTL1_LN0_A0x64004 +#define _XELPDP_PORT_BUF_CTL1_LN0_B0x64104 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC10x16F200 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC20x16F400 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC30x16F600 +#define _XELPDP_PORT_BUF_CTL1_LN0_USBC40x16F800 +#define _XELPDP_PORT_BUF_CTL1(port)(_PICK(port, \ +[PORT_A] = _XELPDP_PORT_BUF_CTL1_LN0_A, \ +[PORT_B] = _XELPDP_PORT_BUF_CTL1_LN0_B, \ +[PORT_TC1] = _XELPDP_PORT_BUF_CTL1
[RFC 05/15] drm/i915/hdmi21/mtl: Add new data members for FRL configuration
HDMI2.1 supports higher resolutions using Fixed Rate Link. Source need to do FRL link training on the 4 lanes before video stream transmission. This patch adds the members to crtc_state and intel_hdmi for identifying the FRL supporting HDMI sink and to maintain the frl training information, after successful training. Signed-off-by: Ankit Nautiyal --- .../drm/i915/display/intel_display_types.h| 9 drivers/gpu/drm/i915/display/intel_hdmi.c | 22 +++ 2 files changed, 31 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c6abaaa46e17..e57fac00e945 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1517,8 +1517,17 @@ struct intel_hdmi { } dp_dual_mode; bool has_hdmi_sink; bool has_audio; + bool has_sink_hdmi_21; + int max_frl_rate; + int max_dsc_frl_rate; struct intel_connector *attached_connector; struct cec_notifier *cec_notifier; + struct { + bool trained; + int lanes; + int rate_gbps; + int ffe_level; + } frl; }; struct intel_dp_mst_encoder; diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 02f8374ea51f..1dd0b0f2e2f1 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2346,6 +2346,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector) intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; + intel_hdmi->has_sink_hdmi_21 = false; intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; intel_hdmi->dp_dual_mode.max_tmds_clock = 0; @@ -2405,11 +2406,21 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) } } +static void +intel_hdmi_reset_frl_config(struct intel_hdmi *intel_hdmi) +{ + intel_hdmi->frl.trained = false; + intel_hdmi->frl.lanes = 0; + intel_hdmi->frl.rate_gbps = 0; + intel_hdmi->frl.ffe_level = 0; +} + static bool intel_hdmi_set_edid(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector)); + struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base; intel_wakeref_t wakeref; struct edid *edid; bool connected = false; @@ -2431,10 +2442,21 @@ intel_hdmi_set_edid(struct drm_connector *connector) to_intel_connector(connector)->detect_edid = edid; if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { + int src_rate_lane_gbps = DIV_ROUND_UP(intel_bios_hdmi_max_frl_rate(encoder), + 100); + int max_src_rate = src_rate_lane_gbps * 4; + intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi_dp_dual_mode_detect(connector); + intel_hdmi->has_sink_hdmi_21 = + drm_hdmi_sink_max_frl_rate(connector) > 0 ? true : false; + intel_hdmi->max_frl_rate = min(drm_hdmi_sink_max_frl_rate(connector), + max_src_rate); + intel_hdmi->max_dsc_frl_rate = min(drm_hdmi_sink_dsc_max_frl_rate(connector), + max_src_rate); + intel_hdmi_reset_frl_config(intel_hdmi); connected = true; } -- 2.25.1
[RFC 11/15] drm/i915/display/mtl: Update Transcoder/DDI registers with the frl bits
For platforms supporting HDMI2.1 we need to fill the lane count in Transcoder and DDI/PORT registers for FRL mode. Similarly, FRL SHIFTER ENABLE, and DATA_WIDTH bits are to be set in FRL mode. These bits are written in both the DDI_BUF_CTL and PORT_BUF_CTL registers. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_ddi.c | 49 +--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e95bde5cf060..5e2e4c78c564 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -38,6 +38,7 @@ #include "intel_combo_phy_regs.h" #include "intel_connector.h" #include "intel_crtc.h" +#include "intel_cx0_reg_defs.h" #include "intel_ddi.h" #include "intel_ddi_buf_trans.h" #include "intel_de.h" @@ -499,6 +500,8 @@ intel_ddi_transcoder_func_reg_val_get(struct intel_encoder *encoder, temp |= TRANS_DDI_HDMI_SCRAMBLING; if (crtc_state->hdmi_high_tmds_clock_ratio) temp |= TRANS_DDI_HIGH_TMDS_CHAR_RATE; + if (crtc_state->frl.enable) + temp |= TRANS_DDI_PORT_WIDTH(crtc_state->lane_count); } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) { temp |= TRANS_DDI_MODE_SELECT_FDI_OR_128B132B; temp |= (crtc_state->fdi_lanes - 1) << 1; @@ -2587,6 +2590,13 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, if (wait) intel_wait_ddi_buf_idle(dev_priv, port); + + /* Clear PORT_BUF_CTL */ + if (crtc_state->frl.enable) { + val = intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)); + intel_de_write(dev_priv, XELPDP_PORT_BUF_CTL1(port), + val & ~(XELPDP_PORT_HDMI_FRL_SHFTR_EN)); + } } static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, @@ -2837,7 +2847,6 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, struct drm_connector *connector = conn_state->connector; enum port port = encoder->port; enum phy phy = intel_port_to_phy(dev_priv, port); - u32 buf_ctl; if (!intel_hdmi_handle_sink_scrambling(encoder, connector, crtc_state->hdmi_high_tmds_clock_ratio, @@ -2894,13 +2903,43 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, * * On ADL_P the PHY link rate and lane count must be programmed but * these are both 0 for HDMI. +* +* But MTL onwards HDMI2.1 is supported and in FRL mode, port width +* needs to be filled with either 3 or 4 lanes. For TMDS mode this +* is always filled with 4 lanes, already set in the crtc_state. */ - buf_ctl = dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE; - if (IS_ALDERLAKE_P(dev_priv) && intel_phy_is_tc(dev_priv, phy)) { + if (DISPLAY_VER(dev_priv) > 13) { + u32 ddi_buf = 0; + u32 port_buf = intel_de_read(dev_priv, XELPDP_PORT_BUF_CTL1(port)); + + port_buf |= XELPDP_PORT_WIDTH(crtc_state->lane_count); + ddi_buf |= DDI_BUF_CTL_ENABLE | + DDI_PORT_WIDTH(crtc_state->lane_count); + + if (intel_bios_is_lane_reversal_needed(dev_priv, port)) + port_buf |= XELPDP_PORT_REVERSAL; + + if (crtc_state->frl.enable) { + port_buf |= XELPDP_PORT_HDMI_FRL_SHFTR_EN; + port_buf |= XELPDP_PORT_BUF_PORT_DATA_20BIT; + ddi_buf |= DDI_BUF_PORT_DATA_20BIT; + } else { + port_buf &= ~XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK; + ddi_buf &= ~DDI_BUF_PORT_DATA_WIDTH_MASK; + } + + intel_de_write(dev_priv, XELPDP_PORT_BUF_CTL1(port), port_buf); + intel_de_write(dev_priv, DDI_BUF_CTL(port), + dig_port->saved_port_bits | ddi_buf); + } else if (IS_ALDERLAKE_P(dev_priv) && intel_phy_is_tc(dev_priv, phy)) { drm_WARN_ON(&dev_priv->drm, !intel_tc_port_in_legacy_mode(dig_port)); - buf_ctl |= DDI_BUF_CTL_TC_PHY_OWNERSHIP; + intel_de_write(dev_priv, DDI_BUF_CTL(port), + dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE | + DDI_BUF_CTL_TC_PHY_OWNERSHIP); + } else { + intel_de_write(dev_priv, DDI_BUF_CTL(port), + dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE); } - intel_de_write(dev_priv, DDI_BUF_CTL(port), buf_ctl); intel_audio_codec_enable(encoder, crtc_state, conn_state); } -- 2.25.1
[RFC 07/15] drm/i915/mtl: Add registers for FRL Link Training
Add registers for FRL configuration. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/i915_reg.h | 22 ++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 765a10e0de88..b50e1349d22c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2121,6 +2121,28 @@ #define TRANS_PUSH_ENREG_BIT(31) #define TRANS_PUSH_SEND REG_BIT(30) +/* HDMI 2.1 FRL Configuration */ +#define _TRANS_HDMI_FRL_CFG_A 0x600B0 +#define TRANS_HDMI_FRL_CFG(trans) _MMIO_TRANS2(trans, _TRANS_HDMI_FRL_CFG_A) +#define TRANS_HDMI_FRL_ENABLE REG_BIT(31) +#define TRANS_HDMI_TMDS_ENABLE 0 +#define TRANS_HDMI_FRL_TRAINING_COMPLETE REG_BIT(28) +#define TRANS_HDMI_DISABLE_DFM_MASKING REG_BIT(20) +#define TRANS_HDMI_R_B_SCHED_ENABLE_MASK REG_BIT(19) +#define TRANS_HDMI_R_B_SCHED_ENABLE(val) REG_FIELD_PREP(TRANS_HDMI_R_B_SCHED_ENABLE_MASK, val) +#define TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH_MASK REG_GENMASK(18, 16) +#define TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH(val) REG_FIELD_PREP(TRANS_HDMI_ACTIVE_CHAR_BUF_THRESH_MASK, val) +#define TRANS_HDMI_MIN_BLANK_CHAR_MASK REG_GENMASK(15, 12) +#define TRANS_HDMI_MIN_BLANK_CHAR(val) REG_FIELD_PREP(TRANS_HDMI_MIN_BLANK_CHAR_MASK, val) +#define TRANS_HDMI_MIN_BLANK_CHAR_VAL 0xA +#define TRANS_HDMI_FRL_PKT_PAYLOAD_MAX_MASKREG_GENMASK(9, 0) +#define TRANS_HDMI_FRL_PKT_PAYLOAD_MAX(val) REG_FIELD_PREP(TRANS_HDMI_FRL_PKT_PAYLOAD_MAX_MASK, val) +#define TRANS_HDMI_PAYLOAD_UPPER_BOUND 0x3FE + +#define _TRANS_HDMI_FRL_TRAIN_A0x600B4 +#define TRANS_HDMI_FRL_TRAIN(trans)_MMIO_TRANS2(trans, _TRANS_HDMI_FRL_TRAIN_A) +#define TRANS_HDMI_FRL_LTP(pattern, lane) ((pattern) << (lane) * 8) + /* * HSW+ eDP PSR registers * -- 2.25.1
[RFC 10/15] drm/i915/display/mtl: Add new members in crtc_state for FRL configuration
Add new struture to store FRL related configurations for a pipe. These members to be calculated during compute config phase, when FRL mode is to be used. Signed-off-by: Ankit Nautiyal --- .../drm/i915/display/intel_display_types.h| 23 +++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e57fac00e945..8cab50d5d565 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1307,6 +1307,29 @@ struct intel_crtc_state { u16 flipline, vmin, vmax, guardband; } vrr; + struct { + /* Go for FRL training */ + bool enable; + + /* Enable resource based scheduling */ + bool rsrc_sched_en; + + /* can be either 3 or 4 lanes */ + u8 required_lanes; + + /* required rate - can be 3, 6, 8, 10, 12 Gbps */ + u8 required_rate; + + /* FRL DFM Parameters */ + u32 tb_borrowed, tb_actual, tb_threshold_min, active_char_buf_threshold; + + /* FRL DFM DSC Tribytes */ + u32 hcactive_tb, hctotal_tb; + + /* Clock parameters in KHz */ + u32 div18, link_m_ext, link_n_ext; + } frl; + /* Stream Splitter for eDP MSO */ struct { bool enable; -- 2.25.1
[RFC 08/15] drm/i915/mtl: Add HDMI2.1 bits in PORT_BUF_CTL_1
This patch adds bits related to HDMI2.1 in PORT_BUF_CTL_1 that is needed to be programmed for D2D Interface for Ports in IO expansion Die. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h | 8 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h b/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h index dfe156141d73..efba0ce90229 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_reg_defs.h @@ -66,14 +66,22 @@ [PORT_TC4] = _XELPDP_PORT_BUF_CTL1_LN0_USBC4)) #define XELPDP_PORT_BUF_CTL1(port) _MMIO(_XELPDP_PORT_BUF_CTL1(port)) +#define XELPDP_PORT_BUF_D2D_LINK_ENABLE REG_BIT(29) +#define XELPDP_PORT_BUF_D2D_LINK_STATEREG_BIT(28) #define XELPDP_PORT_BUF_SOC_PHY_READY REG_BIT(24) #define XELPDP_PORT_REVERSAL REG_BIT(16) +#define XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK REG_GENMASK(19, 18) +#define XELPDP_PORT_BUF_PORT_DATA_10BIT REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 0) +#define XELPDP_PORT_BUF_PORT_DATA_20BIT REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 1) +#define XELPDP_PORT_BUF_PORT_DATA_40BIT REG_FIELD_PREP(XELPDP_PORT_BUF_PORT_DATA_WIDTH_MASK, 2) +#define XELPDP_PORT_BUF_PHY_IDLE REG_BIT(7) #define XELPDP_TC_PHY_OWNERSHIP REG_BIT(6) #define XELPDP_TCSS_POWER_REQUEST REG_BIT(5) #define XELPDP_TCSS_POWER_STATE REG_BIT(4) #define XELPDP_PORT_WIDTH_MASKREG_GENMASK(3, 1) #define XELPDP_PORT_WIDTH(val) REG_FIELD_PREP(XELPDP_PORT_WIDTH_MASK, val) +#define XELPDP_PORT_HDMI_FRL_SHFTR_EN REG_BIT(0) #define XELPDP_PORT_BUF_CTL2(port) _MMIO(_XELPDP_PORT_BUF_CTL1(port) + 4) #define XELPDP_LANE0_PIPE_RESET REG_BIT(31) -- 2.25.1
[RFC 13/15] drm/i915/hdmi21/mtl: Enable Scrambling only for FRL mode
In FRL mode, the Scrambling is always enabled by the HW. The High TMDS Char Rate and Scrambing Enable bit of reg TRANS_DDI_FUNC_CTRL are only set in TMDS mode and not in FRL mode. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_hdmi.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 1dd0b0f2e2f1..1eadf77dc819 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2292,7 +2292,13 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder, pipe_config->lane_count = 4; - if (scdc->scrambling.supported && DISPLAY_VER(dev_priv) >= 10) { + /* +* Enable scrambing for only for TMDS mode. +* For FRL mode, scrambling is always enabled by HW, and +* scrambling enable and high tmds clock bits are not used. +*/ + if (scdc->scrambling.supported && DISPLAY_VER(dev_priv) >= 10 && + !pipe_config->frl.enable) { if (scdc->scrambling.low_rates) pipe_config->hdmi_scrambling = true; -- 2.25.1
[RFC 14/15] drm/i915/hdmi21/mtl: Add support for sending uevent to user for FRL training failure
In case of HDMI2.1 FRL training failure for a given mode, the user should be sent a uevent signalling Link failure. This patch adds support for sending uevent to userspace in case of link training failure. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_hdmi.c | 30 +++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 1eadf77dc819..9e8ee6d5bc5d 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2944,6 +2944,31 @@ void intel_infoframe_init(struct intel_digital_port *dig_port) } } +/* Common code with DP, need to put in a common place */ +static void intel_hdmi_modeset_retry_work_fn(struct work_struct *work) +{ + struct intel_connector *intel_connector; + struct drm_connector *connector; + + intel_connector = container_of(work, typeof(*intel_connector), + modeset_retry_work); + connector = &intel_connector->base; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, + connector->name); + + /* Grab the locks before changing connector property*/ + mutex_lock(&connector->dev->mode_config.mutex); + /* +* Set connector link status to BAD and send a Uevent to notify +* userspace to do a modeset. +*/ + drm_connector_set_link_status_property(connector, + DRM_MODE_LINK_STATUS_BAD); + mutex_unlock(&connector->dev->mode_config.mutex); + /* Send Hotplug uevent so userspace can reprobe */ + drm_kms_helper_hotplug_event(connector->dev); +} + void intel_hdmi_init_connector(struct intel_digital_port *dig_port, struct intel_connector *intel_connector) { @@ -3021,6 +3046,11 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, &conn_info); if (!intel_hdmi->cec_notifier) drm_dbg_kms(&dev_priv->drm, "CEC notifier get failed\n"); + + /* Initialize the work for modeset in case of link train failure */ + if (DISPLAY_VER(dev_priv) >= 14) + INIT_WORK(&intel_connector->modeset_retry_work, + intel_hdmi_modeset_retry_work_fn); } /* -- 2.25.1
[RFC 06/15] drm/drm_scdc_helper: Add SCDC helper funcs for HDMI2.1
HDMI2.1 specifies new SCDC registers to configure FRL Training between source and sink and get the FRL Training updated from and HDMI2.1 sink. This patch adds new SCDC registers and helper functions to read and configure these registers. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/display/drm_scdc_helper.c | 196 ++ include/drm/display/drm_scdc.h| 23 +++ include/drm/display/drm_scdc_helper.h | 21 +++ 3 files changed, 240 insertions(+) diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c index c3ad4ab2b456..dcf05167473d 100644 --- a/drivers/gpu/drm/display/drm_scdc_helper.c +++ b/drivers/gpu/drm/display/drm_scdc_helper.c @@ -261,3 +261,199 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set) return true; } EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio); + +/** + * drm_scdc_read_update_flags - read the SCDC update flags + * @adapter: I2C adapter for DDC channel + * + * Returns: + * 8bit SCDC update + */ +u8 drm_scdc_read_update_flags(struct i2c_adapter *adapter) +{ + u8 update = 0; + int ret; + + ret = drm_scdc_readb(adapter, SCDC_UPDATE_0, &update); + if (ret < 0) + DRM_DEBUG_KMS("Failed to read scdc update: %d\n", ret); + + return update; +} +EXPORT_SYMBOL(drm_scdc_read_update_flags); + +/** + * drm_scdc_clear_update_flags - Clears the given update flag bits + * @adapter: I2C adapter for DDC channel + * @status: update flag bits to be cleared + * + * Returns: + * 0 on success, negative error code otherwise. + */ +int drm_scdc_clear_update_flags(struct i2c_adapter *adapter, u8 update_flags) +{ + u8 buf; + int ret; + + /* Not all flags can be cleared by source */ + if (update_flags & ~(SCDC_STATUS_UPDATE | SCDC_CED_UPDATE | +SCDC_SOURCE_TEST_UPDATE | SCDC_FLT_UPDATE | +SCDC_RSED_UPDATE)) { + DRM_DEBUG_KMS("SCDC Update flag/s %u cannot be cleared\n", + update_flags); + + return false; + } + + ret = drm_scdc_readb(adapter, SCDC_UPDATE_0, &buf); + if (ret < 0) { + DRM_DEBUG_KMS("Failed to read SCDC_UPDATE_0\n"); + + return ret; + } + + buf = buf | update_flags; + + ret = drm_scdc_writeb(adapter, SCDC_UPDATE_0, buf); + if (ret < 0) { + DRM_DEBUG_KMS("Failed to clear SCDC Update flag/s\n"); + + return ret; + } + + return 0; +} +EXPORT_SYMBOL(drm_scdc_clear_update_flags); + +/** + * drm_scdc_read_status_flags - Read the status flags from offset 0x40 + * @adapter: I2C adapter for DDC channel + * + * Returns: + * 8 bit value read from the 0ffset 0x40 + */ +u8 drm_scdc_read_status_flags(struct i2c_adapter *adapter) +{ + u8 update = 0; + int ret; + + ret = drm_scdc_readb(adapter, SCDC_STATUS_FLAGS_0, &update); + if (ret < 0) + DRM_DEBUG_KMS("Failed to read scdc status flag: %d\n", ret); + + return update; +} +EXPORT_SYMBOL(drm_scdc_read_status_flags); + +/** + * drm_scdc_config_frl - configure the sink for starting FRL training + * @adapter: I2C adapter for DDC channel + * @frl_rate: FRL rate per lane required. + * @num_lanes: no. of lanes required, can be either 3 or 4. + * @ffe_levelw: max FFE Levelw supported for current rate for the given FRL rate. + * + * Returns: + * 0 if the SCDC offsets for FRL training are successfully configure, + * negative error code otherwise. + */ +int drm_scdc_config_frl(struct i2c_adapter *adapter, int frl_rate, + int num_lanes, int ffe_levels) +{ + u8 write_buf = 0; + int ret; + + if (num_lanes > 4 || num_lanes < 3) { + DRM_DEBUG_KMS("No. of lanes can be 3 or 4 only\n"); + + return -EINVAL; + } + if (ffe_levels > 3) { + DRM_DEBUG_KMS("Max FFE levels can be 3 or less\n"); + + return -EINVAL; + } + switch (frl_rate) { + case 3: + write_buf |= (num_lanes == 3) ? SCDC_FRL_RATE_3GBPS_3LANES : 0; + break; + case 6: + write_buf |= (num_lanes == 3) ? SCDC_FRL_RATE_6GBPS_3LANES : +SCDC_FRL_RATE_6GBPS_4LANES; + break; + case 8: + write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_8GBPS_4LANES : 0; + break; + case 10: + write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_10GBPS_4LANES : 0; + break; + case 12: + write_buf |= (num_lanes == 4) ? SCDC_FRL_RATE_12GBPS_4LANES : 0; + break; + default: + write_buf |= SCDC_FRL_DISABLE; + } + + write_buf |= (ffe_levels << SCDC_FFE_LEVELS_SHIFT); + + ret = drm_scdc_writeb(adapter, SCDC_CONFIG_1, write_buf); + if (ret < 0) { + DRM_D
[RFC 09/15] drm/i915/mtl: Add port_data/data width for TRANS_DDI_FUNC and DDI_BUF_CTL
This patch adds the bits for port width for TRANS_DDI_FUNC_CTL and port data width for DDI_BUF_CTL. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/i915_reg.h | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b50e1349d22c..8afe4b965463 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6914,6 +6914,9 @@ enum skl_power_gate { #define TRANS_DDI_HDCP_SELECT REG_BIT(5) #define TRANS_DDI_BFI_ENABLE (1 << 4) #define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1 << 4) +#define TRANS_DDI_PORT_WIDTH_MASK REG_GENMASK(3, 1) +#define TRANS_DDI_PORT_WIDTH(width) REG_FIELD_PREP(TRANS_DDI_PORT_WIDTH_MASK, (width) - 1) +#define TRANS_DDI_PORT_WIDTH_SHIFT1 #define TRANS_DDI_HDMI_SCRAMBLING (1 << 0) #define TRANS_DDI_HDMI_SCRAMBLING_MASK (TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE \ | TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ \ @@ -6979,11 +6982,15 @@ enum skl_power_gate { #define DDI_BUF_EMP_MASK (0xf << 24) #define DDI_BUF_PHY_LINK_RATE(r) ((r) << 20) #define DDI_BUF_PORT_REVERSAL (1 << 16) +#define DDI_BUF_PORT_DATA_WIDTH_MASK REG_GENMASK(19, 18) +#define DDI_BUF_PORT_DATA_10BIT REG_FIELD_PREP(DDI_BUF_PORT_DATA_WIDTH_MASK, 0) +#define DDI_BUF_PORT_DATA_20BIT REG_FIELD_PREP(DDI_BUF_PORT_DATA_WIDTH_MASK, 1) +#define DDI_BUF_PORT_DATA_40BIT REG_FIELD_PREP(DDI_BUF_PORT_DATA_WIDTH_MASK, 2) #define DDI_BUF_IS_IDLE (1 << 7) #define DDI_BUF_CTL_TC_PHY_OWNERSHIP REG_BIT(6) #define DDI_A_4_LANES (1 << 4) -#define DDI_PORT_WIDTH(width) (((width) - 1) << 1) -#define DDI_PORT_WIDTH_MASK (7 << 1) +#define DDI_PORT_WIDTH_MASK REG_GENMASK(3, 1) +#define DDI_PORT_WIDTH(width) REG_FIELD_PREP(DDI_PORT_WIDTH_MASK, (width) - 1) #define DDI_PORT_WIDTH_SHIFT 1 #define DDI_INIT_DISPLAY_DETECTED (1 << 0) -- 2.25.1
[RFC 12/15] drm/i915/display/mtl: Reset FRL Transcoder config while disabling HDMI
While disabling HDMI, reset the FRL transcoder config if FRL mode was used. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_ddi.c | 12 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 5e2e4c78c564..cb0d19b6ee56 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2667,6 +2667,8 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_hdmi *intel_hdmi = &dig_port->hdmi; + enum transcoder hdmi_transcoder; + u8 buf; dig_port->set_infoframes(encoder, false, old_crtc_state, old_conn_state); @@ -2679,6 +2681,16 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) >= 12) intel_ddi_disable_pipe_clock(old_crtc_state); + if (old_crtc_state->frl.enable) { + hdmi_transcoder = old_crtc_state->cpu_transcoder; + buf = intel_de_read(dev_priv, + TRANS_HDMI_FRL_CFG(hdmi_transcoder)); + buf &= ~(TRANS_HDMI_FRL_ENABLE | TRANS_HDMI_FRL_TRAINING_COMPLETE); + + intel_de_write(dev_priv, + TRANS_HDMI_FRL_CFG(hdmi_transcoder), buf); + } + intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain, fetch_and_zero(&dig_port->ddi_io_wakeref)); -- 2.25.1
[RFC 15/15] drm/i915/display/mtl: Add functions for FRL trainining state machine
Add support for FRL Link training state and transition to different states during FRL Link training. Signed-off-by: Ankit Nautiyal --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 + drivers/gpu/drm/i915/display/intel_hdmi.c | 383 ++ drivers/gpu/drm/i915/display/intel_hdmi.h | 2 + 3 files changed, 387 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cb0d19b6ee56..4b1b8a18863e 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2514,6 +2514,8 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state, intel_ddi_enable_pipe_clock(encoder, crtc_state); + intel_hdmi_start_frl(encoder, crtc_state); + dig_port->set_infoframes(encoder, crtc_state->has_infoframe, crtc_state, conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 9e8ee6d5bc5d..6553763306ff 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3285,3 +3285,386 @@ intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices, return 0; } + +static +bool is_flt_ready(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct i2c_adapter *adapter = + intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + + return drm_scdc_read_status_flags(adapter) & SCDC_FLT_READY; +} + +static +bool intel_hdmi_frl_prepare_lts2(struct intel_encoder *encoder, +const struct intel_crtc_state *crtc_state, +int ffe_level) +{ +#define TIMEOUT_FLT_READY_MS 250 + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct i2c_adapter *adapter = + intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + bool flt_ready = false; + int frl_rate; + int frl_lanes; + + frl_rate = crtc_state->frl.required_rate; + frl_lanes = crtc_state->frl.required_lanes; + + if (!frl_rate || !frl_lanes) + return false; + + /* +* POLL for FRL ready : READ SCDC 0x40 Bit 6 FLT ready +* #TODO Check if 250 msec is required +*/ + wait_for(flt_ready = is_flt_ready(encoder) == true, +TIMEOUT_FLT_READY_MS); + + if (!flt_ready) { + drm_dbg_kms(&dev_priv->drm, + "HDMI sink not ready for FRL in %d\n", + TIMEOUT_FLT_READY_MS); + + return false; + } + + /* +* #TODO As per spec, during prepare phase LTS2, the TXFFE to be +* programmed to be 0 for each lane in the PHY registers. +*/ + + if (drm_scdc_config_frl(adapter, frl_rate, frl_lanes, ffe_level) < 0) { + drm_dbg_kms(&dev_priv->drm, + "Failed to write SCDC config regs for FRL\n"); + + return false; + } + + return flt_ready; +} + +enum frl_lt_status { + FRL_TRAINING_PASSED, + FRL_CHANGE_RATE, + FRL_TRAIN_CONTINUE, + FRL_TRAIN_RETRAIN, + FRL_TRAIN_STOP, +}; + +static +u8 get_frl_update_flag(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct i2c_adapter *adapter = + intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + + return drm_scdc_read_update_flags(adapter); +} + +static +int get_link_training_patterns(struct intel_encoder *encoder, + enum drm_scdc_frl_ltp ltp[4]) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct i2c_adapter *adapter = + intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + + return drm_scdc_get_ltp(adapter, ltp); +} + +static enum frl_lt_status +intel_hdmi_train_lanes(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int ffe_level) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum transcoder trans = crtc_state->cpu_transcoder; + enum drm_scdc_frl_ltp ltp[4]; + int num_lanes = crtc_state->frl.required_lanes; + int lane; + + /* +* LTS3 Link Training in Progress. +* Section 6.4.2.3 Table 6-34. +* +* Transmit link training pattern as requested by the sink +* for a specific rate. +* Source keep on Polling on FLT
[PATCH v28 04/11] soc: mediatek: add mtk-mmsys support for mt8195 vdosys1
Add mt8195 vdosys1 routing table to the driver data of mtk-mmsys. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rex-BC Chen Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mt8195-mmsys.h | 139 drivers/soc/mediatek/mtk-mmsys.c| 10 ++ 2 files changed, 149 insertions(+) diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h index abfe94a30248..fd7b455bd675 100644 --- a/drivers/soc/mediatek/mt8195-mmsys.h +++ b/drivers/soc/mediatek/mt8195-mmsys.h @@ -75,6 +75,70 @@ #define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16) #define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16) +#define MT8195_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04 +#define MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1 + +#define MT8195_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08 +#define MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1 + +#define MT8195_VDO1_DISP_DPI1_SEL_IN 0xf10 +#define MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0 + +#define MT8195_VDO1_DISP_DP_INTF0_SEL_IN 0xf14 +#define MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0 + +#define MT8195_VDO1_MERGE4_SOUT_SEL0xf18 +#define MT8195_MERGE4_SOUT_TO_DPI1_SEL 2 +#define MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL 3 + +#define MT8195_VDO1_MIXER_IN1_SEL_IN 0xf24 +#define MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1 + +#define MT8195_VDO1_MIXER_IN2_SEL_IN 0xf28 +#define MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1 + +#define MT8195_VDO1_MIXER_IN3_SEL_IN 0xf2c +#define MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1 + +#define MT8195_VDO1_MIXER_IN4_SEL_IN 0xf30 +#define MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1 + +#define MT8195_VDO1_MIXER_OUT_SOUT_SEL 0xf34 +#define MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1 + +#define MT8195_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c +#define MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1 + +#define MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40 +#define MT8195_SOUT_TO_MIXER_IN1_SEL 1 + +#define MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44 +#define MT8195_SOUT_TO_MIXER_IN2_SEL 1 + +#define MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48 +#define MT8195_SOUT_TO_MIXER_IN3_SEL 1 + +#define MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c +#define MT8195_SOUT_TO_MIXER_IN4_SEL 1 + +#define MT8195_VDO1_MERGE4_ASYNC_SEL_IN0xf50 +#define MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1 + +#define MT8195_VDO1_MIXER_IN1_SOUT_SEL 0xf58 +#define MT8195_MIXER_IN1_SOUT_TO_DISP_MIXER0 + +#define MT8195_VDO1_MIXER_IN2_SOUT_SEL 0xf5c +#define MT8195_MIXER_IN2_SOUT_TO_DISP_MIXER0 + +#define MT8195_VDO1_MIXER_IN3_SOUT_SEL 0xf60 +#define MT8195_MIXER_IN3_SOUT_TO_DISP_MIXER0 + +#define MT8195_VDO1_MIXER_IN4_SOUT_SEL 0xf64 +#define MT8195_MIXER_IN4_SOUT_TO_DISP_MIXER0 + +#define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68 +#define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0 + static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = { { DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0, @@ -367,4 +431,79 @@ static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = { } }; +static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = { + { + DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1, + MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0), + MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 + }, { + DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1, + MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0), + MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 + }, { + DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2, + MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0), + MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 + }, { + DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER, + MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0), +
[PATCH v28 06/11] soc: mediatek: add mtk-mmsys config API for mt8195 vdosys1
Add four mmsys config APIs. The config APIs are used for config mmsys reg. Some mmsys regs need to be set according to the HW engine binding to the mmsys simultaneously. 1. mtk_mmsys_merge_async_config: config merge async width/height. async is used for cross-clock domain synchronization. 2. mtk_mmsys_hdr_confing: config hdr backend async width/height. 3. mtk_mmsys_mixer_in_config and mtk_mmsys_mixer_in_config: config mixer related settings. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mt8195-mmsys.h| 6 + drivers/soc/mediatek/mtk-mmsys.c | 35 ++ include/linux/soc/mediatek/mtk-mmsys.h | 9 +++ 3 files changed, 50 insertions(+) diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h index fd7b455bd675..454944a9409c 100644 --- a/drivers/soc/mediatek/mt8195-mmsys.h +++ b/drivers/soc/mediatek/mt8195-mmsys.h @@ -75,6 +75,12 @@ #define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16) #define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16) +#define MT8195_VDO1_MERGE0_ASYNC_CFG_WD0xe30 +#define MT8195_VDO1_HDRBE_ASYNC_CFG_WD 0xe70 +#define MT8195_VDO1_HDR_TOP_CFG0xd00 +#define MT8195_VDO1_MIXER_IN1_ALPHA0xd30 +#define MT8195_VDO1_MIXER_IN1_PAD 0xd40 + #define MT8195_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04 #define MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1 diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 73c8bd27e6ae..6040a3cff6f8 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -137,6 +137,41 @@ void mtk_mmsys_ddp_disconnect(struct device *dev, } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect); +void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height) +{ + mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MERGE0_ASYNC_CFG_WD + 0x10 * idx, + ~0, height << 16 | width); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_merge_async_config); + +void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height) +{ + mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_HDRBE_ASYNC_CFG_WD, ~0, + be_height << 16 | be_width); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_hdr_config); + +void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha, + u8 mode, u32 biwidth) +{ + struct mtk_mmsys *mmsys = dev_get_drvdata(dev); + + mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0, + alpha << 16 | alpha); + mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx), + alpha_sel << (19 + idx)); + mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4, + GENMASK(31, 16) | GENMASK(1, 0), biwidth << 16 | mode); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_config); + +void mtk_mmsys_mixer_in_channel_swap(struct device *dev, int idx, bool channel_swap) +{ + mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4, + BIT(4), channel_swap << 4); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_channel_swap); + void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val) { if (val) diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h index 127f1b888ace..a4708859c188 100644 --- a/include/linux/soc/mediatek/mtk-mmsys.h +++ b/include/linux/soc/mediatek/mtk-mmsys.h @@ -75,4 +75,13 @@ void mtk_mmsys_ddp_disconnect(struct device *dev, void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val); +void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height); + +void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height); + +void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha, + u8 mode, u32 biwidth); + +void mtk_mmsys_mixer_in_channel_swap(struct device *dev, int idx, bool channel_swap); + #endif /* __MTK_MMSYS_H */ -- 2.18.0
[PATCH v28 02/11] dt-bindings: reset: mt8195: add vdosys1 reset control bit
Add vdosys1 reset control bit for MT8195 platform. Signed-off-by: Nancy.Lin Reviewed-by: Chun-Kuang Hu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rex-BC Chen Acked-by: Krzysztof Kozlowski Acked-by: Philipp Zabel Tested-by: AngeloGioacchino Del Regno --- include/dt-bindings/reset/mt8195-resets.h | 45 +++ 1 file changed, 45 insertions(+) diff --git a/include/dt-bindings/reset/mt8195-resets.h b/include/dt-bindings/reset/mt8195-resets.h index 24ab3631dcea..e61660438d61 100644 --- a/include/dt-bindings/reset/mt8195-resets.h +++ b/include/dt-bindings/reset/mt8195-resets.h @@ -35,4 +35,49 @@ #define MT8195_INFRA_RST2_PCIE_P1_SWRST4 #define MT8195_INFRA_RST2_USBSIF_P1_SWRST 5 +/* VDOSYS1 */ +#define MT8195_VDOSYS1_SW0_RST_B_SMI_LARB2 0 +#define MT8195_VDOSYS1_SW0_RST_B_SMI_LARB3 1 +#define MT8195_VDOSYS1_SW0_RST_B_GALS 2 +#define MT8195_VDOSYS1_SW0_RST_B_FAKE_ENG0 3 +#define MT8195_VDOSYS1_SW0_RST_B_FAKE_ENG1 4 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA0 5 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA1 6 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA2 7 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA3 8 +#define MT8195_VDOSYS1_SW0_RST_B_VPP_MERGE09 +#define MT8195_VDOSYS1_SW0_RST_B_VPP_MERGE110 +#define MT8195_VDOSYS1_SW0_RST_B_VPP_MERGE211 +#define MT8195_VDOSYS1_SW0_RST_B_VPP_MERGE312 +#define MT8195_VDOSYS1_SW0_RST_B_VPP_MERGE413 +#define MT8195_VDOSYS1_SW0_RST_B_VPP2_TO_VDO1_DL_ASYNC 14 +#define MT8195_VDOSYS1_SW0_RST_B_VPP3_TO_VDO1_DL_ASYNC 15 +#define MT8195_VDOSYS1_SW0_RST_B_DISP_MUTEX16 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA4 17 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA5 18 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA6 19 +#define MT8195_VDOSYS1_SW0_RST_B_MDP_RDMA7 20 +#define MT8195_VDOSYS1_SW0_RST_B_DP_INTF0 21 +#define MT8195_VDOSYS1_SW0_RST_B_DPI0 22 +#define MT8195_VDOSYS1_SW0_RST_B_DPI1 23 +#define MT8195_VDOSYS1_SW0_RST_B_DISP_MONITOR 24 +#define MT8195_VDOSYS1_SW0_RST_B_MERGE0_DL_ASYNC 25 +#define MT8195_VDOSYS1_SW0_RST_B_MERGE1_DL_ASYNC 26 +#define MT8195_VDOSYS1_SW0_RST_B_MERGE2_DL_ASYNC 27 +#define MT8195_VDOSYS1_SW0_RST_B_MERGE3_DL_ASYNC 28 +#define MT8195_VDOSYS1_SW0_RST_B_MERGE4_DL_ASYNC 29 +#define MT8195_VDOSYS1_SW0_RST_B_VDO0_DSC_TO_VDO1_DL_ASYNC 30 +#define MT8195_VDOSYS1_SW0_RST_B_VDO0_MERGE_TO_VDO1_DL_ASYNC 31 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE0 32 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE0 33 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_BE34 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE1 48 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE1 49 +#define MT8195_VDOSYS1_SW1_RST_B_DISP_MIXER50 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE0_DL_ASYNC 51 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_FE1_DL_ASYNC 52 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE0_DL_ASYNC 53 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_GFX_FE1_DL_ASYNC 54 +#define MT8195_VDOSYS1_SW1_RST_B_HDR_VDO_BE_DL_ASYNC 55 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8195 */ -- 2.18.0
[PATCH v28 00/11] Add MediaTek SoC(vdosys1) support for mt8195
The hardware path of vdosys1 with DPTx output need to go through by several modules, such as, OVL_ADAPTOR and MERGE. Add mmsys and mutex modules support by the patches below: Changes in v28: - rebase to next-20221107 - fix reviewer comment in v27 - remove change id - fix mmsys config api typo Changes in v27: - rebase to next-20221102 - change mmsys compatible for mt8195 vdosys1 - base on jason's series[ref 1] - fix reviewer comment - only register mmsys reset controller if num_resets > 0 Changes in v26: - fix reviewer comment - set mmsys num_resets to 32 for 8192 - rebase to next-20220819 Changes in v25: - fix reviewer comment - refine mtk_mmsys_reset_update func - rebase to next-20220708 Changes in v24: - fix reviewer comment - refine mtk_mmsys_reset_update func - rebase to next-20220622 Changes in v23: - separate[7] mmsys/mutex and drm patches into two series Changes in v22: - rebase to next-20220525 - rebase to vdosys0 series v22 - separate dts to a new patch Changes in v21: - fix reviewer comment - fix rdma and ethdr binding doc and dts Changes in v20: - fix reviewer comment - update mmsys update bit api name - add mtk_mmsys_update_bits error message if lose gce property - list all mt8195 vdosys1 reset bits Changes in v19: - fix reviewer comment - separate mt8195 mmsys component to a new patch - separate mt8195 vdo0 and vdo1 routing table - separate mmsys_write_reg api to a new patch and simplify write reg code - separate mmsys 64 bit reset to a new patch - separate mtk-mutex dp_intf1 component to a new patch Changes in v18: - fix reviewer comment - fix rdma binding doc - fix ethdr binding doc - refine mmsys config cmdq support - refine merge reset control flow, get reset control in probe function - add ethdr reset control error handling and remove dbg log - rebase to vdosys0 series v20 (ref [5]) Changes in v17: - fix reviewer comment in v16 - separate ovl adaptor comp in mtk-mmsys and mtk-mutex - separate mmsys config API - move mdp_rdma binding yaml - fix ovl adaptor pm runtime get sync timing issue - rebase to vdosys0 series v19 (ref [5]) - rebase to [7] for modify vblank register change Changes in v16: - fix reviewer comment in v 15 - fix mtk_drm_ddp_comp.c alignment - fix vdosys0 mmsys num before adding vdosys1 patch Changes in v15: - fix ethdr uppercase hex number in dts Changes in v14: - remove MTK_MMSYS 64 bit dependency - add ethdr.yaml back and fix dt_schema check fail Resend v13 - add related maintainer in maillist Changes in v13: - fix reviewer comment in v12 - fix rdma dt-binding format - fix dts node naming - fix 32 bit build error - modify 64bit dependency for mtk-mmsys - rebase to vdosys0 series v16. (ref [5]) Changes in v12: - fix reviewer comment in v11 - modify mbox index - refine dma dev for ovl_adaptor sub driver Changes in v11: - remove ethdr vblank spin lock - refine ovl_adaptor print message Changes in v10: - refine ethdr reset control using devm_reset_control_array_get_optional_exclusive - fix ovl_adaptor mtk_ovl_adaptor_clk_enable error handle issue Changes in v9: - rebase on kernel-5.16-rc1 - rebase on vdosys0 series v13. (ref [5]) - fix ovl_adaptor sub driver is brought up unintentionally - fix clang build test fail- duplicate ethdr/mdp_rdma init_module/cleanup_module symbol issue Changes in v8: - separate merge async reset to new patch. - separate drm ovl_adaptor sub driver to new patch. - fix reviewer comment in v7. Changes in v7: - rebase on vdosys0 series v12 (ref[5]) - add dma description in ethdr binding document. - refine vdosys1 bit definition of mmsys routing table. - separate merge modification into 3 pathces. - separate mutex modification into 2 patches. - add plane color coding for mdp_rdma csc. - move mdp_rdma pm control to ovl_adaptor. - fix reviewer comment in v6. Changes in v6: - rebase on kernel-5.15-rc1. - change mbox label to gce0 for dts node of vdosys1. - modify mmsys reset num for mt8195. - rebase on vdosys0 series v10. (ref [5]) - use drm to bring up ovl_adaptor driver. - move drm iommu/mutex check from kms init to drm bind. - modify rdma binding doc location. (Documentation/devicetree/bindings/arm/) - modify for reviewer's comment in v5. Changes in v5: - add mmsys reset controller reference. Changes in v4: - use merge common driver for merge1~4. - refine ovl_adaptor rdma driver. - use ovl_adaptor ddp_comp function instead of ethdr. - modify for reviewer's comment in v3. Changes in v3: - modify for reviewer's comment in v2. - add vdosys1 2 pixels align limit. - add mixer odd offset support. Changes in v2: - Merge PSEUDO_OVL and ETHDR into one DRM component. - Add mmsys config API for vdosys1 hardware setting. - Add mmsys reset control using linux reset framework. Signed-off-by: Nancy.Lin This series are based on the following patch: [1] Change mmsys compatible for mt8195 mediatek-drm 20220927152704.12018-1-jason-jh@mediatek.com Nancy.Lin (11): d
[PATCH v28 08/11] soc: mediatek: mmsys: add mmsys for support 64 reset bits
Add mmsys for support 64 reset bits. It is a preparation for MT8195 vdosys1 HW reset. MT8195 vdosys1 has more than 32 reset bits. 1. Add the number of reset bits in mmsys private data 2. move the whole "reset register code section" behind the "get mmsys->data" code section for getting the num_resets in mmsys->data. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: Bo-Chen Chen Reviewed-by: Nícolas F. R. A. Prado --- drivers/soc/mediatek/mtk-mmsys.c | 40 +--- drivers/soc/mediatek/mtk-mmsys.h | 1 + 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 1bd2f8e45d85..78601372512f 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -20,6 +20,8 @@ #include "mt8195-mmsys.h" #include "mt8365-mmsys.h" +#define MMSYS_SW_RESET_PER_REG 32 + static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { .clk_driver = "clk-mt2701-mm", .routes = mmsys_default_routing_table, @@ -51,6 +53,7 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { .routes = mmsys_default_routing_table, .num_routes = ARRAY_SIZE(mmsys_default_routing_table), .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B, + .num_resets = 32, }; static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { @@ -58,6 +61,7 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { .routes = mmsys_mt8183_routing_table, .num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table), .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B, + .num_resets = 32, }; static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { @@ -65,6 +69,7 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = { .routes = mmsys_mt8186_routing_table, .num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table), .sw0_rst_offset = MT8186_MMSYS_SW0_RST_B, + .num_resets = 32, }; static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { @@ -72,6 +77,7 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { .routes = mmsys_mt8192_routing_table, .num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table), .sw0_rst_offset = MT8186_MMSYS_SW0_RST_B, + .num_resets = 32, }; static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = { @@ -206,13 +212,19 @@ static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned l { struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev); unsigned long flags; + u32 offset; + u32 reg; + + offset = (id / MMSYS_SW_RESET_PER_REG) * sizeof(u32); + id = id % MMSYS_SW_RESET_PER_REG; + reg = mmsys->data->sw0_rst_offset + offset; spin_lock_irqsave(&mmsys->lock, flags); if (assert) - mtk_mmsys_update_bits(mmsys, mmsys->data->sw0_rst_offset, BIT(id), 0, NULL); + mtk_mmsys_update_bits(mmsys, reg, BIT(id), 0, NULL); else - mtk_mmsys_update_bits(mmsys, mmsys->data->sw0_rst_offset, BIT(id), BIT(id), NULL); + mtk_mmsys_update_bits(mmsys, reg, BIT(id), BIT(id), NULL); spin_unlock_irqrestore(&mmsys->lock, flags); @@ -267,20 +279,22 @@ static int mtk_mmsys_probe(struct platform_device *pdev) return ret; } - spin_lock_init(&mmsys->lock); + mmsys->data = of_device_get_match_data(&pdev->dev); - mmsys->rcdev.owner = THIS_MODULE; - mmsys->rcdev.nr_resets = 32; - mmsys->rcdev.ops = &mtk_mmsys_reset_ops; - mmsys->rcdev.of_node = pdev->dev.of_node; - ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev); - if (ret) { - dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret); - return ret; + if (mmsys->data->num_resets > 0) { + spin_lock_init(&mmsys->lock); + + mmsys->rcdev.owner = THIS_MODULE; + mmsys->rcdev.nr_resets = mmsys->data->num_resets; + mmsys->rcdev.ops = &mtk_mmsys_reset_ops; + mmsys->rcdev.of_node = pdev->dev.of_node; + ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev); + if (ret) { + dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret); + return ret; + } } - mmsys->data = of_device_get_match_data(&pdev->dev); - #if IS_REACHABLE(CONFIG_MTK_CMDQ) ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0); if (ret) diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h index 77f37f8c715b..e19994749adb 100644 --- a/drivers/soc/mediatek/mtk-mmsys.h +++ b/drivers/soc/mediatek/mtk-mmsys.h @@
[PATCH v28 01/11] dt-bindings: arm: mediatek: mmsys: add vdosys1 compatible for MT8195
Add vdosys1 mmsys compatible for MT8195 platform. For MT8195, VDOSYS0 and VDOSYS1 are 2 display HW pipelines binding to 2 different power domains, different clock drivers and different mediatek-drm drivers. Signed-off-by: Nancy.Lin Reviewed-by: Nícolas F. R. A. Prado --- .../devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml index 0711f1834fbd..aaabe2196185 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml @@ -48,7 +48,9 @@ properties: - const: syscon - items: - - const: mediatek,mt8195-vdosys0 + - enum: + - mediatek,mt8195-vdosys0 + - mediatek,mt8195-vdosys1 - const: mediatek,mt8195-mmsys - const: syscon -- 2.18.0
[PATCH v28 05/11] soc: mediatek: refine code to use mtk_mmsys_update_bits API
Simplify code for update mmsys reg. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen Reviewed-by: Nícolas F. R. A. Prado --- drivers/soc/mediatek/mtk-mmsys.c | 45 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 9a327eb5d9d7..73c8bd27e6ae 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -99,22 +99,27 @@ struct mtk_mmsys { struct reset_controller_dev rcdev; }; +static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val) +{ + u32 tmp; + + tmp = readl_relaxed(mmsys->regs + offset); + tmp = (tmp & ~mask) | (val & mask); + writel_relaxed(tmp, mmsys->regs + offset); +} + void mtk_mmsys_ddp_connect(struct device *dev, enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next) { struct mtk_mmsys *mmsys = dev_get_drvdata(dev); const struct mtk_mmsys_routes *routes = mmsys->data->routes; - u32 reg; int i; for (i = 0; i < mmsys->data->num_routes; i++) - if (cur == routes[i].from_comp && next == routes[i].to_comp) { - reg = readl_relaxed(mmsys->regs + routes[i].addr); - reg &= ~routes[i].mask; - reg |= routes[i].val; - writel_relaxed(reg, mmsys->regs + routes[i].addr); - } + if (cur == routes[i].from_comp && next == routes[i].to_comp) + mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, + routes[i].val); } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect); @@ -124,27 +129,14 @@ void mtk_mmsys_ddp_disconnect(struct device *dev, { struct mtk_mmsys *mmsys = dev_get_drvdata(dev); const struct mtk_mmsys_routes *routes = mmsys->data->routes; - u32 reg; int i; for (i = 0; i < mmsys->data->num_routes; i++) - if (cur == routes[i].from_comp && next == routes[i].to_comp) { - reg = readl_relaxed(mmsys->regs + routes[i].addr); - reg &= ~routes[i].mask; - writel_relaxed(reg, mmsys->regs + routes[i].addr); - } + if (cur == routes[i].from_comp && next == routes[i].to_comp) + mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0); } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect); -static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val) -{ - u32 tmp; - - tmp = readl_relaxed(mmsys->regs + offset); - tmp = (tmp & ~mask) | val; - writel_relaxed(tmp, mmsys->regs + offset); -} - void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val) { if (val) @@ -161,18 +153,13 @@ static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned l { struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev); unsigned long flags; - u32 reg; spin_lock_irqsave(&mmsys->lock, flags); - reg = readl_relaxed(mmsys->regs + mmsys->data->sw0_rst_offset); - if (assert) - reg &= ~BIT(id); + mtk_mmsys_update_bits(mmsys, mmsys->data->sw0_rst_offset, BIT(id), 0); else - reg |= BIT(id); - - writel_relaxed(reg, mmsys->regs + mmsys->data->sw0_rst_offset); + mtk_mmsys_update_bits(mmsys, mmsys->data->sw0_rst_offset, BIT(id), BIT(id)); spin_unlock_irqrestore(&mmsys->lock, flags); -- 2.18.0
[PATCH v28 07/11] soc: mediatek: add cmdq support of mtk-mmsys config API for mt8195 vdosys1
Add cmdq support for mtk-mmsys config API. The mmsys config register settings need to take effect with the other HW settings(like OVL_ADAPTOR...) at the same vblanking time. If we use CPU to write the mmsys reg, we can't guarantee all the settings can be written in the same vblanking time. Cmdq is used for this purpose. We prepare all the related HW settings in one cmdq packet. The first command in the packet is "wait stream done", and then following with all the HW settings. After the cmdq packet is flush to GCE HW. The GCE waits for the "stream done event" to coming and then starts flushing all the HW settings. This can guarantee all the settings flush in the same vblanking. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mtk-mmsys.c | 59 ++ include/linux/soc/mediatek/mtk-mmsys.h | 15 +-- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 6040a3cff6f8..1bd2f8e45d85 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -97,12 +97,27 @@ struct mtk_mmsys { const struct mtk_mmsys_driver_data *data; spinlock_t lock; /* protects mmsys_sw_rst_b reg */ struct reset_controller_dev rcdev; + struct cmdq_client_reg cmdq_base; }; -static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val) +static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val, + struct cmdq_pkt *cmdq_pkt) { u32 tmp; +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (cmdq_pkt) { + if (mmsys->cmdq_base.size == 0) { + pr_err("mmsys lose gce property, failed to update mmsys bits with cmdq"); + return; + } + cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys, + mmsys->cmdq_base.offset + offset, val, + mask); + return; + } +#endif + tmp = readl_relaxed(mmsys->regs + offset); tmp = (tmp & ~mask) | (val & mask); writel_relaxed(tmp, mmsys->regs + offset); @@ -119,7 +134,7 @@ void mtk_mmsys_ddp_connect(struct device *dev, for (i = 0; i < mmsys->data->num_routes; i++) if (cur == routes[i].from_comp && next == routes[i].to_comp) mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, - routes[i].val); + routes[i].val, NULL); } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect); @@ -133,42 +148,45 @@ void mtk_mmsys_ddp_disconnect(struct device *dev, for (i = 0; i < mmsys->data->num_routes; i++) if (cur == routes[i].from_comp && next == routes[i].to_comp) - mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0); + mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL); } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect); -void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height) +void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height, + struct cmdq_pkt *cmdq_pkt) { mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MERGE0_ASYNC_CFG_WD + 0x10 * idx, - ~0, height << 16 | width); + ~0, height << 16 | width, cmdq_pkt); } EXPORT_SYMBOL_GPL(mtk_mmsys_merge_async_config); -void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height) +void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height, + struct cmdq_pkt *cmdq_pkt) { mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_HDRBE_ASYNC_CFG_WD, ~0, - be_height << 16 | be_width); + be_height << 16 | be_width, cmdq_pkt); } EXPORT_SYMBOL_GPL(mtk_mmsys_hdr_config); void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha, - u8 mode, u32 biwidth) + u8 mode, u32 biwidth, struct cmdq_pkt *cmdq_pkt) { struct mtk_mmsys *mmsys = dev_get_drvdata(dev); mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0, - alpha << 16 | alpha); + alpha << 16 | alpha, cmdq_pkt); mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx), - alpha_sel << (19 + idx)); + alpha_sel << (19 + idx), cmdq_pkt); mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1
[PATCH v28 10/11] soc: mediatek: add mtk-mutex component - dp_intf1
Add mtk-mutex DDP_COMPONENT_DP_INTF1 component. The MT8195 vdosys1 path component contains ovl_adaptor, merge5, and dp_intf1. It is a preparation for adding support for MT8195 vdosys1 path component. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mtk-mutex.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index c1a33d52038e..41cba6aa0e83 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -602,6 +602,9 @@ void mtk_mutex_add_comp(struct mtk_mutex *mutex, case DDP_COMPONENT_DP_INTF0: sof_id = MUTEX_SOF_DP_INTF0; break; + case DDP_COMPONENT_DP_INTF1: + sof_id = MUTEX_SOF_DP_INTF1; + break; default: if (mtx->data->mutex_mod[id] < 32) { offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, @@ -642,6 +645,7 @@ void mtk_mutex_remove_comp(struct mtk_mutex *mutex, case DDP_COMPONENT_DPI0: case DDP_COMPONENT_DPI1: case DDP_COMPONENT_DP_INTF0: + case DDP_COMPONENT_DP_INTF1: writel_relaxed(MUTEX_SOF_SINGLE_MODE, mtx->regs + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, -- 2.18.0
[PATCH v28 11/11] soc: mediatek: add mtk-mutex support for mt8195 vdosys1
Add mtk-mutex support for mt8195 vdosys1. The vdosys1 path component contains ovl_adaptor, merge5, and dp_intf1. Ovl_adaptor is composed of several sub-elements which include MDP_RDMA0~7, MERGE0~3, and ETHDR. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mtk-mutex.c | 33 1 file changed, 33 insertions(+) diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index 41cba6aa0e83..8d0eb70690e5 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -130,6 +130,24 @@ #define MT8195_MUTEX_MOD_DISP_DP_INTF0 21 #define MT8195_MUTEX_MOD_DISP_PWM0 27 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 0 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 1 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 2 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 3 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 4 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 5 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 6 +#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 7 +#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 8 +#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 9 +#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 10 +#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 11 +#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 12 +#define MT8195_MUTEX_MOD_DISP1_DISP_MIXER 18 +#define MT8195_MUTEX_MOD_DISP1_DPI025 +#define MT8195_MUTEX_MOD_DISP1_DPI126 +#define MT8195_MUTEX_MOD_DISP1_DP_INTF027 + #define MT8365_MUTEX_MOD_DISP_OVL0 7 #define MT8365_MUTEX_MOD_DISP_OVL0_2L 8 #define MT8365_MUTEX_MOD_DISP_RDMA09 @@ -372,6 +390,21 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DSI0] = MT8195_MUTEX_MOD_DISP_DSI0, [DDP_COMPONENT_PWM0] = MT8195_MUTEX_MOD_DISP_PWM0, [DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0, + [DDP_COMPONENT_MDP_RDMA0] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA0, + [DDP_COMPONENT_MDP_RDMA1] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA1, + [DDP_COMPONENT_MDP_RDMA2] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA2, + [DDP_COMPONENT_MDP_RDMA3] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA3, + [DDP_COMPONENT_MDP_RDMA4] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA4, + [DDP_COMPONENT_MDP_RDMA5] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA5, + [DDP_COMPONENT_MDP_RDMA6] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA6, + [DDP_COMPONENT_MDP_RDMA7] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA7, + [DDP_COMPONENT_MERGE1] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE0, + [DDP_COMPONENT_MERGE2] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE1, + [DDP_COMPONENT_MERGE3] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE2, + [DDP_COMPONENT_MERGE4] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE3, + [DDP_COMPONENT_ETHDR_MIXER] = MT8195_MUTEX_MOD_DISP1_DISP_MIXER, + [DDP_COMPONENT_MERGE5] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE4, + [DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0, }; static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = { -- 2.18.0
[PATCH v28 09/11] soc: mediatek: mmsys: add reset control for MT8195 vdosys1
MT8195 vdosys1 has more than 32 reset bits and a different reset base than other chips. Add the number of reset bits and reset base in mmsys private data. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/soc/mediatek/mt8195-mmsys.h | 1 + drivers/soc/mediatek/mtk-mmsys.c| 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h index 454944a9409c..a6652ae63431 100644 --- a/drivers/soc/mediatek/mt8195-mmsys.h +++ b/drivers/soc/mediatek/mt8195-mmsys.h @@ -75,6 +75,7 @@ #define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16) #define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16) +#define MT8195_VDO1_SW0_RST_B 0x1d0 #define MT8195_VDO1_MERGE0_ASYNC_CFG_WD0xe30 #define MT8195_VDO1_HDRBE_ASYNC_CFG_WD 0xe70 #define MT8195_VDO1_HDR_TOP_CFG0xd00 diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 78601372512f..5278edd032c6 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -90,6 +90,8 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { .clk_driver = "clk-mt8195-vdo1", .routes = mmsys_mt8195_vdo1_routing_table, .num_routes = ARRAY_SIZE(mmsys_mt8195_vdo1_routing_table), + .sw0_rst_offset = MT8195_VDO1_SW0_RST_B, + .num_resets = 64, }; static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = { -- 2.18.0
[PATCH v28 03/11] soc: mediatek: add mtk-mmsys ethdr and mdp_rdma components
Add new mmsys component: ethdr_mixer and mdp_rdma. These components will use in mt8195 vdosys1. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- include/linux/soc/mediatek/mtk-mmsys.h | 9 + 1 file changed, 9 insertions(+) diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h index 16ac0e5847f0..127f1b888ace 100644 --- a/include/linux/soc/mediatek/mtk-mmsys.h +++ b/include/linux/soc/mediatek/mtk-mmsys.h @@ -28,7 +28,16 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_DSI1, DDP_COMPONENT_DSI2, DDP_COMPONENT_DSI3, + DDP_COMPONENT_ETHDR_MIXER, DDP_COMPONENT_GAMMA, + DDP_COMPONENT_MDP_RDMA0, + DDP_COMPONENT_MDP_RDMA1, + DDP_COMPONENT_MDP_RDMA2, + DDP_COMPONENT_MDP_RDMA3, + DDP_COMPONENT_MDP_RDMA4, + DDP_COMPONENT_MDP_RDMA5, + DDP_COMPONENT_MDP_RDMA6, + DDP_COMPONENT_MDP_RDMA7, DDP_COMPONENT_MERGE0, DDP_COMPONENT_MERGE1, DDP_COMPONENT_MERGE2, -- 2.18.0
[PATCH v28 7/7] drm/mediatek: add mediatek-drm of vdosys1 support for MT8195
Add driver data of mt8195 vdosys1 to mediatek-drm. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 17 - 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 41b5256f4c8d..cf24788a47c1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -208,6 +208,12 @@ static const unsigned int mt8195_mtk_ddp_main[] = { DDP_COMPONENT_DP_INTF0, }; +static const unsigned int mt8195_mtk_ddp_ext[] = { + DDP_COMPONENT_DRM_OVL_ADAPTOR, + DDP_COMPONENT_MERGE5, + DDP_COMPONENT_DP_INTF1, +}; + static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { .main_path = mt2701_mtk_ddp_main, .main_len = ARRAY_SIZE(mt2701_mtk_ddp_main), @@ -277,7 +283,14 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = { static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = { .main_path = mt8195_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8195_mtk_ddp_main), - .mmsys_dev_num = 1, + .mmsys_dev_num = 2, +}; + +static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = { + .ext_path = mt8195_mtk_ddp_ext, + .ext_len = ARRAY_SIZE(mt8195_mtk_ddp_ext), + .mmsys_id = 1, + .mmsys_dev_num = 2, }; static const struct of_device_id mtk_drm_of_ids[] = { @@ -299,6 +312,8 @@ static const struct of_device_id mtk_drm_of_ids[] = { .data = &mt8192_mmsys_driver_data}, { .compatible = "mediatek,mt8195-vdosys0", .data = &mt8195_vdosys0_driver_data}, + { .compatible = "mediatek,mt8195-vdosys1", + .data = &mt8195_vdosys1_driver_data}, { } }; MODULE_DEVICE_TABLE(of, mtk_drm_of_ids); -- 2.18.0
[PATCH v28 4/7] drm/mediatek: add dma dev get function
This is a preparation for adding support for the ovl_adaptor sub driver Ovl_adaptor is a DRM sub driver, which doesn't have dma dev. Add dma_dev_get function for getting representative dma dev in ovl_adaptor. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioachino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 15 +++ drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 1 + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 8 3 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 112615817dcb..78e20f604158 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -58,6 +58,7 @@ struct mtk_drm_crtc { #endif struct device *mmsys_dev; + struct device *dma_dev; struct mtk_mutex*mutex; unsigned intddp_comp_nr; struct mtk_ddp_comp **ddp_comp; @@ -865,6 +866,13 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev, return 0; } +struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) +{ + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); + + return mtk_crtc->dma_dev; +} + int mtk_drm_crtc_create(struct drm_device *drm_dev, const enum mtk_ddp_comp_id *path, unsigned int path_len) { @@ -953,6 +961,13 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, return ret; } + /* +* Default to use the first component as the dma dev. +* In the case of ovl_adaptor sub driver, it needs to use the +* dma_dev_get function to get representative dma dev. +*/ + mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]); + ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h index cb9a36c48d4f..f5a6e80c5265 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h @@ -22,5 +22,6 @@ int mtk_drm_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane, struct mtk_plane_state *state); void mtk_drm_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane, struct drm_atomic_state *plane_state); +struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc); #endif /* MTK_DRM_CRTC_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 2d0052c23dcb..364f3f7f59fa 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -71,6 +71,7 @@ struct mtk_ddp_comp_funcs { void (*bgclr_in_off)(struct device *dev); void (*ctm_set)(struct device *dev, struct drm_crtc_state *state); + struct device * (*dma_dev_get)(struct device *dev); }; struct mtk_ddp_comp { @@ -203,6 +204,13 @@ static inline void mtk_ddp_ctm_set(struct mtk_ddp_comp *comp, comp->funcs->ctm_set(comp->dev, state); } +static inline struct device *mtk_ddp_comp_dma_dev_get(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->dma_dev_get) + return comp->funcs->dma_dev_get(comp->dev); + return comp->dev; +} + int mtk_ddp_comp_get_id(struct device_node *node, enum mtk_ddp_comp_type comp_type); unsigned int mtk_drm_find_possible_crtc_by_comp(struct drm_device *drm, -- 2.18.0
[PATCH v28 5/7] drm/mediatek: modify mediatek-drm for mt8195 multi mmsys support
MT8195 have two mmsys. Modify drm for MT8195 multi-mmsys support. The two mmsys (vdosys0 and vdosys1) will bring up two drm drivers, only one drm driver register as the drm device. Each drm driver binds its own component. The last bind drm driver allocates and registers the drm device to drm core. Each crtc path is created with the corresponding drm driver data. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen Tested-by: Nícolas F. R. A. Prado --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 24 +- drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 3 +- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 292 ++-- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 10 +- 4 files changed, 243 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 78e20f604158..30dcb65d8a5a 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -874,21 +874,28 @@ struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) } int mtk_drm_crtc_create(struct drm_device *drm_dev, - const enum mtk_ddp_comp_id *path, unsigned int path_len) + const enum mtk_ddp_comp_id *path, unsigned int path_len, + int priv_data_index) { struct mtk_drm_private *priv = drm_dev->dev_private; struct device *dev = drm_dev->dev; struct mtk_drm_crtc *mtk_crtc; unsigned int num_comp_planes = 0; - int pipe = priv->num_pipes; int ret; int i; bool has_ctm = false; uint gamma_lut_size = 0; + struct drm_crtc *tmp; + int crtc_i = 0; if (!path) return 0; + priv = priv->all_drm_private[priv_data_index]; + + drm_for_each_crtc(tmp, drm_dev) + crtc_i++; + for (i = 0; i < path_len; i++) { enum mtk_ddp_comp_id comp_id = path[i]; struct device_node *node; @@ -900,7 +907,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, if (!node) { dev_info(dev, "Not creating crtc %d because component %d is disabled or missing\n", -pipe, comp_id); +crtc_i, comp_id); return 0; } @@ -956,7 +963,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i, - pipe); + crtc_i); if (ret) return ret; } @@ -968,24 +975,23 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, */ mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]); - ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe); + ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, crtc_i); if (ret < 0) return ret; if (gamma_lut_size) drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size); drm_crtc_enable_color_mgmt(&mtk_crtc->base, 0, has_ctm, gamma_lut_size); - priv->num_pipes++; mutex_init(&mtk_crtc->hw_lock); #if IS_REACHABLE(CONFIG_MTK_CMDQ) + i = priv->mbox_index++; mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev; mtk_crtc->cmdq_client.client.tx_block = false; mtk_crtc->cmdq_client.client.knows_txdone = true; mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb; mtk_crtc->cmdq_client.chan = - mbox_request_channel(&mtk_crtc->cmdq_client.client, -drm_crtc_index(&mtk_crtc->base)); + mbox_request_channel(&mtk_crtc->cmdq_client.client, i); if (IS_ERR(mtk_crtc->cmdq_client.chan)) { dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", drm_crtc_index(&mtk_crtc->base)); @@ -995,7 +1001,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, if (mtk_crtc->cmdq_client.chan) { ret = of_property_read_u32_index(priv->mutex_node, "mediatek,gce-events", - drm_crtc_index(&mtk_crtc->base), +i, &mtk_crtc->cmdq_event); if (ret) { dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.h b/drivers/gpu/drm/mediatek/mtk_drm_crtc.h index f5a6e80c5265..606f72f35924 10064
[PATCH v28 0/7] Add MediaTek SoC DRM (vdosys1) support for mt8195
The hardware path of vdosys1 with DPTx output need to go through by several modules, such as, OVL_ADAPTOR and MERGE. Add DRM and these modules support by the patches below: Changes in v28: - rebase to next-20221107 - fix reviewer comment in v27 - extra new line at the end mtk_ethdr.h Changes in v27: - rebase to next-20221102 - change mmsys compatible for mt8195 vdosys1 - base on jason's series[ref 1] - fix reviewer comment - add error return code if no ovl_adaptor's comp found Changes in v26: - rebase to next-20220819 - resend for patch corrupted in v25 Changes in v25: - rebase to next-20220803 Changes in v24: - fix ovl_adaptor binding issue (mtk_disp_ovl_adaptor.c) - Since ovl_adaptor is an aggregated component, it should be bounded after all its child components are bounded. - rebase to next-20220708 Changes in v23: - separate[7] mmsys/mutex and drm patches into two series Changes in v22: - rebase to next-20220525 - rebase to vdosys0 series v22 - separate dts to a new patch Changes in v21: - fix reviewer comment - fix rdma and ethdr binding doc and dts Changes in v20: - fix reviewer comment - update mmsys update bit api name - add mtk_mmsys_update_bits error message if lose gce property - list all mt8195 vdosys1 reset bits Changes in v19: - fix reviewer comment - separate mt8195 mmsys component to a new patch - separate mt8195 vdo0 and vdo1 routing table - separate mmsys_write_reg api to a new patch and simplify write reg code - separate mmsys 64 bit reset to a new patch - separate mtk-mutex dp_intf1 component to a new patch Changes in v18: - fix reviewer comment - fix rdma binding doc - fix ethdr binding doc - refine mmsys config cmdq support - refine merge reset control flow, get reset control in probe function - add ethdr reset control error handling and remove dbg log - rebase to vdosys0 series v20 (ref [5]) Changes in v17: - fix reviewer comment in v16 - separate ovl adaptor comp in mtk-mmsys and mtk-mutex - separate mmsys config API - move mdp_rdma binding yaml - fix ovl adaptor pm runtime get sync timing issue - rebase to vdosys0 series v19 (ref [5]) - rebase to [7] for modify vblank register change Changes in v16: - fix reviewer comment in v 15 - fix mtk_drm_ddp_comp.c alignment - fix vdosys0 mmsys num before adding vdosys1 patch Changes in v15: - fix ethdr uppercase hex number in dts Changes in v14: - remove MTK_MMSYS 64 bit dependency - add ethdr.yaml back and fix dt_schema check fail Resend v13 - add related maintainer in maillist Changes in v13: - fix reviewer comment in v12 - fix rdma dt-binding format - fix dts node naming - fix 32 bit build error - modify 64bit dependency for mtk-mmsys - rebase to vdosys0 series v16. (ref [5]) Changes in v12: - fix reviewer comment in v11 - modify mbox index - refine dma dev for ovl_adaptor sub driver Changes in v11: - remove ethdr vblank spin lock - refine ovl_adaptor print message Changes in v10: - refine ethdr reset control using devm_reset_control_array_get_optional_exclusive - fix ovl_adaptor mtk_ovl_adaptor_clk_enable error handle issue Changes in v9: - rebase on kernel-5.16-rc1 - rebase on vdosys0 series v13. (ref [5]) - fix ovl_adaptor sub driver is brought up unintentionally - fix clang build test fail- duplicate ethdr/mdp_rdma init_module/cleanup_module symbol issue Changes in v8: - separate merge async reset to new patch. - separate drm ovl_adaptor sub driver to new patch. - fix reviewer comment in v7. Changes in v7: - rebase on vdosys0 series v12 (ref[5]) - add dma description in ethdr binding document. - refine vdosys1 bit definition of mmsys routing table. - separate merge modification into 3 pathces. - separate mutex modification into 2 patches. - add plane color coding for mdp_rdma csc. - move mdp_rdma pm control to ovl_adaptor. - fix reviewer comment in v6. Changes in v6: - rebase on kernel-5.15-rc1. - change mbox label to gce0 for dts node of vdosys1. - modify mmsys reset num for mt8195. - rebase on vdosys0 series v10. (ref [5]) - use drm to bring up ovl_adaptor driver. - move drm iommu/mutex check from kms init to drm bind. - modify rdma binding doc location. (Documentation/devicetree/bindings/arm/) - modify for reviewer's comment in v5. Changes in v5: - add mmsys reset controller reference. Changes in v4: - use merge common driver for merge1~4. - refine ovl_adaptor rdma driver. - use ovl_adaptor ddp_comp function instead of ethdr. - modify for reviewer's comment in v3. Changes in v3: - modify for reviewer's comment in v2. - add vdosys1 2 pixels align limit. - add mixer odd offset support. Changes in v2: - Merge PSEUDO_OVL and ETHDR into one DRM component. - Add mmsys config API for vdosys1 hardware setting. - Add mmsys reset control using linux reset framework. Signed-off-by: Nancy.Lin This series are based on the following patch: [1] Change mmsys compatible for mt8195 mediatek-drm 20220927152704.12018-1-jason-jh@mediatek.com [2] Add
[PATCH v28 6/7] drm/mediatek: add drm ovl_adaptor sub driver for MT8195
Add drm ovl_adaptor sub driver. Bring up ovl_adaptor sub driver if the component exists in the path. Signed-off-by: Nancy.Lin Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: CK Hu Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen Tested-by: Nícolas F. R. A. Prado --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 61 - drivers/gpu/drm/mediatek/mtk_drm_crtc.h | 2 +- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 129 drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 50 +++- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 78 ++-- drivers/gpu/drm/mediatek/mtk_drm_drv.h | 12 +- 6 files changed, 209 insertions(+), 123 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 30dcb65d8a5a..ce5617ad04cb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -379,13 +379,17 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc) } for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { - mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, - mtk_crtc->ddp_comp[i]->id, - mtk_crtc->ddp_comp[i + 1]->id); - mtk_mutex_add_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); + if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i + 1]->id)) + mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev, + mtk_crtc->ddp_comp[i]->id, + mtk_crtc->ddp_comp[i + 1]->id); + if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_add_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); } - mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); + if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); mtk_mutex_enable(mtk_crtc->mutex); for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { @@ -434,17 +438,22 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_drm_crtc *mtk_crtc) } for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) - mtk_mutex_remove_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); mtk_mutex_disable(mtk_crtc->mutex); for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) { - mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, -mtk_crtc->ddp_comp[i]->id, -mtk_crtc->ddp_comp[i + 1]->id); - mtk_mutex_remove_comp(mtk_crtc->mutex, - mtk_crtc->ddp_comp[i]->id); + if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev, +mtk_crtc->ddp_comp[i + 1]->id)) + mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev, +mtk_crtc->ddp_comp[i]->id, +mtk_crtc->ddp_comp[i + 1]->id); + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, + mtk_crtc->ddp_comp[i]->id); } - mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); + if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex)) + mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id); mtk_crtc_ddp_clk_disable(mtk_crtc); mtk_mutex_unprepare(mtk_crtc->mutex); @@ -874,7 +883,7 @@ struct device *mtk_drm_crtc_dma_dev_get(struct drm_crtc *crtc) } int mtk_drm_crtc_create(struct drm_device *drm_dev, - const enum mtk_ddp_comp_id *path, unsigned int path_len, + const unsigned int *path, unsigned int path_len, int priv_data_index) { struct mtk_drm_private *priv = drm_dev->dev_private; @@ -897,22 +906,18 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, crtc_i++; for (i = 0; i < path_len; i++) { - enum mtk_ddp_comp_id comp_id = path[i]; + unsigned int comp_id = path[i]; struct device_node *node; - struct mtk_ddp_comp *comp; node = priv->comp_node[comp_id]; -
[PATCH v28 2/7] drm/mediatek: add ETHDR support for MT8195
ETHDR is a part of ovl_adaptor. ETHDR is designed for HDR video and graphics conversion in the external display path. It handles multiple HDR input types and performs tone mapping, color space/color format conversion, and then combine different layers, output the required HDR or SDR signal to the subsequent display path. Signed-off-by: Nancy.Lin Reviewed-by: Chun-Kuang Hu Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/gpu/drm/mediatek/Makefile | 1 + drivers/gpu/drm/mediatek/mtk_drm_drv.c | 1 + drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 + drivers/gpu/drm/mediatek/mtk_ethdr.c | 370 + drivers/gpu/drm/mediatek/mtk_ethdr.h | 25 ++ 5 files changed, 398 insertions(+) create mode 100644 drivers/gpu/drm/mediatek/mtk_ethdr.c create mode 100644 drivers/gpu/drm/mediatek/mtk_ethdr.h diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 3517d1c65cd7..840f14436d3c 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -14,6 +14,7 @@ mediatek-drm-y := mtk_disp_aal.o \ mtk_drm_plane.o \ mtk_dsi.o \ mtk_dpi.o \ + mtk_ethdr.o \ mtk_mdp_rdma.o obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index a6941b295641..43633d670ef4 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -771,6 +771,7 @@ static struct platform_driver * const mtk_drm_drivers[] = { &mtk_dpi_driver, &mtk_drm_platform_driver, &mtk_dsi_driver, + &mtk_ethdr_driver, &mtk_mdp_rdma_driver, }; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index 64a1f66df26a..3fb85776b8b3 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -55,6 +55,7 @@ extern struct platform_driver mtk_disp_ovl_driver; extern struct platform_driver mtk_disp_rdma_driver; extern struct platform_driver mtk_dpi_driver; extern struct platform_driver mtk_dsi_driver; +extern struct platform_driver mtk_ethdr_driver; extern struct platform_driver mtk_mdp_rdma_driver; #endif /* MTK_DRM_DRV_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c new file mode 100644 index ..73dc4da3ba3b --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_drm_crtc.h" +#include "mtk_drm_ddp_comp.h" +#include "mtk_drm_drv.h" +#include "mtk_ethdr.h" + +#define MIX_INTEN 0x4 +#define MIX_FME_CPL_INTEN BIT(1) +#define MIX_INTSTA 0x8 +#define MIX_EN 0xc +#define MIX_RST0x14 +#define MIX_ROI_SIZE 0x18 +#define MIX_DATAPATH_CON 0x1c +#define OUTPUT_NO_RND BIT(3) +#define SOURCE_RGB_SEL BIT(7) +#define BACKGROUND_RELAY (4 << 9) +#define MIX_ROI_BGCLR 0x20 +#define BGCLR_BLACK0xff00 +#define MIX_SRC_CON0x24 +#define MIX_SRC_L0_EN BIT(0) +#define MIX_L_SRC_CON(n) (0x28 + 0x18 * (n)) +#define NON_PREMULTI_SOURCE(2 << 12) +#define MIX_L_SRC_SIZE(n) (0x30 + 0x18 * (n)) +#define MIX_L_SRC_OFFSET(n)(0x34 + 0x18 * (n)) +#define MIX_FUNC_DCM0 0x120 +#define MIX_FUNC_DCM1 0x124 +#define MIX_FUNC_DCM_ENABLE0x + +#define HDR_VDO_FE_0804_HDR_DM_FE 0x804 +#define HDR_VDO_FE_0804_BYPASS_ALL 0xfd +#define HDR_GFX_FE_0204_GFX_HDR_FE 0x204 +#define HDR_GFX_FE_0204_BYPASS_ALL 0xfd +#define HDR_VDO_BE_0204_VDO_DM_BE 0x204 +#define HDR_VDO_BE_0204_BYPASS_ALL 0x7e + +#define MIXER_INX_MODE_BYPASS 0 +#define MIXER_INX_MODE_EVEN_EXTEND 1 +#define DEFAULT_9BIT_ALPHA 0x100 +#defineMIXER_ALPHA_AEN BIT(8) +#defineMIXER_ALPHA 0xff +#define ETHDR_CLK_NUM 13 + +enum mtk_ethdr_comp_id { + ETHDR_MIXER, + ETHDR_VDO_FE0, + ETHDR_VDO_FE1, + ETHDR_GFX_FE0, + ETHDR_GFX_FE1, + ETHDR_VDO_BE, + ETHDR_ADL_DS, + ETHDR_ID_MAX +}; + +struct mtk_ethdr_comp { + struct device *dev; + void __iomem*regs; + struct cmdq_client_reg cmdq_base;
[PATCH v28 1/7] dt-bindings: mediatek: add ethdr definition for mt8195
Add vdosys1 ETHDR definition. Signed-off-by: Nancy.Lin Reviewed-by: Chun-Kuang Hu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Krzysztof Kozlowski Tested-by: AngeloGioacchino Del Regno --- .../display/mediatek/mediatek,ethdr.yaml | 188 ++ 1 file changed, 188 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml new file mode 100644 index ..3b11e47a8834 --- /dev/null +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml @@ -0,0 +1,188 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/mediatek/mediatek,ethdr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Ethdr Device + +maintainers: + - Chun-Kuang Hu + - Philipp Zabel + +description: + ETHDR (ET High Dynamic Range) is a MediaTek internal HDR engine and is + designed for HDR video and graphics conversion in the external display path. + It handles multiple HDR input types and performs tone mapping, color + space/color format conversion, and then combine different layers, + output the required HDR or SDR signal to the subsequent display path. + This engine is composed of two video frontends, two graphic frontends, + one video backend and a mixer. ETHDR has two DMA function blocks, DS and ADL. + These two function blocks read the pre-programmed registers from DRAM and + set them to HW in the v-blanking period. + +properties: + compatible: +const: mediatek,mt8195-disp-ethdr + + reg: +maxItems: 7 + + reg-names: +items: + - const: mixer + - const: vdo_fe0 + - const: vdo_fe1 + - const: gfx_fe0 + - const: gfx_fe1 + - const: vdo_be + - const: adl_ds + + interrupts: +maxItems: 1 + + iommus: +minItems: 1 +maxItems: 2 + + clocks: +items: + - description: mixer clock + - description: video frontend 0 clock + - description: video frontend 1 clock + - description: graphic frontend 0 clock + - description: graphic frontend 1 clock + - description: video backend clock + - description: autodownload and menuload clock + - description: video frontend 0 async clock + - description: video frontend 1 async clock + - description: graphic frontend 0 async clock + - description: graphic frontend 1 async clock + - description: video backend async clock + - description: ethdr top clock + + clock-names: +items: + - const: mixer + - const: vdo_fe0 + - const: vdo_fe1 + - const: gfx_fe0 + - const: gfx_fe1 + - const: vdo_be + - const: adl_ds + - const: vdo_fe0_async + - const: vdo_fe1_async + - const: gfx_fe0_async + - const: gfx_fe1_async + - const: vdo_be_async + - const: ethdr_top + + power-domains: +maxItems: 1 + + resets: +items: + - description: video frontend 0 async reset + - description: video frontend 1 async reset + - description: graphic frontend 0 async reset + - description: graphic frontend 1 async reset + - description: video backend async reset + + reset-names: +items: + - const: vdo_fe0_async + - const: vdo_fe1_async + - const: gfx_fe0_async + - const: gfx_fe1_async + - const: vdo_be_async + + mediatek,gce-client-reg: +$ref: /schemas/types.yaml#/definitions/phandle-array +description: The register of display function block to be set by gce. + There are 4 arguments in this property, gce node, subsys id, offset and + register size. The subsys id is defined in the gce header of each chips + include/dt-bindings/gce/-gce.h, mapping to the register of display + function block. +items: + items: +- description: phandle of GCE +- description: GCE subsys id +- description: register offset +- description: register size +minItems: 7 +maxItems: 7 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + - resets + - mediatek,gce-client-reg + +additionalProperties: false + +examples: + - | +#include +#include +#include +#include +#include +#include + +soc { +#address-cells = <2>; +#size-cells = <2>; + +hdr-engine@1c114000 { +compatible = "mediatek,mt8195-disp-ethdr"; +reg = <0 0x1c114000 0 0x1000>, + <0 0x1c115000 0 0x1000>, + <0 0x1c117000 0 0x1000>, + <0 0x1c119000 0 0x1000>, + <0 0x1c11a000 0 0x1000>, + <0 0x1c11b000 0 0x1000>, + <0 0x1c11c000 0 0x1000>; +reg-names = "mixe
[PATCH v28 3/7] drm/mediatek: add ovl_adaptor support for MT8195
Add ovl_adaptor driver for MT8195. Ovl_adaptor is an encapsulated module and designed for simplified DRM control flow. This module is composed of 8 RDMAs, 4 MERGEs and an ETHDR. Two RDMAs merge into one layer, so this module support 4 layers. Signed-off-by: Nancy.Lin Reviewed-by: Chun-Kuang Hu Reviewed-by: AngeloGioacchino Del Regno Tested-by: AngeloGioacchino Del Regno Tested-by: Bo-Chen Chen --- drivers/gpu/drm/mediatek/Makefile | 1 + drivers/gpu/drm/mediatek/mtk_disp_drv.h | 26 + .../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 533 ++ drivers/gpu/drm/mediatek/mtk_drm_drv.h| 1 + 4 files changed, 561 insertions(+) create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index 840f14436d3c..d4d193f60271 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -6,6 +6,7 @@ mediatek-drm-y := mtk_disp_aal.o \ mtk_disp_gamma.o \ mtk_disp_merge.o \ mtk_disp_ovl.o \ + mtk_disp_ovl_adaptor.o \ mtk_disp_rdma.o \ mtk_drm_crtc.o \ mtk_drm_ddp_comp.o \ diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 33e61a136bbc..654f8e257984 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -7,6 +7,8 @@ #define _MTK_DISP_DRV_H_ #include +#include +#include #include "mtk_drm_plane.h" #include "mtk_mdp_rdma.h" @@ -116,6 +118,30 @@ void mtk_rdma_unregister_vblank_cb(struct device *dev); void mtk_rdma_enable_vblank(struct device *dev); void mtk_rdma_disable_vblank(struct device *dev); +void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex); +void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex); +void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, +unsigned int next); +void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, + unsigned int next); +int mtk_ovl_adaptor_clk_enable(struct device *dev); +void mtk_ovl_adaptor_clk_disable(struct device *dev); +void mtk_ovl_adaptor_config(struct device *dev, unsigned int w, + unsigned int h, unsigned int vrefresh, + unsigned int bpc, struct cmdq_pkt *cmdq_pkt); +void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx, + struct mtk_plane_state *state, + struct cmdq_pkt *cmdq_pkt); +void mtk_ovl_adaptor_register_vblank_cb(struct device *dev, void (*vblank_cb)(void *), + void *vblank_cb_data); +void mtk_ovl_adaptor_unregister_vblank_cb(struct device *dev); +void mtk_ovl_adaptor_enable_vblank(struct device *dev); +void mtk_ovl_adaptor_disable_vblank(struct device *dev); +void mtk_ovl_adaptor_start(struct device *dev); +void mtk_ovl_adaptor_stop(struct device *dev); +unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev); +struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev); + int mtk_mdp_rdma_clk_enable(struct device *dev); void mtk_mdp_rdma_clk_disable(struct device *dev); void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c new file mode 100644 index ..046217828ab3 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_disp_drv.h" +#include "mtk_drm_crtc.h" +#include "mtk_drm_ddp_comp.h" +#include "mtk_drm_drv.h" +#include "mtk_ethdr.h" + +#define MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH 1920 +#define MTK_OVL_ADAPTOR_LAYER_NUM 4 + +enum mtk_ovl_adaptor_comp_type { + OVL_ADAPTOR_TYPE_RDMA = 0, + OVL_ADAPTOR_TYPE_MERGE, + OVL_ADAPTOR_TYPE_ETHDR, + OVL_ADAPTOR_TYPE_NUM, +}; + +enum mtk_ovl_adaptor_comp_id { + OVL_ADAPTOR_MDP_RDMA0, + OVL_ADAPTOR_MDP_RDMA1, + OVL_ADAPTOR_MDP_RDMA2, + OVL_ADAPTOR_MDP_RDMA3, + OVL_ADAPTOR_MDP_RDMA4, + OVL_ADAPTOR_MDP_RDMA5, + OVL_ADAPTOR_MDP_RDMA6, + OVL_ADAPTOR_MDP_RDMA7, + OVL_ADAPTOR_MERGE0, + OVL_ADAPTOR_MERGE1, + OVL_ADAPTOR_MERGE2, + OVL_ADAPTOR_MERGE3, + OVL_ADAPTOR_ETHDR0, + OVL_ADAPTOR_ID_MAX +}; + +struct ovl_adaptor_comp_match { + enum mtk_ovl_adaptor_comp_type type; + int alias_id; +}; + +struct mtk_disp_ovl_adaptor { + struct device *ovl_adaptor_comp[OVL_ADAPTOR_ID_MAX]; + struct d
Re: [PATCH v2 28/65] clk: renesas: r9a06g032: Add a determine_rate hook
CC Gareth On Fri, Nov 4, 2022 at 2:18 PM Maxime Ripard wrote: > > The Renesas r9a06g032 bitselect clock implements a mux with a set_parent > hook, but doesn't provide a determine_rate implementation. > > This is a bit odd, since set_parent() is there to, as its name implies, > change the parent of a clock. However, the most likely candidate to > trigger that parent change is a call to clk_set_rate(), with > determine_rate() figuring out which parent is the best suited for a > given rate. > > The other trigger would be a call to clk_set_parent(), but it's far less > used, and it doesn't look like there's any obvious user for that clock. > > So, the set_parent hook is effectively unused, possibly because of an > oversight. However, it could also be an explicit decision by the > original author to avoid any reparenting but through an explicit call to > clk_set_parent(). > > The latter case would be equivalent to setting the flag > CLK_SET_RATE_NO_REPARENT, together with setting our determine_rate hook > to __clk_mux_determine_rate(). Indeed, if no determine_rate > implementation is provided, clk_round_rate() (through > clk_core_round_rate_nolock()) will call itself on the parent if > CLK_SET_RATE_PARENT is set, and will not change the clock rate > otherwise. __clk_mux_determine_rate() has the exact same behavior when > CLK_SET_RATE_NO_REPARENT is set. > > And if it was an oversight, then we are at least explicit about our > behavior now and it can be further refined down the line. > > Signed-off-by: Maxime Ripard > --- > drivers/clk/renesas/r9a06g032-clocks.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/clk/renesas/r9a06g032-clocks.c > b/drivers/clk/renesas/r9a06g032-clocks.c > index 983faa5707b9..70c37097ca6e 100644 > --- a/drivers/clk/renesas/r9a06g032-clocks.c > +++ b/drivers/clk/renesas/r9a06g032-clocks.c > @@ -773,6 +773,7 @@ static int r9a06g032_clk_mux_set_parent(struct clk_hw > *hw, u8 index) > } > > static const struct clk_ops clk_bitselect_ops = { > + .determine_rate = __clk_mux_determine_rate, > .get_parent = r9a06g032_clk_mux_get_parent, > .set_parent = r9a06g032_clk_mux_set_parent, > }; > @@ -797,7 +798,7 @@ r9a06g032_register_bitsel(struct r9a06g032_priv *clocks, > > init.name = desc->name; > init.ops = &clk_bitselect_ops; > - init.flags = CLK_SET_RATE_PARENT; > + init.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT; > init.parent_names = names; > init.num_parents = 2; > > > -- > b4 0.11.0-dev-99e3a