fbdev/vga16fb: Create EGA/VGA devices in sysfb code
Move the device-creation from vga16fb to sysfb code. The driver's
videomode checks are independent from device creation, so move them
into vga16fb's probe function. This will allow to create the module
init/exit code automatically.
The vga16fb driver requires a screen_info for type VIDEO_TYPE_VGAC
or VIDEO_TYPE_EGAC. Such code is nowhere present in the kernel, except
for some MIPS systems. It's not clear if the vga16fb driver actually
works in practice.
v2:
* keep driver name to "vga16fb" (Javier)
* give rational for moving mode checks (Javier)
Marek Vasut [Sun, 10 Jul 2022 19:44:37 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Split GIP and init sequences
The ST7701 initialization sequence is well parametrized, split the GIP
programming sequence, which is fully custom completely undocumented
TFT matrix specific magic register programming sequence into separate
callback so other TFT matrix definitions can add their own GIP sequence.
Marek Vasut [Sun, 10 Jul 2022 19:44:36 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Parametrize voltage and timing
Instead of hard-coding TFT matrix voltage and timing settings, which can
even lead to permanent TFT matrix damage, parametrize them in TFT matrix
descriptor.
Marek Vasut [Sun, 10 Jul 2022 19:44:35 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Infer horizontal pixel count from TFT mode
The horizontal pixel count is a property of the TFT matrix. Currently the
driver hard-codes content of this register to specific value which is
only compatible with one TFT matrix, likely the TS8550B one.
Calculate the horizontal pixel count from the mode instead.
Marek Vasut [Sun, 10 Jul 2022 19:44:34 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Adjust porch control bitfield name
Define DSI_CMD2_BK0_PORCTRL_VBP_MASK and DSI_CMD2_BK0_PORCTRL_VFP_MASK
and move the vertical back and front porch calculation from macros into
the st7701_init_sequence() function, so it is clear what this does.
Marek Vasut [Sun, 10 Jul 2022 19:44:33 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Infer vertical line count from TFT mode
The vertical line count is a property of the TFT matrix. Currently the
driver hard-codes content of this register to specific value which is
only compatible with one TFT matrix, likely the TS8550B one.
Calculate the vertical line count from the mode instead.
Marek Vasut [Sun, 10 Jul 2022 19:44:32 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Make gamma correction TFT specific
The gamma correction values are specific to the TFT which is attached to
the ST7701 TFT matrix driver, move the gamma correction values from what
incorrectly looks like common init sequence into TFT matrix specific
settings.
While doing so, add macros which defined fields within the gamma register
file and a macro which mimics FIELD_PREP except works with constant
expressions.
Marek Vasut [Sun, 10 Jul 2022 19:44:31 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Make voltage supplies common to ST7701
The ST7701 and ST7701S all have two voltage supplies, one for internal
logic and one for the TFT matrix driver. The supplies are not property
of the TFT matrix driver, so move them to common ST7701 code.
The ST7701(S) is capable of DSI burst mode, which is more energy
efficient than the non-burst modes. Make use of it.
The ST7701(S) is capable of DSI non-continuous clock, since it
sources the TFT matrix driver clock from internal clock source.
The DSI non-continuous clock further reduce power utilization.
The ST7701(S) uses DSI LPM for command transmissions, make sure
this is configured correctly in the DSI mode flags.
Marek Vasut [Sun, 10 Jul 2022 19:44:29 +0000 (21:44 +0200)]
drm/panel/panel-sitronix-st7701: Make DSI mode flags common to ST7701
The ST7701 and ST7701S are TFT matrix drivers with integrated multi
protocol decoder capable of DSI/DPI/SPI input and 480x360...864 line
TFT matrix output. Currently the only supported input is DSI.
The protocol decoder is separate from the TFT matrix driver and is
always capable of handling all of DSI non-burst mode with sync pulses
or sync events as well as DSI burst mode.
Move the DSI mode configuration from TFT matrix driver properties to
common ST7701 code, because this is common to all TFT matrices.
Make it clear that DMA_RESV_USAGE_BOOKKEEP can be used for explicit synced
user space submissions as well and document the rules around adding the
same fence with different usages.
Pin-Yen Lin [Thu, 14 Jul 2022 09:39:20 +0000 (17:39 +0800)]
drm/bridge: it6505: Power on downstream device in .atomic_enable
Send DPCD DP_SET_POWER_D0 command to the monitor in .atomic_enable
callback. Without this command, some monitors won't show up again after
changing the resolution.
drm/ssd130x: Use new regmap bulk write support to drop custom bus
Data writes for the ssd130x 4-wire SPI protocol need special handling, due
the Data/Command control (D/C) pin having to be toggled prior to the write.
The regmap API only allowed drivers to provide .reg_{read,write} callbacks
to do per register read/write, but didn't provide a way for drivers to do
the same for bulk read/writes.
For this reason, a custom regmap bus was used by the driver just to define
a bulk write callback that implements the D/C pin toggling. But the regmap
API has been extended to support defining bulk read/write handlers, so the
custom regmap bus is not needed anymore and could just be dropped.
Laurent Pinchart [Thu, 16 Jun 2022 18:52:10 +0000 (21:52 +0300)]
drm/fourcc: Add formats for packed YUV 4:4:4 AVUY and XVUY permutations
Add FourCCs for two missing permutations of the packed YUV 4:4:4 color
components, namely AVUY and XVUY.
These formats are needed by the NXP i.MX8 ISI. While the ISI is
supported by a V4L2 device (corresponding formats have been submitted to
V4L2), it is handled in userspace by libcamera, which uses DRM FourCCs
for pixel formats.
Sam Ravnborg [Wed, 13 Jul 2022 17:02:01 +0000 (19:02 +0200)]
drm/via: Make macros readable in the via_3d_reg header
The macros for texture 1 setting all used continuation on a new line,
resulting in a highly ureadable definition.
Merge the lines so they are each on a single line.
As a nice side-effect this fixes a number of checkpatch warnings:
"WARNING: please, no spaces at the start of a line".
Sam Ravnborg [Wed, 13 Jul 2022 17:01:58 +0000 (19:01 +0200)]
drm/via: Embed via_drv.h in via_dri1
With this change the driver is now a signle file driver.
The only remaning heder file describes the HW and can be shared with the
new openchrome driver.
Sam Ravnborg [Wed, 13 Jul 2022 17:01:56 +0000 (19:01 +0200)]
drm/via: Embed via_dmablit in via_dri1
Embed some of the header file in via_drv.h and
the rest in via_dri1.c
While embedding deleted extra empty lines and functions that
has no external users are made static.
Sam Ravnborg [Wed, 13 Jul 2022 17:01:50 +0000 (19:01 +0200)]
drm/via: Rename via_drv to via_dri1
The via driver implements the DRI1 interface, and we have a new
implementation of the via driver coming that supports atomic
modesetting.
It is not acceptable just to replace the existing driver so
this is first step to make it a single-file implementation allowing
it to stay without interfering with the new driver.
Tom Rix [Sat, 2 Jul 2022 15:39:04 +0000 (11:39 -0400)]
drm/nouveau/bios: set info only when the return is not 0
clang static analysis reports
drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c:68:17: warning: The right operand of '*' is a garbage value [core.UndefinedBinaryOperatorResult]
switch (!!data * *ver) {
^ ~~~~
A switch statement with only a default should be reduced to an if.
If nvbios_pmuEp() returns 0, via the data variable, the output info parameter
is not used. So set info only when data is not 0.
The struct nvbios_pmuE only has the type and data elements. Since both of these
are explicitly set, memset is not needed. So remove it.
drm: Use size_t type for len variable in drm_copy_field()
The strlen() function returns a size_t which is an unsigned int on 32-bit
arches and an unsigned long on 64-bit arches. But in the drm_copy_field()
function, the strlen() return value is assigned to an 'int len' variable.
Later, the len variable is passed as copy_from_user() third argument that
is an unsigned long parameter as well.
In theory, this can lead to an integer overflow via type conversion. Since
the assignment happens to a signed int lvalue instead of a size_t lvalue.
In practice though, that's unlikely since the values copied are set by DRM
drivers and not controlled by userspace. But using a size_t for len is the
correct thing to do anyways.
Maxime Ripard [Mon, 11 Jul 2022 17:39:38 +0000 (19:39 +0200)]
drm/vc4: v3d: Rework the runtime_pm setup
At bind time, vc4_v3d_bind() will read a register to retrieve the v3d
version and make sure it's a version we're compatible with.
However, the v3d has an optional clock that is enabled only after the
register read-out and a power domain that wasn't enabled at all in the bind
implementation. This was working fine at boot because both were enabled,
but resulted in the version check failing if we were unbinding and
rebinding the driver because the unbinding would have turned them off.
The fix isn't as easy as calling pm_runtime_resume_and_get() prior to the
register access to power up the power domain though.
Indeed, the runtime_resume implementation will enable the clock mentioned
above, call vc4_v3d_init_hw() and then vc4_irq_enable().
Prior to the previous patch, vc4_irq_enable() needed to occur after our
call to platform_get_irq() and vc4_irq_install(), since vc4_irq_enable()
used to call enable_irq() and vc4_irq_install() will call request_irq().
vc4_irq_install() will also do some register access, so needs the power
domain to be on. So we ended up in a situation where
vc4_v3d_runtime_resume() needed vc4_irq_install() to have been called
before, and vc4_irq_install() needed vc4_v3d_runtime_resume().
The previous patch removed the enable_irq() call in vc4_irq_enable() and
thus removed the dependency of vc4_v3d_runtime_resume() on
vc4_irq_install().
Thus, we can now rework our bind implementation to call
pm_runtime_resume_and_get() before our register access to make sure the
power domain is on. vc4_v3d_runtime_resume() also takes care of turning the
clock on and calling vc4_v3d_init_hw() so we can remove them from bind.
Maxime Ripard [Mon, 11 Jul 2022 17:39:37 +0000 (19:39 +0200)]
drm/vc4: v3d: Stop disabling interrupts
The vc4_irq_disable(), among other things, will call disable_irq() to
complete any in-flight interrupts.
This requires its counterpart, vc4_irq_enable(), to call enable_irq() which
causes issues addressed in a later patch.
However, vc4_irq_disable() is called by two callees: vc4_irq_uninstall()
and vc4_v3d_runtime_suspend().
vc4_irq_uninstall() also calls free_irq() which already disables the
interrupt line. We thus don't require an explicit disable_irq() for that
call site.
vc4_v3d_runtime_suspend() doesn't have any other code. However, the rest of
vc4_irq_disable() masks the interrupts coming from the v3d, so explictly
disabling the interrupt line is also redundant.
The only thing we really care about is thus to make sure we don't have any
handler in-flight, as suggested by the comment. We can thus replace
disable_irq() by synchronize_irq().
Maxime Ripard [Mon, 11 Jul 2022 17:39:34 +0000 (19:39 +0200)]
drm/vc4: debugfs: Simplify debugfs registration
The vc4 has a custom API to allow components to register a debugfs file
before the DRM driver has been registered and the debugfs_init hook has
been called.
However, the .late_register hook allows to have the debugfs file creation
deferred after that time already.
Let's remove our custom code to only register later our debugfs entries as
part of either debugfs_init or after it.
Maxime Ripard [Mon, 11 Jul 2022 17:39:32 +0000 (19:39 +0200)]
drm/vc4: debugfs: Protect device resources
Our current code now mixes some resources whose lifetime are tied to the
device (clocks, IO mappings, etc.) and some that are tied to the DRM device
(encoder, bridge).
The device one will be freed at unbind time, but the DRM one will only be
freed when the last user of the DRM device closes its file handle.
So we end up with a time window during which we can call the encoder hooks,
but we don't have access to the underlying resources and device.
Let's protect all those sections with drm_dev_enter() and drm_dev_exit() so
that we bail out if we are during that window.
Maxime Ripard [Mon, 11 Jul 2022 17:39:30 +0000 (19:39 +0200)]
drm/vc4: vec: Protect device resources after removal
Whenever the device and driver are unbound, the main device and all the
subdevices will be removed by calling their unbind() method.
However, the DRM device itself will only be freed when the last user will
have closed it.
It means that there is a time window where the device and its resources
aren't there anymore, but the userspace can still call into our driver.
Fortunately, the DRM framework provides the drm_dev_enter() and
drm_dev_exit() functions to make sure our underlying device is still there
for the section protected by those calls. Let's add them to the VEC driver.
Maxime Ripard [Mon, 11 Jul 2022 17:39:29 +0000 (19:39 +0200)]
drm/vc4: vec: Switch to DRM-managed connector initialization
The current code will call drm_connector_unregister() and
drm_connector_cleanup() when the device is unbound. However, by then, there
might still be some references held to that connector, including by the
userspace that might still have the DRM device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:28 +0000 (19:39 +0200)]
drm/vc4: vec: Switch to DRM-managed encoder initialization
The current code will call drm_encoder_cleanup() when the device is
unbound. However, by then, there might still be some references held to
that encoder, including by the userspace that might still have the DRM
device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:27 +0000 (19:39 +0200)]
drm/vc4: vec: Remove call to drm_connector_unregister()
drm_connector_unregister() is only to be used for connectors that have been
registered through drm_connector_register() after drm_dev_register() has
been called. This is our case here so let's remove the call.
Maxime Ripard [Mon, 11 Jul 2022 17:39:26 +0000 (19:39 +0200)]
drm/vc4: vec: Switch to drmm_kzalloc
Our internal structure that stores the DRM entities structure is allocated
through a device-managed kzalloc.
This means that this will eventually be freed whenever the device is
removed. In our case, the most likely source of removal is that the main
device is going to be unbound, and component_unbind_all() is being run.
However, it occurs while the DRM device is still registered, which will
create dangling pointers, eventually resulting in use-after-free.
Switch to a DRM-managed allocation to keep our structure until the DRM
driver doesn't need it anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:39:25 +0000 (19:39 +0200)]
drm/vc4: vec: Embed DRM structures into the private structure
The VC4 VEC driver private structure contains only a pointer to the
encoder and connector it implements. This makes the overall structure
somewhat inconsistent with the rest of the driver, and complicates its
initialisation without any apparent gain.
Let's embed the drm_encoder structure (through the vc4_encoder one) and
drm_connector into struct vc4_vec to fix both issues.
Maxime Ripard [Mon, 11 Jul 2022 17:39:23 +0000 (19:39 +0200)]
drm/vc4: txp: Protect device resources
Our current code now mixes some resources whose lifetime are tied to the
device (clocks, IO mappings, etc.) and some that are tied to the DRM device
(encoder, bridge).
The device one will be freed at unbind time, but the DRM one will only be
freed when the last user of the DRM device closes its file handle.
So we end up with a time window during which we can call the encoder hooks,
but we don't have access to the underlying resources and device.
Let's protect all those sections with drm_dev_enter() and drm_dev_exit() so
that we bail out if we are during that window.
Maxime Ripard [Mon, 11 Jul 2022 17:39:22 +0000 (19:39 +0200)]
drm/vc4: txp: Remove call to drm_connector_unregister()
drm_connector_unregister() is only to be used for connectors that have been
registered through drm_connector_register() after drm_dev_register() has
been called. This is our case here so let's remove the call.
Maxime Ripard [Mon, 11 Jul 2022 17:39:21 +0000 (19:39 +0200)]
drm/vc4: txp: Switch to drmm_kzalloc
Our internal structure that stores the DRM entities structure is allocated
through a device-managed kzalloc.
This means that this will eventually be freed whenever the device is
removed. In our case, the most likely source of removal is that the main
device is going to be unbound, and component_unbind_all() is being run.
However, it occurs while the DRM device is still registered, which will
create dangling pointers, eventually resulting in use-after-free.
Switch to a DRM-managed allocation to keep our structure until the DRM
driver doesn't need it anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:39:17 +0000 (19:39 +0200)]
drm/vc4: hdmi: Protect device resources after removal
Whenever the device and driver are unbound, the main device and all the
subdevices will be removed by calling their unbind() method.
However, the DRM device itself will only be freed when the last user will
have closed it.
It means that there is a time window where the device and its resources
aren't there anymore, but the userspace can still call into our driver.
Fortunately, the DRM framework provides the drm_dev_enter() and
drm_dev_exit() functions to make sure our underlying device is still there
for the section protected by those calls. Let's add them to the HDMI driver.
Maxime Ripard [Mon, 11 Jul 2022 17:39:16 +0000 (19:39 +0200)]
drm/vc4: hdmi: Move audio structure offset checks
The HDMI driver unbind hook doesn't have any ALSA-related code anymore, so
let's move the ALSA sanity checks and comments we have to some other part
of the driver dedicated to ALSA.
Maxime Ripard [Mon, 11 Jul 2022 17:39:15 +0000 (19:39 +0200)]
drm/vc4: hdmi: Use devm to register hotplug interrupts
Commit 776efe800fed ("drm/vc4: hdmi: Drop devm interrupt handler for
hotplug interrupts") dropped the device-managed interrupt registration
because it was creating bugs and races whenever an interrupt was coming in
while the device was removed.
However, our latest patches to the HDMI controller driver fix this as well,
so we can use device-managed interrupt handlers again.
Maxime Ripard [Mon, 11 Jul 2022 17:39:14 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to DRM-managed kfree to build regsets
The current code to build the registers set later exposed in debugfs for
the HDMI controller relies on traditional allocations, that are later
free'd as part of the driver unbind hook.
Since krealloc doesn't have a DRM-managed equivalent, let's add an action
to free the buffer later on.
Maxime Ripard [Mon, 11 Jul 2022 17:39:12 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to device-managed CEC initialization
The current code to unregister our CEC device needs to be undone manually
when we remove the HDMI driver.
Since the CEC framework will allocate its main structure, and will defer
its deallocation to when the last user will have closed it, we don't really
need to take any particular measure to prevent any use-after-free and can
thus use any managed action.
Maxime Ripard [Mon, 11 Jul 2022 17:39:11 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to device-managed ALSA initialization
The current code to unregister our ALSA device needs to be undone manually
when we remove the HDMI driver.
Since ALSA doesn't seem to support any mechanism to defer freeing something
until the last user of the ALSA device is gone, we can either use a
device-managed or a DRM-managed action.
The consistent way would be to use a DRM-managed one, just like pretty much
any framework-facing structure should be doing. However, ALSA does a lot of
allocation and registration using device-managed calls. Thus, if we're
going that way, by the time the DRM-managed action would run all of those
allocation would have been freed and we would end up with a use-after-free.
Thus, let's do a device-managed action. It's been tested with KASAN enabled
and doesn't seem to trigger any issue, so it's as good as anything.
Maxime Ripard [Mon, 11 Jul 2022 17:39:10 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to DRM-managed connector initialization
The current code will call drm_connector_unregister() and
drm_connector_cleanup() when the device is unbound. However, by then, there
might still be some references held to that connector, including by the
userspace that might still have the DRM device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:09 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to DRM-managed encoder initialization
The current code will call drm_encoder_cleanup() when the device is
unbound. However, by then, there might still be some references held to
that encoder, including by the userspace that might still have the DRM
device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:08 +0000 (19:39 +0200)]
drm/vc4: hdmi: Remove call to drm_connector_unregister()
drm_connector_unregister() is only to be used for connectors that have been
registered through drm_connector_register() after drm_dev_register() has
been called. This is our case here so let's remove the call.
Maxime Ripard [Mon, 11 Jul 2022 17:39:07 +0000 (19:39 +0200)]
drm/vc4: hdmi: Switch to drmm_kzalloc
Our internal structure that stores the DRM entities structure is allocated
through a device-managed kzalloc.
This means that this will eventually be freed whenever the device is
removed. In our case, the most likely source of removal is that the main
device is going to be unbound, and component_unbind_all() is being run.
However, it occurs while the DRM device is still registered, which will
create dangling pointers, eventually resulting in use-after-free.
Switch to a DRM-managed allocation to keep our structure until the DRM
driver doesn't need it anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:39:05 +0000 (19:39 +0200)]
drm/vc4: dsi: Fix the driver structure lifetime
The vc4_dsi structure is currently allocated through a device-managed
allocation. This can lead to use-after-free issues however in the unbinding
path since the DRM entities will stick around, but the underlying structure
has been freed.
However, we can't just fix it by using a DRM-managed allocation like we did
for the other drivers since the DSI case is a bit more intricate.
Indeed, the structure will be allocated at probe time, when we don't have a
DRM device yet, to be able to register the DSI bus driver. We will then
reuse it at bind time to register our KMS entities in the framework.
In order to work around both constraints, we can use a kref to track the
users of the structure (DSI host, and KMS), and then put our structure when
the DSI host will have been unregistered, and through a DRM-managed action
that will execute once we won't need the KMS entities anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:39:04 +0000 (19:39 +0200)]
drm/vc4: dsi: Switch to drmm_of_get_bridge
The current code uses a device-managed function to retrieve the next bridge
downstream.
However, that means that it will be removed at unbind time, where the DRM
device is still very much live and might still have some applications that
still have it open.
Switch to a DRM-managed variant to clean everything up once the DRM device
has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:03 +0000 (19:39 +0200)]
drm/vc4: dsi: Switch to DRM-managed encoder initialization
The current code will call drm_encoder_cleanup() when the device is
unbound. However, by then, there might still be some references held to
that encoder, including by the userspace that might still have the DRM
device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:39:02 +0000 (19:39 +0200)]
drm/vc4: dsi: Embed DRM structures into the private structure
The VC4 DSI driver private structure contains only a pointer to the
encoder it implements. This makes the overall structure somewhat
inconsistent with the rest of the driver, and complicates its
initialisation without any apparent gain.
Let's embed the drm_encoder structure (through the vc4_encoder one) into
struct vc4_dsi to fix both issues.
Maxime Ripard [Mon, 11 Jul 2022 17:39:01 +0000 (19:39 +0200)]
drm/vc4: dpi: Protect device resources
Our current code now mixes some resources whose lifetime are tied to the
device (clocks, IO mappings, etc.) and some that are tied to the DRM device
(encoder, bridge).
The device one will be freed at unbind time, but the DRM one will only be
freed when the last user of the DRM device closes its file handle.
So we end up with a time window during which we can call the encoder hooks,
but we don't have access to the underlying resources and device.
Let's protect all those sections with drm_dev_enter() and drm_dev_exit() so
that we bail out if we are during that window.
Maxime Ripard [Mon, 11 Jul 2022 17:39:00 +0000 (19:39 +0200)]
drm/vc4: dpi: Switch to drmm_of_get_bridge
The current code uses a device-managed function to retrieve the next bridge
downstream.
However, that means that it will be removed at unbind time, where the DRM
device is still very much live and might still have some applications that
still have it open.
Switch to a DRM-managed variant to clean everything up once the DRM device
has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:38:59 +0000 (19:38 +0200)]
drm/vc4: dpi: Switch to DRM-managed encoder initialization
The current code will call drm_encoder_cleanup() when the device is
unbound. However, by then, there might still be some references held to
that encoder, including by the userspace that might still have the DRM
device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Since we have a managed call to create our panel_bridge instance, the call
to drm_of_panel_bridge_remove() at unbind is both redundant and dangerous
since it might lead to a use-after-free.
Maxime Ripard [Mon, 11 Jul 2022 17:38:55 +0000 (19:38 +0200)]
drm/vc4: dpi: Switch to drmm_kzalloc
Our internal structure that stores the DRM entities structure is allocated
through a device-managed kzalloc.
This means that this will eventually be freed whenever the device is
removed. In our case, the most likely source of removal is that the main
device is going to be unbound, and component_unbind_all() is being run.
However, it occurs while the DRM device is still registered, which will
create dangling pointers, eventually resulting in use-after-free.
Switch to a DRM-managed allocation to keep our structure until the DRM
driver doesn't need it anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:38:54 +0000 (19:38 +0200)]
drm/vc4: dpi: Embed DRM structures into the private structure
The VC4 DPI driver private structure contains only a pointer to the
encoder it implements. This makes the overall structure somewhat
inconsistent with the rest of the driver, and complicates its
initialisation without any apparent gain.
Let's embed the drm_encoder structure (through the vc4_encoder one) into
struct vc4_dpi to fix both issues.
Maxime Ripard [Mon, 11 Jul 2022 17:38:52 +0000 (19:38 +0200)]
drm/vc4: crtc: Switch to DRM-managed CRTC initialization
The current code will call drm_crtc_cleanup() when the device is
unbound. However, by then, there might still be some references held to
that CRTC, including by the userspace that might still have the DRM
device open.
Let's switch to a DRM-managed initialization to clean up after ourselves
only once the DRM device has been last closed.
Maxime Ripard [Mon, 11 Jul 2022 17:38:51 +0000 (19:38 +0200)]
drm/vc4: crtc: Switch to drmm_kzalloc
Our internal structure that stores the DRM entities structure is allocated
through a device-managed kzalloc.
This means that this will eventually be freed whenever the device is
removed. In our case, the most likely source of removal is that the main
device is going to be unbound, and component_unbind_all() is being run.
However, it occurs while the DRM device is still registered, which will
create dangling pointers, eventually resulting in use-after-free.
Switch to a DRM-managed allocation to keep our structure until the DRM
driver doesn't need it anymore.
Maxime Ripard [Mon, 11 Jul 2022 17:38:48 +0000 (19:38 +0200)]
drm/vc4: crtc: Remove manual plane removal on error
When vc4_crtc_bind() fails after vc4_crtc_init() has been called, we have
a loop undoing the plane creation and calling destroy on each plane
registered and matching the possible_crtcs mask.
However, this is redundant with what drm_mode_config_cleanup() is doing, so
let's remove it.
Maxime Ripard [Mon, 11 Jul 2022 17:38:47 +0000 (19:38 +0200)]
drm/vc4: plane: Take possible_crtcs as an argument
vc4_plane_init() currently initialises the plane with no possible CRTCs,
and will expect the caller to set it up by itself.
Let's change that logic a bit to follow the syntax of
drm_universal_plane_init() and pass the possible CRTCs bitmask as an
argument to the function instead.
Maxime Ripard [Mon, 11 Jul 2022 17:38:45 +0000 (19:38 +0200)]
drm/vc4: hvs: Protect device resources after removal
Whenever the device and driver are unbound, the main device and all the
subdevices will be removed by calling their unbind() method.
However, the DRM device itself will only be freed when the last user will
have closed it.
It means that there is a time window where the device and its resources
aren't there anymore, but the userspace can still call into our driver.
Fortunately, the DRM framework provides the drm_dev_enter() and
drm_dev_exit() functions to make sure our underlying device is still there
for the section protected by those calls. Let's add them to the HVS driver.
Maxime Ripard [Mon, 11 Jul 2022 17:38:43 +0000 (19:38 +0200)]
drm/vc4: drv: Use drm_dev_unplug
When our KMS driver is unbound, the device is no longer there but we might
still have users with an opened fd to the KMS device.
To avoid any issue in such a situation, every device access needs to be
protected by calls to drm_dev_enter() and drm_dev_exit(), and the driver
needs to call drm_dev_unplug().
We'll add calls to drm_dev_enter()/drm_dev_exit() in subsequent patches
changing the relevant drivers, but let's start by calling drm_dev_unplug().
Maxime Ripard [Mon, 11 Jul 2022 17:38:42 +0000 (19:38 +0200)]
drm/vc4: drv: Call component_unbind_all()
While we were using the component framework to deal with all the DRM
subdevices, we were not calling component_unbind_all().
This leads to none of the subdevices freeing up their resources as part of
their unbind() or device managed hooks.
Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.") Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com> Signed-off-by: Maxime Ripard <maxime@cerno.tech> Link: https://lore.kernel.org/r/20220711173939.1132294-13-maxime@cerno.tech