* Re: [PATCH net-next v4 00/13] net: lan966x: add support for PCIe FDMA
From: Daniel Machon @ 2026-05-12 9:56 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Horatiu Vultur, Steen Hegelund, UNGLinuxDriver,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Herve Codina, Arnd Bergmann,
Greg Kroah-Hartman, Mohsin Bashir, netdev, linux-kernel, bpf,
linux-arm-kernel
In-Reply-To: <20260511192018.49dfcd7b@kernel.org>
> On Fri, 8 May 2026 09:35:24 +0200 Daniel Machon wrote:
> > When lan966x operates as a PCIe endpoint, the driver currently uses
> > register-based I/O for frame injection and extraction. This approach is
> > functional but slow, topping out at around 33 Mbps on an Intel x86 host
> > with a lan966x PCIe card.
>
> Looks like sashiko-bot responded but only CCed bpf@
> Please let us know if all the issues are false positives,
> I'm going to assume for now that at least one of the issues
> is real :)
I ran through all the issues from sashiko-gemini (sashiko-nipa only reported low
severity issues).
Most of them are false-positives, some are pre-existing and some are purely
theoretical. I have experimented a little with fixing some of the theoretical,
but subsequent local sashiko runs seem to just find new ones indefinitely ;)
IMHO, like Paolo commented on v3, I think these can safely be postponed to
future follow-ups, if need be.
Let me know what you think.
/Daniel
^ permalink raw reply
* Re: [PATCH v3 10/20] drm/plane: Add new atomic_create_state callback
From: Maxime Ripard @ 2026-05-12 9:55 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Jonas Karlman, Jernej Skrabec, Simon Ser, Harry Wentland,
Melissa Wen, Sebastian Wick, Alex Hung, Jani Nikula, Rodrigo Vivi,
Joonas Lahtinen, Tvrtko Ursulin, Chen-Yu Tsai, Samuel Holland,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance,
dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi
In-Reply-To: <20260504165229.GM1344263@killaraus.ideasonboard.com>
[-- Attachment #1: Type: text/plain, Size: 3257 bytes --]
Hi,
On Mon, May 04, 2026 at 07:52:29PM +0300, Laurent Pinchart wrote:
> On Fri, Apr 24, 2026 at 12:18:50PM +0200, Maxime Ripard wrote:
> > Commit 47b5ac7daa46 ("drm/atomic: Add new atomic_create_state callback
> > to drm_private_obj") introduced a new pattern for allocating drm object
> > states.
> >
> > Instead of relying on the reset() callback, it created a new
> > atomic_create_state hook. This is helpful because reset is a bit
> > overloaded: it's used to create the initial software state, reset it,
> > but also reset the hardware.
> >
> > It can also be used either at probe time, to create the initial state
> > and possibly reset the hardware to an expected default, but also during
> > suspend/resume.
> >
> > Both these cases come with different expectations too: during the
> > initialization, we want to initialize all states, but during
> > suspend/resume, drm_private_states for example are expected to be kept
> > around.
> >
> > reset() also isn't fallible, which makes it harder to handle
> > initialization errors properly. This is only really relevant for some
> > drivers though, since all the helpers for reset only create a new
> > state, and don't touch the hardware at all.
> >
> > It was thus decided to create a new hook that would allocate and
> > initialize a pristine state without any side effect:
> > atomic_create_state to untangle a bit some of it, and to separate the
> > initialization with the actual reset one might need during a
> > suspend/resume.
> >
> > Continue the transition to the new pattern with planes.
> >
> > Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > ---
> > drivers/gpu/drm/drm_atomic_state_helper.c | 25 +++++++++++++++++++++++++
> > drivers/gpu/drm/drm_mode_config.c | 21 ++++++++++++++++++++-
> > include/drm/drm_atomic_state_helper.h | 2 ++
> > include/drm/drm_plane.h | 16 ++++++++++++++++
> > 4 files changed, 63 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> > index 285efbf29520..50fe4eec41a8 100644
> > --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> > @@ -338,10 +338,35 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
> > if (plane->state)
> > __drm_atomic_helper_plane_reset(plane, plane->state);
> > }
> > EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
> >
> > +/**
> > + * drm_atomic_helper_plane_create_state - default &drm_plane_funcs.atomic_create_state hook for planes
>
> drm_atomic_helper_colorop_create_state() states "Allocates and
> initializes colorop atomic state", while here you document it as
> "default hook for planes". Consistency would be good.
I don't think it's inconsistent?
colorops don't have a create_state callback, so the only function to
create it is defined as "Allocates and initializes colorop atomic
state". For planes, the hook is documented as "Allocates a pristine,
initialized, state for the plane object and returns it.", and here we
have the default implementation for that hook, which is documented as
such.
It all seems consistent to me?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v3 3/3] usb: dwc3: imx8mp: disable auto suspend for host role
From: Xu Yang @ 2026-05-12 9:53 UTC (permalink / raw)
To: Franz Schnyder
Cc: Thinh.Nguyen, gregkh, shawnguo, s.hauer, kernel, festevam,
linux-usb, linux-kernel, imx, linux-arm-kernel, jun.li,
Francesco Dolcini
In-Reply-To: <hsyy2owzbt7tsljktlrz5g4bnrnecznvcyy6zxt7gfyxb4xvgi@ysko6xe6h2zm>
On Fri, May 08, 2026 at 06:04:49PM +0200, Franz Schnyder wrote:
> Hi Xu,
>
> On Fri, May 08, 2026 at 06:54:40PM +0800, Xu Yang wrote:
> > It's strange that link->status is not DL_STATE_DORMANT or DL_STATE_NONE at
> > the time which means the device core may not properly unbind consumer devices
> > or handle something. The patch does a simple thing so the issue may not come
> > from the patch itself.
> >
> > 1639: list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) {
> > 1640: WARN_ON(link->status != DL_STATE_DORMANT &&
> > 1641: link->status != DL_STATE_NONE);
> > 1642: __device_link_del(&link->kref);
> > 1643: }
> >
> > Which kernel and dtb are you using? If it's a downstream repo, how do the USB
> > controller and related DTS nodes look like?
>
> I was using kernel version 7.1-rc2 and noticed it while working on
> sending the Aquila iMX95 upstream.
> https://lore.kernel.org/all/20260506-add-aquila-imx95-v1-2-69c8ee1c5413@toradex.com/
I don't see any special configuration in your DTS. I modified my configuration
to match yours, but I can't reproduce the issue. I also created some fault points
during the probe process, but still didn't encounter the issue.
> >
> > Does the issue easily happen? Does dwc3_imx8mp_probe() eventually succeed?
>
> I did various boot attempts with the commit reverted and couldn't
> reproduce the issue. With the commit I ran into the issue in about one
> third of all boot attempts. So most of the time dwc3_imx8mp_prove
> actually succeeds.
OK. I mean, does dwc3_imx8mp_probe() still succeed after the kernel dumps
at the end?
>
> >
> > Could you add "#define DEBUG" in the head of drivers/base/core.c, rerun and share the log?
> >
> I can provide you with the data next week.
OK. More debug information will be helpful.
Thanks,
Xu Yang
^ permalink raw reply
* Re: cleanup the RAID6 P/Q library v2
From: Ard Biesheuvel @ 2026-05-12 9:50 UTC (permalink / raw)
To: Christoph Hellwig, Andrew Morton
Cc: Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, Herbert Xu, Dan Williams, Chris Mason,
David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
linux-raid
In-Reply-To: <20260512052230.2947683-1-hch@lst.de>
On Tue, 12 May 2026, at 07:20, Christoph Hellwig wrote:
> Hi all,
>
> this series cleans up the RAID6 P/Q library to match the recent updates
> to the RAID 5 XOR library and other CRC/crypto libraries. This includes
> providing properly documented external interfaces, hiding the internals,
> using static_call instead of indirect calls and turning the user space
> test suite into an in-kernel kunit test which is also extended to
> improve coverage.
>
> Note that this changes registration so that non-priority algorithms are
> not registered, which greatly helps with the benchmark time at boot time.
> I'd like to encourage all architecture maintainers to see if they can
> further optimized this by registering as few as possible algorithms when
> there is a clear benefit in optimized or more unrolled implementations.
>
> This series sits on top of the "cleanup the RAID5 XOR library v3" series.
>
> A git tree is also available here:
>
> git://git.infradead.org/users/hch/misc.git lib-raid6
>
> Gitweb:
>
>
> https://git.infradead.org/?p=users/hch/misc.git;a=shortlog;h=refs/heads/lib-raid6
>
> Changes since v1:
> - fix arm64 objdir != srcdir builds
> - call the kunit module raid6_kunit.ko from the beginning
> - update MAINTAINERS
> - don't require preemptible context and apply the same restrictions as
> the merged version of the XOR API
> - fix the arm64 default in Kconfig
> - pick the last registered (and presumably most optimized) algorithm when
> benchmarking is disabled
> - port over the randomization fixes from the XOR series
> - misc other kunit cleanups
> - require at least 4 devices for RAID6 to skip broken special cases
>
Tested-by: Ard Biesheuvel <ardb@kernel.org> # kunit only on arm64
Acked-by: Ard Biesheuvel <ardb@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/4] remoteproc: add common wc-ioremap carveout callbacks
From: Arnaud POULIQUEN @ 2026-05-12 9:44 UTC (permalink / raw)
To: Ben Levinsky, Bjorn Andersson, Mathieu Poirier, linux-remoteproc
Cc: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Geert Uytterhoeven, Magnus Damm, Patrice Chotard, Maxime Coquelin,
Alexandre Torgue, imx, linux-arm-kernel, linux-kernel,
linux-renesas-soc, linux-stm32, tanmay.shah
In-Reply-To: <20260511211841.284809-2-ben.levinsky@amd.com>
On 5/11/26 23:18, Ben Levinsky wrote:
> Several remoteproc drivers open-code the same ioremap_wc() and
> iounmap() callbacks for carveout mappings. Add subsystem-private
> helpers in remoteproc_internal.h so those drivers can share the same
> implementation.
>
> Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
> ---
> drivers/remoteproc/remoteproc_internal.h | 26 +++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 0a5e15744b1d..3724a47a9748 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -12,8 +12,9 @@
> #ifndef REMOTEPROC_INTERNAL_H
> #define REMOTEPROC_INTERNAL_H
>
> -#include <linux/irqreturn.h>
> #include <linux/firmware.h>
> +#include <linux/io.h>
> +#include <linux/irqreturn.h>
>
> struct rproc;
>
> @@ -122,6 +123,29 @@ rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
> void rproc_add_rvdev(struct rproc *rproc, struct rproc_vdev *rvdev);
> void rproc_remove_rvdev(struct rproc_vdev *rvdev);
>
> +static inline int rproc_mem_entry_ioremap_wc(struct rproc *rproc,
> + struct rproc_mem_entry *mem)
> +{
> + void __iomem *va;
> +
> + va = ioremap_wc(mem->dma, mem->len);
> + if (!va)
> + return -ENOMEM;
Could you add error message here to help for debug
+ dev_err(dev, "Unable to map memory region: %pa+%zx\n",
+ &mem->dma, mem->len);
> +
> + mem->va = (__force void *)va;
> + mem->is_iomem = true;
HHere, you set mem->is_iomem, but this is not done in platform drivers.
It seems better to add this in a separate commit after patch 2/4, with
an explanation of why it needs to be set.
Regards,
Arnaud
> +
> + return 0;
> +}
> +
> +static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
> + struct rproc_mem_entry *mem)
> +{
> + iounmap((__force __iomem void *)mem->va);
> +
> + return 0;
> +}
> +
> static inline int rproc_prepare_device(struct rproc *rproc)
> {
> if (rproc->ops->prepare)
^ permalink raw reply
* Re: [PATCH v3 2/5] arm_mpam: resctrl: Pre-allocate assignable monitors
From: Ben Horgan @ 2026-05-12 9:43 UTC (permalink / raw)
To: Shaopeng Tan (Fujitsu)
Cc: amitsinght@marvell.com, baisheng.gao@unisoc.com,
baolin.wang@linux.alibaba.com, carl@os.amperecomputing.com,
dave.martin@arm.com, david@kernel.org, dfustini@baylibre.com,
fenghuay@nvidia.com, gshan@redhat.com, james.morse@arm.com,
jonathan.cameron@huawei.com, kobak@nvidia.com,
lcherian@marvell.com, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, peternewman@google.com,
punit.agrawal@oss.qualcomm.com, quic_jiles@quicinc.com,
reinette.chatre@intel.com, rohit.mathew@arm.com,
scott@os.amperecomputing.com, sdonthineni@nvidia.com,
xhao@linux.alibaba.com, zengheng4@huawei.com, x86@kernel.org
In-Reply-To: <TY4PR01MB1693081CFF2DCB47DA4C2F9C38B392@TY4PR01MB16930.jpnprd01.prod.outlook.com>
Hi Shaopeng,
Thanks for the quick review.
On 5/12/26 08:16, Shaopeng Tan (Fujitsu) wrote:
> Hello Ben,
>
>
>> MPAM is able to emulate ABMC, i.e. mbm_event mode, by making memory
>> bandwidth monitors assignable. Rather than supporting the 'default'
>> mbm_assign_mode always use 'mbm_event' mode even if there are sufficient
>> memory bandwidth monitors. The per monitor event configuration is only
>> provided by resctrl when in 'mbm_event' mode and so only allowing
>> 'mbm_event' mode will make it easier to support per-monitor event
>> configuration for MPAM. For the moment, the only event supported is
>> mbm_total_event with no bandwidth type configuration. The 'mbm_assign_mode'
>> file will still show 'default' when there is no support for memory
>> bandwidth monitoring.
>>
>> The monitors need to be allocated from the driver, and mapped to whichever
>> control/monitor group resctrl wants to use them with.
>>
>> Add a second array to hold the monitor values indexed by resctrl's cntr_id.
>>
>> When CDP is in use, two monitors are needed so the available number of
>> counters halves. Platforms with one monitor will have zero monitors when
>> CDP is in use.
>>
>> Co-developed-by: James Morse <james.morse@arm.com>
>> Signed-off-by: James Morse <james.morse@arm.com>
>> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
>> ---
>> Changes since rfc v1:
>> abmc enabled even if enough counters
>> Helpers from dropped free running commits
>> carry on with zero counters if using cdp
>> set config bits
>> use kmalloc_objs
>> drop tags for rework
>> Configure mbm_cntr_configurable, mbm_cntr_assign_fixed
>>
>> Changes since rfc v2:
>> Don't set mon->assigned_counters to an error pointer
>> Fix mpam_resctrl_teardown_mon()
>> Remove free running check
>> Separate cleanup allocations, e.g. __free(), from the rest
>> Restrict scope on err in mpam_resctrl_monitor_init()
>> ---
>> drivers/resctrl/mpam_internal.h | 6 +-
>> drivers/resctrl/mpam_resctrl.c | 138 +++++++++++++++++++++++++++++++-
>> 2 files changed, 140 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
>> index 1914aefdcba9..7a166b395b5a 100644
>> --- a/drivers/resctrl/mpam_internal.h
>> +++ b/drivers/resctrl/mpam_internal.h
>> @@ -411,7 +411,11 @@ struct mpam_resctrl_res {
>> struct mpam_resctrl_mon {
>> struct mpam_class *class;
>>
>> - /* per-class data that resctrl needs will live here */
>> + /* Array of allocated MBWU monitors, indexed by (closid, rmid). */
>> + int *mbwu_idx_to_mon;
>> +
>> + /* Array of assigned MBWU monitors, indexed by idx argument. */
>> + int *assigned_counters;
>> };
>>
>> static inline int mpam_alloc_csu_mon(struct mpam_class *class)
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index f70fa65d39e4..cba295621f56 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -75,6 +75,8 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
>> */
>> static bool resctrl_enabled;
>>
>> +static unsigned int l3_num_allocated_mbwu = ~0;
>> +
>> bool resctrl_arch_alloc_capable(void)
>> {
>> struct mpam_resctrl_res *res;
>> @@ -140,7 +142,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
>>
>> bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
>> {
>> - return false;
>> + return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
>> }
>>
>> int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
>> @@ -185,6 +187,22 @@ static void resctrl_reset_task_closids(void)
>> read_unlock(&tasklist_lock);
>> }
>>
>> +static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
>> +{
>> + l3->mon.num_mbm_cntrs = l3_num_allocated_mbwu;
>> + if (cdp_enabled)
>> + l3->mon.num_mbm_cntrs /= 2;
>> +
>> + /*
>> + * Continue as normal even if there are zero counters to avoid giving
>> + * resctrl mixed messages.
>> + */
>> + l3->mon.mbm_cntr_assignable = true;
>> + l3->mon.mbm_assign_on_mkdir = true;
>> + l3->mon.mbm_cntr_configurable = false;
>> + l3->mon.mbm_cntr_assign_fixed = true;
>> +}
>> +
>> int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
>> {
>> u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
>> @@ -244,6 +262,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
>> WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
>>
>> resctrl_reset_task_closids();
>> + mpam_resctrl_monitor_sync_abmc_vals(l3);
>>
>> for_each_possible_cpu(cpu)
>> mpam_set_cpu_defaults(cpu, partid_d, partid_i, 0, 0);
>> @@ -613,6 +632,9 @@ static bool class_has_usable_mbwu(struct mpam_class *class)
>> if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
>> return false;
>>
>> + if (!cprops->num_mbwu_mon)
>> + return false;
>> +
>> return true;
>> }
>>
>> @@ -935,6 +957,52 @@ static void mpam_resctrl_pick_mba(void)
>> }
>> }
>>
>> +static void __free_mbwu_mon(struct mpam_class *class, int *array,
>> + u16 num_mbwu_mon)
>> +{
>> + for (int i = 0; i < num_mbwu_mon; i++) {
>> + if (array[i] < 0)
>> + continue;
>> +
>> + mpam_free_mbwu_mon(class, array[i]);
>> + array[i] = ~0;
>> + }
>> +}
>> +
>> +static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
>> + u16 num_mbwu_mon)
>> +{
>> + for (int i = 0; i < num_mbwu_mon; i++) {
>> + int mbwu_mon = mpam_alloc_mbwu_mon(class);
>> +
>> + if (mbwu_mon < 0) {
>> + __free_mbwu_mon(class, array, num_mbwu_mon);
>> + return mbwu_mon;
>> + }
>> + array[i] = mbwu_mon;
>> + }
>> +
>> + l3_num_allocated_mbwu = min(l3_num_allocated_mbwu, num_mbwu_mon);
>> +
>> + return 0;
>> +}
>> +
>> +static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
>> +{
>> + int err;
>> +
>> + int *array __free(kfree) = kmalloc_objs(*array, num_mbwu_mon);
>> + if (!array)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + memset(array, -1, num_mbwu_mon * sizeof(*array));
>> +
>> + err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
>> + if (err)
>> + return ERR_PTR(err);
>> + return_ptr(array);
>> +}
>> +
>> static void counter_update_class(enum resctrl_event_id evt_id,
>> struct mpam_class *class)
>> {
>> @@ -1089,6 +1157,38 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
>> return comp->comp_id;
>> }
>>
>> +/*
>> + * This must run after all event counters have been picked so that any free
>> + * running counters have already been allocated.
>> + */
>> +static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
>> +{
>> + struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
>> + struct rdt_resource *l3 = &res->resctrl_res;
>> + struct mpam_class *class = mon->class;
>> + u16 num_mbwu_mon;
>> + size_t num_rmid = resctrl_arch_system_num_rmid_idx();
>> + int *cntrs;
>
> Wouldn't a reverse tree format be better?
Do you mean just moving the num_rmid line up? If so, yes, that is a bit neater.
struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
size_t num_rmid = resctrl_arch_system_num_rmid_idx();
struct rdt_resource *l3 = &res->resctrl_res;
struct mpam_class *class = mon->class;
u16 num_mbwu_mon;
int *cntrs;
>
>> + int *rmid_array __free(kfree) = kmalloc_objs(*rmid_array, num_rmid);
>> + if (!rmid_array) {
>> + pr_debug("Failed to allocate RMID array\n");
>> + return -ENOMEM;
>> + }
>> + memset(rmid_array, -1, num_rmid * sizeof(*rmid_array));
>> +
>> + num_mbwu_mon = class->props.num_mbwu_mon;
>> + cntrs = __alloc_mbwu_array(mon->class, num_mbwu_mon);
>> + if (IS_ERR(cntrs))
>> + return PTR_ERR(cntrs);
>> + mon->assigned_counters = cntrs;
>> + mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
>> +
>> + mpam_resctrl_monitor_sync_abmc_vals(l3);
>> +
>> + return 0;
>> +}
>> +
>> static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
>> enum resctrl_event_id type)
>> {
>> @@ -1133,8 +1233,21 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
>> */
>> l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
>>
>> - if (resctrl_enable_mon_event(type, false, 0, NULL))
>> - l3->mon_capable = true;
>> + if (type == QOS_L3_MBM_TOTAL_EVENT_ID) {
>> + int err;
>> +
>> + err = mpam_resctrl_monitor_init_abmc(mon);
>> + if (err)
>> + return err;
>> +
>> + static_assert(MAX_EVT_CONFIG_BITS == 0x7f);
>> + l3->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
>> + }
>> +
>> + if (!resctrl_enable_mon_event(type, false, 0, NULL))
>> + return -EINVAL;
>> +
>> + l3->mon_capable = true;
>>
>> return 0;
>> }
>> @@ -1697,6 +1810,23 @@ void mpam_resctrl_exit(void)
>> resctrl_exit();
>> }
>>
>> +static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
>> +{
>> + u32 num_mbwu_mon = l3_num_allocated_mbwu;
>> +
>> + if (mon->mbwu_idx_to_mon)
>> + return;
>
> Isn't it 'if (mon->mbwu_idx_to_mon == NULL)' ?
Oops... indeed.
Thanks,
Ben
>
>
> Best regards,
> Shaopeng TAN
>
>> + if (mon->assigned_counters) {
>> + __free_mbwu_mon(class, mon->assigned_counters, num_mbwu_mon);
>> + kfree(mon->assigned_counters);
>> + mon->assigned_counters = NULL;
>> + }
>> +
>> + kfree(mon->mbwu_idx_to_mon);
>> + mon->mbwu_idx_to_mon = NULL;
>> +}
>> +
>> /*
>> * The driver is detaching an MSC from this class, if resctrl was using it,
>> * pull on resctrl_exit().
>> @@ -1719,6 +1849,8 @@ void mpam_resctrl_teardown_class(struct mpam_class *class)
>> for_each_mpam_resctrl_mon(mon, eventid) {
>> if (mon->class == class) {
>> mon->class = NULL;
>> +
>> + mpam_resctrl_teardown_mon(mon, class);
>> break;
>> }
>> }
>> --
>> 2.43.0
^ permalink raw reply
* Re: [PATCH net-next 1/2] net: ti: icssg: Derive stats array lengths from ARRAY_SIZE
From: MD Danish Anwar @ 2026-05-12 9:40 UTC (permalink / raw)
To: David CARLIER
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, Roger Quadros,
Andrew Lunn, Jacob Keller, Meghana Malladi, Kevin Hao,
Vadim Fedorenko, netdev, linux-doc, linux-kernel,
linux-arm-kernel, Vignesh Raghavendra
In-Reply-To: <CA+XhMqykBWcMdk+iNnOtUxM4MX6jpDyUwfuAVZFbjAShO9_v7Q@mail.gmail.com>
Hi David,
On 12/05/26 1:28 pm, David CARLIER wrote:
> Hi MD,
>
> On Tue, 12 May 2026 at 07:06, MD Danish Anwar <danishanwar@ti.com> wrote:
>>
>> Replace the manually maintained ICSSG_NUM_MIIG_STATS and
>> ICSSG_NUM_PA_STATS constants with ARRAY_SIZE() expressions derived
>> directly from the corresponding stat descriptor arrays, so that adding
>> new entries to icssg_all_miig_stats[] or icssg_all_pa_stats[] no longer
>> requires a separate update to a numeric constant.
>>
>> To make this self-contained, break the circular include dependency
>> between icssg_stats.h and icssg_prueth.h:
>>
>> - icssg_stats.h previously included icssg_prueth.h (transitively
>> pulling in icssg_switch_map.h and ETH_GSTRING_LEN). Replace that
>> with direct includes of <linux/ethtool.h>, <linux/kernel.h> and
>> "icssg_switch_map.h".
>>
>> - icssg_prueth.h now includes icssg_stats.h, giving it access to
>> the ARRAY_SIZE-based ICSSG_NUM_MIIG_STATS and ICSSG_NUM_PA_STATS
>> before they are used in the prueth_emac struct and ICSSG_NUM_STATS.
>>
>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>> ---
>> drivers/net/ethernet/ti/icssg/icssg_prueth.h | 3 +--
>> drivers/net/ethernet/ti/icssg/icssg_stats.h | 7 ++++++-
>> 2 files changed, 7 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> index df93d15c5b78..e2ccecb0a0dd 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> @@ -43,6 +43,7 @@
>>
>> #include "icssg_config.h"
>> #include "icss_iep.h"
>> +#include "icssg_stats.h"
>> #include "icssg_switch_map.h"
>>
>> #define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN)
>> @@ -57,8 +58,6 @@
>>
>> #define ICSSG_MAX_RFLOWS 8 /* per slice */
>>
>> -#define ICSSG_NUM_PA_STATS 32
>> -#define ICSSG_NUM_MIIG_STATS 60
>> /* Number of ICSSG related stats */
>> #define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
>> #define ICSSG_NUM_STANDARD_STATS 31
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> index 5ec0b38e0c67..b854eb587c1e 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> @@ -8,10 +8,15 @@
>> #ifndef __NET_TI_ICSSG_STATS_H
>> #define __NET_TI_ICSSG_STATS_H
>>
>> -#include "icssg_prueth.h"
>> +#include <linux/ethtool.h>
>> +#include <linux/kernel.h>
>> +#include "icssg_switch_map.h"
>>
>> #define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */
>>
>> +#define ICSSG_NUM_MIIG_STATS ARRAY_SIZE(icssg_all_miig_stats)
>> +#define ICSSG_NUM_PA_STATS ARRAY_SIZE(icssg_all_pa_stats)
>> +
>> struct miig_stats_regs {
>> /* Rx */
>> u32 rx_packets;
>> --
>> 2.34.1
>>
>
> One thing that caught my eye: icssg_all_miig_stats[] and
> icssg_all_pa_stats[] are 'static const' arrays in icssg_stats.h with
> ETH_GSTRING_LEN name buffers per entry. Right now only icssg_stats.c
> and icssg_ethtool.c pull them in. After this patch icssg_prueth.h
> includes icssg_stats.h, so every .c in the driver (classifier,
> common, config, mii_cfg, queues, switchdev, ...) ends up with its own
> static-const copy of both tables.
>
> Would a static_assert() work for what you're after? Something like:
>
While adding more stats manually, The ARRAY_SIZE() approach was
explicitly requested by maintainer [1]:
This patch is a direct response to that feedback. static_assert() would
still require updating the numeric constant on every array change. The
goal here is to eliminate the need of manually incrementing stats count
whenever new stats are added
Your concern about multiple copies of table is noted and valid. Could
you advise on the preferred way to reconcile these two requirements? I
am happy to restructure if there is an approach that satisfies both.
[1]
https://lore.kernel.org/all/20260112181436.4s5ceywwembn674r@skbuf/#:~:text=Can%27t%20this%20be%20expressed%20as%20ARRAY_SIZE(icssg_all_pa_stats)%3F%20It%20is%20very%0Afragile%20to%20have%20to%20count%20and%20update%20this%20manually.
> static const struct icssg_miig_stats icssg_all_miig_stats[] = {
> ...
> };
> static_assert(ARRAY_SIZE(icssg_all_miig_stats) == ICSSG_NUM_MIIG_STATS);
>
> next to each array, keeping the numeric #defines as-is. Then 2/2 fails
> to build the moment a new entry is added without bumping the count,
> which is the case you're guarding against — without touching the
> include graph.
>
> What do you think ?
>
> Cheers.
--
Thanks and Regards,
Danish
^ permalink raw reply
* Re: [PATCH 2/3] [v5 net-next] p54spi: convert to devicetree
From: Simon Horman @ 2026-05-12 9:40 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Arnd Bergmann, Netdev, Aaro Koskinen, Andreas Kemnade,
Bartosz Golaszewski, Benoît Cousson, David S . Miller,
Dmitry Torokhov, Eric Dumazet, Felipe Balbi, Jakub Kicinski,
Johannes Berg, Kevin Hilman, krzk+dt, Linus Walleij, Paolo Abeni,
Rob Herring, Roger Quadros, Tony Lindgren, linux-wireless,
devicetree, linux-kernel, linux-arm-kernel,
open list:GPIO SUBSYSTEM, Linux-OMAP, Krzysztof Kozlowski
In-Reply-To: <edc4d6d6-7a43-442e-adb5-148e37402924@app.fastmail.com>
On Mon, May 11, 2026 at 09:45:18PM +0200, Arnd Bergmann wrote:
> On Mon, May 11, 2026, at 18:12, Simon Horman wrote:
> >
> > Simon says: As a pre-existing issue I don't think we need to be concerned
> > about this in the scope of this patch-set. But it may
> > be a potential for follow-up.
> >
> > This problem wasn't introduced by this patch, but I noticed a pre-existing
> > issue in the context here. Does the p54spi_spi_read() function perform an SPI
> > transfer using a stack-allocated buffer?
> >
> > Looking at p54spi_spi_read(), the addr variable is allocated on the stack and
> > passed as a transfer buffer to spi_sync(). The SPI framework maps transfer
> > buffers for DMA. Passing a stack-allocated buffer is illegal, particularly with
> > CONFIG_VMAP_STACK enabled, because stack memory resides in vmalloc space and
> > cannot be safely DMA-mapped.
> >
> > Could this cause memory corruption or a kernel panic during the transfer?
>
> I already commented on this earlier: This is indeed a theoretical
> bug, but it works in practice because DMA-capable SPI controllers
> tend to all use MMIO for short transfers instead of DMA.
>
> SPI is very fragile this way, and I do have some patches to improve
> that overall, but it seems out of scope for this one driver.
Thanks, I agree this is out of scope.
> >> -
> >> - gpio_direction_output(p54spi_gpio_power, 0);
> >> - gpio_direction_input(p54spi_gpio_irq);
> >> -
> >> - ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
> >> - p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi",
> >> - priv->spi);
> >> + ret = request_irq(spi->irq, p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi);
> >
> > Simon says: This one seems more concerning in the context of this patch-set.
> >
> > Is there missing validation for spi->irq before calling request_irq()?
> >
> > If the device tree node lacks an interrupts property, the SPI core may set
> > spi->irq to 0 or a negative error code.
> >
> > Passing this directly to request_irq() without validation can successfully
> > hijack a core system interrupt like the system timer on some architectures,
> > leading to system instability or deadlocks.
> >
> > Should there be a check like if (spi->irq <= 0) to fail the probe gracefully?
>
> I also commented on this: request_irq() already fails gracefully
> with -EINVAL when presented with an invalid IRQ. IRQ 0 is guaranteed
> to be invalid on any target that uses devicetree.
Thanks, and sorry for not seeing your earlier comment.
Or realising it is a false positive.
^ permalink raw reply
* [PATCH v5] media: verisilicon: Create AV1 helper library
From: Benjamin Gaignard @ 2026-05-12 7:59 UTC (permalink / raw)
To: nicolas.dufresne, p.zabel, mchehab, heiko
Cc: linux-kernel, linux-media, linux-rockchip, linux-arm-kernel,
kernel, Benjamin Gaignard
Regroup all none hardware related AV1 functions into a helper library.
The goal is to avoid code duplication for future AV1 codecs.
Tested on rock 5b board Fluster score remains the same 204/241.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
version 5:
- be more strict about checking arrays range and the value returned
by hantro_av1_get_frame_index()
- rebased on v7.1-rc3 tag
version 4:
- change functions prototypes to use a structure.
- rebased on v7.1-rc2 tag.
drivers/media/platform/verisilicon/Makefile | 7 +-
.../media/platform/verisilicon/hantro_av1.c | 790 +++++++++++++
.../media/platform/verisilicon/hantro_av1.h | 64 ++
...entropymode.c => hantro_av1_entropymode.c} | 18 +-
...entropymode.h => hantro_av1_entropymode.h} | 18 +-
...av1_filmgrain.c => hantro_av1_filmgrain.c} | 125 +-
.../verisilicon/hantro_av1_filmgrain.h | 48 +
.../media/platform/verisilicon/hantro_hw.h | 7 +-
.../verisilicon/rockchip_av1_filmgrain.h | 36 -
.../verisilicon/rockchip_vpu981_hw_av1_dec.c | 1014 ++---------------
.../platform/verisilicon/rockchip_vpu_hw.c | 7 +-
11 files changed, 1115 insertions(+), 1019 deletions(-)
create mode 100644 drivers/media/platform/verisilicon/hantro_av1.c
create mode 100644 drivers/media/platform/verisilicon/hantro_av1.h
rename drivers/media/platform/verisilicon/{rockchip_av1_entropymode.c => hantro_av1_entropymode.c} (99%)
rename drivers/media/platform/verisilicon/{rockchip_av1_entropymode.h => hantro_av1_entropymode.h} (95%)
rename drivers/media/platform/verisilicon/{rockchip_av1_filmgrain.c => hantro_av1_filmgrain.c} (85%)
create mode 100644 drivers/media/platform/verisilicon/hantro_av1_filmgrain.h
delete mode 100644 drivers/media/platform/verisilicon/rockchip_av1_filmgrain.h
diff --git a/drivers/media/platform/verisilicon/Makefile b/drivers/media/platform/verisilicon/Makefile
index f6f019d04ff0..a1dd6c2d29be 100644
--- a/drivers/media/platform/verisilicon/Makefile
+++ b/drivers/media/platform/verisilicon/Makefile
@@ -19,7 +19,10 @@ hantro-vpu-y += \
hantro_hevc.o \
hantro_mpeg2.o \
hantro_vp8.o \
- hantro_vp9.o
+ hantro_vp9.o \
+ hantro_av1.o \
+ hantro_av1_filmgrain.o \
+ hantro_av1_entropymode.o
hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \
imx8m_vpu_hw.o
@@ -33,8 +36,6 @@ hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
rockchip_vpu2_hw_mpeg2_dec.o \
rockchip_vpu2_hw_vp8_dec.o \
rockchip_vpu981_hw_av1_dec.o \
- rockchip_av1_filmgrain.o \
- rockchip_av1_entropymode.o \
rockchip_vpu_hw.o
hantro-vpu-$(CONFIG_VIDEO_HANTRO_SUNXI) += \
diff --git a/drivers/media/platform/verisilicon/hantro_av1.c b/drivers/media/platform/verisilicon/hantro_av1.c
new file mode 100644
index 000000000000..ac7ae8e87f50
--- /dev/null
+++ b/drivers/media/platform/verisilicon/hantro_av1.c
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026, Collabora
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@collabora.com>
+ */
+
+#include <linux/types.h>
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "hantro.h"
+#include "hantro_av1.h"
+#include "hantro_hw.h"
+
+#define GM_GLOBAL_MODELS_PER_FRAME 7
+#define GLOBAL_MODEL_TOTAL_SIZE (6 * 4 + 4 * 2)
+#define GLOBAL_MODEL_SIZE ALIGN(GM_GLOBAL_MODELS_PER_FRAME * GLOBAL_MODEL_TOTAL_SIZE, 2048)
+#define AV1_MAX_TILES 128
+#define AV1_TILE_INFO_SIZE (AV1_MAX_TILES * 16)
+#define AV1_TILE_SIZE ALIGN(32 * 128, 4096)
+
+#define SUPERRES_SCALE_BITS 3
+
+#define DIV_LUT_PREC_BITS 14
+#define DIV_LUT_BITS 8
+#define DIV_LUT_NUM BIT(DIV_LUT_BITS)
+#define WARP_PARAM_REDUCE_BITS 6
+#define WARPEDMODEL_PREC_BITS 16
+
+#define AV1_DIV_ROUND_UP_POW2(value, n) \
+({ \
+ typeof(n) _n = n; \
+ typeof(value) _value = value; \
+ (_value + (BIT(_n) >> 1)) >> _n; \
+})
+
+#define AV1_DIV_ROUND_UP_POW2_SIGNED(value, n) \
+({ \
+ typeof(n) _n_ = n; \
+ typeof(value) _value_ = value; \
+ (((_value_) < 0) ? -AV1_DIV_ROUND_UP_POW2(-(_value_), (_n_)) \
+ : AV1_DIV_ROUND_UP_POW2((_value_), (_n_))); \
+})
+
+static const short div_lut[DIV_LUT_NUM + 1] = {
+ 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
+ 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
+ 15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
+ 14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
+ 13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
+ 13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
+ 13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
+ 12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
+ 12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
+ 11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
+ 11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
+ 11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
+ 10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
+ 10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
+ 10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
+ 9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
+ 9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
+ 9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
+ 9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
+ 9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
+ 8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
+ 8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
+ 8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
+ 8240, 8224, 8208, 8192,
+};
+
+enum hantro_av1_tx_mode {
+ HANTRO_AV1_TX_MODE_ONLY_4X4 = 0,
+ HANTRO_AV1_TX_MODE_8X8 = 1,
+ HANTRO_AV1_TX_MODE_16x16 = 2,
+ HANTRO_AV1_TX_MODE_32x32 = 3,
+ HANTRO_AV1_TX_MODE_SELECT = 4,
+};
+
+enum hantro_av1_inter_prediction_filter_type {
+ HANTRO_AV1_EIGHT_TAP_SMOOTH = 0,
+ HANTRO_AV1_EIGHT_TAP = 1,
+ HANTRO_AV1_EIGHT_TAP_SHARP = 2,
+ HANTRO_AV1_BILINEAR = 3,
+ HANTRO_AV1_SWITCHABLE = 4,
+};
+
+int hantro_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode)
+{
+ switch (tx_mode) {
+ case V4L2_AV1_TX_MODE_ONLY_4X4:
+ return HANTRO_AV1_TX_MODE_ONLY_4X4;
+ case V4L2_AV1_TX_MODE_LARGEST:
+ return HANTRO_AV1_TX_MODE_32x32;
+ case V4L2_AV1_TX_MODE_SELECT:
+ return HANTRO_AV1_TX_MODE_SELECT;
+ }
+
+ return HANTRO_AV1_TX_MODE_32x32;
+}
+
+int hantro_av1_get_hardware_mcomp_filt_type(int interpolation_filter)
+{
+ switch (interpolation_filter) {
+ case V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP:
+ return HANTRO_AV1_EIGHT_TAP;
+ case V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH:
+ return HANTRO_AV1_EIGHT_TAP_SMOOTH;
+ case V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP:
+ return HANTRO_AV1_EIGHT_TAP_SHARP;
+ case V4L2_AV1_INTERPOLATION_FILTER_BILINEAR:
+ return HANTRO_AV1_BILINEAR;
+ case V4L2_AV1_INTERPOLATION_FILTER_SWITCHABLE:
+ return HANTRO_AV1_SWITCHABLE;
+ }
+
+ return HANTRO_AV1_EIGHT_TAP_SMOOTH;
+}
+
+int hantro_av1_get_frame_index(struct hantro_ctx *ctx, int ref)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ u64 timestamp;
+ int i, idx;
+
+ if (ref < 0 || ref >= V4L2_AV1_REFS_PER_FRAME)
+ return AV1_INVALID_IDX;
+
+ idx = frame->ref_frame_idx[ref];
+
+ if (idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME || idx < 0)
+ return AV1_INVALID_IDX;
+
+ timestamp = frame->reference_frame_ts[idx];
+ for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
+ if (!av1_dec->frame_refs[i].used)
+ continue;
+ if (av1_dec->frame_refs[i].timestamp == timestamp)
+ return i;
+ }
+
+ return AV1_INVALID_IDX;
+}
+
+int hantro_av1_get_order_hint(struct hantro_ctx *ctx, int ref)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ int idx = hantro_av1_get_frame_index(ctx, ref);
+
+ if (idx != AV1_INVALID_IDX)
+ return av1_dec->frame_refs[idx].order_hint;
+
+ return 0;
+}
+
+int hantro_av1_frame_ref(struct hantro_ctx *ctx, u64 timestamp)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ int i;
+
+ for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
+ int j;
+
+ if (av1_dec->frame_refs[i].used)
+ continue;
+
+ av1_dec->frame_refs[i].width = frame->frame_width_minus_1 + 1;
+ av1_dec->frame_refs[i].height = frame->frame_height_minus_1 + 1;
+ av1_dec->frame_refs[i].mi_cols = DIV_ROUND_UP(frame->frame_width_minus_1 + 1, 8);
+ av1_dec->frame_refs[i].mi_rows = DIV_ROUND_UP(frame->frame_height_minus_1 + 1, 8);
+ av1_dec->frame_refs[i].timestamp = timestamp;
+ av1_dec->frame_refs[i].frame_type = frame->frame_type;
+ av1_dec->frame_refs[i].order_hint = frame->order_hint;
+ av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx);
+
+ for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++)
+ av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j];
+ av1_dec->frame_refs[i].used = true;
+ av1_dec->current_frame_index = i;
+
+ return i;
+ }
+
+ return AV1_INVALID_IDX;
+}
+
+static void hantro_av1_frame_unref(struct hantro_ctx *ctx, int idx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+
+ if (idx >= 0)
+ av1_dec->frame_refs[idx].used = false;
+}
+
+void hantro_av1_clean_refs(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+
+ int ref, idx;
+
+ for (idx = 0; idx < AV1_MAX_FRAME_BUF_COUNT; idx++) {
+ u64 timestamp = av1_dec->frame_refs[idx].timestamp;
+ bool used = false;
+
+ if (!av1_dec->frame_refs[idx].used)
+ continue;
+
+ for (ref = 0; ref < V4L2_AV1_TOTAL_REFS_PER_FRAME; ref++) {
+ if (ctrls->frame->reference_frame_ts[ref] == timestamp)
+ used = true;
+ }
+
+ if (!used)
+ hantro_av1_frame_unref(ctx, idx);
+ }
+}
+
+size_t hantro_av1_luma_size(struct hantro_ctx *ctx)
+{
+ return ctx->ref_fmt.plane_fmt[0].bytesperline * ctx->ref_fmt.height;
+}
+
+size_t hantro_av1_chroma_size(struct hantro_ctx *ctx)
+{
+ size_t cr_offset = hantro_av1_luma_size(ctx);
+
+ return ALIGN((cr_offset * 3) / 2, 64);
+}
+
+static void hantro_av1_tiles_free(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+
+ if (av1_dec->db_data_col.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->db_data_col.size,
+ av1_dec->db_data_col.cpu,
+ av1_dec->db_data_col.dma);
+ av1_dec->db_data_col.cpu = NULL;
+
+ if (av1_dec->db_ctrl_col.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->db_ctrl_col.size,
+ av1_dec->db_ctrl_col.cpu,
+ av1_dec->db_ctrl_col.dma);
+ av1_dec->db_ctrl_col.cpu = NULL;
+
+ if (av1_dec->cdef_col.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->cdef_col.size,
+ av1_dec->cdef_col.cpu, av1_dec->cdef_col.dma);
+ av1_dec->cdef_col.cpu = NULL;
+
+ if (av1_dec->sr_col.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->sr_col.size,
+ av1_dec->sr_col.cpu, av1_dec->sr_col.dma);
+ av1_dec->sr_col.cpu = NULL;
+
+ if (av1_dec->lr_col.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->lr_col.size,
+ av1_dec->lr_col.cpu, av1_dec->lr_col.dma);
+ av1_dec->lr_col.cpu = NULL;
+}
+
+static int hantro_av1_tiles_reallocate(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
+ unsigned int num_tile_cols = tile_info->tile_cols;
+ unsigned int height = ALIGN(ctrls->frame->frame_height_minus_1 + 1, 64);
+ unsigned int height_in_sb = height / 64;
+ unsigned int stripe_num = ((height + 8) + 63) / 64;
+ size_t size;
+
+ if (av1_dec->db_data_col.size >=
+ ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols)
+ return 0;
+
+ hantro_av1_tiles_free(ctx);
+
+ size = ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols;
+ av1_dec->db_data_col.cpu = dma_alloc_coherent(vpu->dev, size,
+ &av1_dec->db_data_col.dma,
+ GFP_KERNEL);
+ if (!av1_dec->db_data_col.cpu)
+ goto buffer_allocation_error;
+ av1_dec->db_data_col.size = size;
+
+ size = ALIGN(height * 2 * 16 / 4, 128) * num_tile_cols;
+ av1_dec->db_ctrl_col.cpu = dma_alloc_coherent(vpu->dev, size,
+ &av1_dec->db_ctrl_col.dma,
+ GFP_KERNEL);
+ if (!av1_dec->db_ctrl_col.cpu)
+ goto buffer_allocation_error;
+ av1_dec->db_ctrl_col.size = size;
+
+ size = ALIGN(height_in_sb * 44 * ctx->bit_depth * 16 / 8, 128) * num_tile_cols;
+ av1_dec->cdef_col.cpu = dma_alloc_coherent(vpu->dev, size,
+ &av1_dec->cdef_col.dma,
+ GFP_KERNEL);
+ if (!av1_dec->cdef_col.cpu)
+ goto buffer_allocation_error;
+ av1_dec->cdef_col.size = size;
+
+ size = ALIGN(height_in_sb * (3040 + 1280), 128) * num_tile_cols;
+ av1_dec->sr_col.cpu = dma_alloc_coherent(vpu->dev, size,
+ &av1_dec->sr_col.dma,
+ GFP_KERNEL);
+ if (!av1_dec->sr_col.cpu)
+ goto buffer_allocation_error;
+ av1_dec->sr_col.size = size;
+
+ size = ALIGN(stripe_num * 1536 * ctx->bit_depth / 8, 128) * num_tile_cols;
+ av1_dec->lr_col.cpu = dma_alloc_coherent(vpu->dev, size,
+ &av1_dec->lr_col.dma,
+ GFP_KERNEL);
+ if (!av1_dec->lr_col.cpu)
+ goto buffer_allocation_error;
+ av1_dec->lr_col.size = size;
+
+ av1_dec->num_tile_cols_allocated = num_tile_cols;
+ return 0;
+
+buffer_allocation_error:
+ hantro_av1_tiles_free(ctx);
+ return -ENOMEM;
+}
+
+void hantro_av1_exit(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+
+ if (av1_dec->global_model.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->global_model.size,
+ av1_dec->global_model.cpu,
+ av1_dec->global_model.dma);
+ av1_dec->global_model.cpu = NULL;
+
+ if (av1_dec->tile_info.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->tile_info.size,
+ av1_dec->tile_info.cpu,
+ av1_dec->tile_info.dma);
+ av1_dec->tile_info.cpu = NULL;
+
+ if (av1_dec->film_grain.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->film_grain.size,
+ av1_dec->film_grain.cpu,
+ av1_dec->film_grain.dma);
+ av1_dec->film_grain.cpu = NULL;
+
+ if (av1_dec->prob_tbl.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->prob_tbl.size,
+ av1_dec->prob_tbl.cpu, av1_dec->prob_tbl.dma);
+ av1_dec->prob_tbl.cpu = NULL;
+
+ if (av1_dec->prob_tbl_out.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->prob_tbl_out.size,
+ av1_dec->prob_tbl_out.cpu,
+ av1_dec->prob_tbl_out.dma);
+ av1_dec->prob_tbl_out.cpu = NULL;
+
+ if (av1_dec->tile_buf.cpu)
+ dma_free_coherent(vpu->dev, av1_dec->tile_buf.size,
+ av1_dec->tile_buf.cpu, av1_dec->tile_buf.dma);
+ av1_dec->tile_buf.cpu = NULL;
+
+ hantro_av1_tiles_free(ctx);
+}
+
+int hantro_av1_init(struct hantro_ctx *ctx)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+
+ memset(av1_dec, 0, sizeof(*av1_dec));
+
+ av1_dec->global_model.cpu = dma_alloc_coherent(vpu->dev, GLOBAL_MODEL_SIZE,
+ &av1_dec->global_model.dma,
+ GFP_KERNEL);
+ if (!av1_dec->global_model.cpu)
+ return -ENOMEM;
+ av1_dec->global_model.size = GLOBAL_MODEL_SIZE;
+
+ av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_TILE_INFO_SIZE,
+ &av1_dec->tile_info.dma,
+ GFP_KERNEL);
+ if (!av1_dec->tile_info.cpu)
+ return -ENOMEM;
+ av1_dec->tile_info.size = AV1_TILE_INFO_SIZE;
+
+ av1_dec->film_grain.cpu = dma_alloc_coherent(vpu->dev,
+ ALIGN(sizeof(struct hantro_av1_film_grain),
+ 2048),
+ &av1_dec->film_grain.dma,
+ GFP_KERNEL);
+ if (!av1_dec->film_grain.cpu)
+ return -ENOMEM;
+ av1_dec->film_grain.size = ALIGN(sizeof(struct hantro_av1_film_grain), 2048);
+
+ av1_dec->prob_tbl.cpu = dma_alloc_coherent(vpu->dev,
+ ALIGN(sizeof(struct av1cdfs), 2048),
+ &av1_dec->prob_tbl.dma,
+ GFP_KERNEL);
+ if (!av1_dec->prob_tbl.cpu)
+ return -ENOMEM;
+ av1_dec->prob_tbl.size = ALIGN(sizeof(struct av1cdfs), 2048);
+
+ av1_dec->prob_tbl_out.cpu = dma_alloc_coherent(vpu->dev,
+ ALIGN(sizeof(struct av1cdfs), 2048),
+ &av1_dec->prob_tbl_out.dma,
+ GFP_KERNEL);
+ if (!av1_dec->prob_tbl_out.cpu)
+ return -ENOMEM;
+ av1_dec->prob_tbl_out.size = ALIGN(sizeof(struct av1cdfs), 2048);
+ av1_dec->cdfs = &av1_dec->default_cdfs;
+ av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
+
+ hantro_av1_set_default_cdfs(av1_dec->cdfs, av1_dec->cdfs_ndvc);
+
+ av1_dec->tile_buf.cpu = dma_alloc_coherent(vpu->dev,
+ AV1_TILE_SIZE,
+ &av1_dec->tile_buf.dma,
+ GFP_KERNEL);
+ if (!av1_dec->tile_buf.cpu)
+ return -ENOMEM;
+ av1_dec->tile_buf.size = AV1_TILE_SIZE;
+
+ return 0;
+}
+
+int hantro_av1_prepare_run(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+
+ ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
+ if (WARN_ON(!ctrls->sequence))
+ return -EINVAL;
+
+ ctrls->tile_group_entry =
+ hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
+ if (WARN_ON(!ctrls->tile_group_entry))
+ return -EINVAL;
+
+ ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
+ if (WARN_ON(!ctrls->frame))
+ return -EINVAL;
+
+ ctrls->film_grain =
+ hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
+
+ return hantro_av1_tiles_reallocate(ctx);
+}
+
+static int hantro_av1_get_msb(u32 n)
+{
+ if (n == 0)
+ return 0;
+ return 31 ^ __builtin_clz(n);
+}
+
+static short hantro_av1_resolve_divisor_32(u32 d, short *shift)
+{
+ int f;
+ u64 e;
+
+ *shift = hantro_av1_get_msb(d);
+ /* e is obtained from D after resetting the most significant 1 bit. */
+ e = d - ((u32)1 << *shift);
+ /* Get the most significant DIV_LUT_BITS (8) bits of e into f */
+ if (*shift > DIV_LUT_BITS)
+ f = AV1_DIV_ROUND_UP_POW2(e, *shift - DIV_LUT_BITS);
+ else
+ f = e << (DIV_LUT_BITS - *shift);
+ if (f > DIV_LUT_NUM)
+ return -1;
+ *shift += DIV_LUT_PREC_BITS;
+ /* Use f as lookup into the precomputed table of multipliers */
+ return div_lut[f];
+}
+
+static void hantro_av1_get_shear_params(const u32 *params, s64 *alpha,
+ s64 *beta, s64 *gamma, s64 *delta)
+{
+ const int *mat = params;
+ short shift;
+ short y;
+ long long gv, dv;
+
+ if (mat[2] <= 0)
+ return;
+
+ *alpha = clamp_val(mat[2] - (1 << WARPEDMODEL_PREC_BITS), S16_MIN, S16_MAX);
+ *beta = clamp_val(mat[3], S16_MIN, S16_MAX);
+
+ y = hantro_av1_resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1);
+
+ gv = ((long long)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y;
+
+ *gamma = clamp_val((int)AV1_DIV_ROUND_UP_POW2_SIGNED(gv, shift), S16_MIN, S16_MAX);
+
+ dv = ((long long)mat[3] * mat[4]) * y;
+ *delta = clamp_val(mat[5] -
+ (int)AV1_DIV_ROUND_UP_POW2_SIGNED(dv, shift) - (1 << WARPEDMODEL_PREC_BITS),
+ S16_MIN, S16_MAX);
+
+ *alpha = AV1_DIV_ROUND_UP_POW2_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *beta = AV1_DIV_ROUND_UP_POW2_SIGNED(*beta, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *gamma = AV1_DIV_ROUND_UP_POW2_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+ *delta = AV1_DIV_ROUND_UP_POW2_SIGNED(*delta, WARP_PARAM_REDUCE_BITS)
+ * (1 << WARP_PARAM_REDUCE_BITS);
+}
+
+void hantro_av1_set_global_model(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ const struct v4l2_av1_global_motion *gm = &frame->global_motion;
+ u8 *dst = av1_dec->global_model.cpu;
+ int ref_frame, i;
+
+ memset(dst, 0, GLOBAL_MODEL_SIZE);
+ for (ref_frame = 0; ref_frame < V4L2_AV1_REFS_PER_FRAME; ++ref_frame) {
+ s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
+
+ for (i = 0; i < 6; ++i) {
+ if (i == 2)
+ *(s32 *)dst =
+ gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][3];
+ else if (i == 3)
+ *(s32 *)dst =
+ gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][2];
+ else
+ *(s32 *)dst =
+ gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][i];
+ dst += 4;
+ }
+
+ if (gm->type[V4L2_AV1_REF_LAST_FRAME + ref_frame] <= V4L2_AV1_WARP_MODEL_AFFINE)
+ hantro_av1_get_shear_params(&gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][0],
+ &alpha, &beta, &gamma, &delta);
+
+ *(s16 *)dst = alpha;
+ dst += 2;
+ *(s16 *)dst = beta;
+ dst += 2;
+ *(s16 *)dst = gamma;
+ dst += 2;
+ *(s16 *)dst = delta;
+ dst += 2;
+ }
+}
+
+int hantro_av1_tile_log2(int target)
+{
+ int k;
+
+ /*
+ * returns the smallest value for k such that 1 << k is greater
+ * than or equal to target
+ */
+ for (k = 0; (1 << k) < target; k++)
+ ;
+
+ return k;
+}
+
+int hantro_av1_get_dist(struct hantro_ctx *ctx, int a, int b)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ int bits = ctrls->sequence->order_hint_bits - 1;
+ int diff, m;
+
+ if (!ctrls->sequence->order_hint_bits)
+ return 0;
+
+ diff = a - b;
+ m = 1 << bits;
+ diff = (diff & (m - 1)) - (diff & m);
+
+ return diff;
+}
+
+void hantro_av1_set_frame_sign_bias(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ const struct v4l2_ctrl_av1_sequence *sequence = ctrls->sequence;
+ int i;
+
+ if (!sequence->order_hint_bits || IS_INTRA(frame->frame_type)) {
+ for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++)
+ av1_dec->ref_frame_sign_bias[i] = 0;
+
+ return;
+ }
+ // Identify the nearest forward and backward references.
+ for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME - 1; i++) {
+ if (hantro_av1_get_frame_index(ctx, i) >= 0) {
+ int rel_off =
+ hantro_av1_get_dist(ctx,
+ hantro_av1_get_order_hint(ctx, i),
+ frame->order_hint);
+ av1_dec->ref_frame_sign_bias[i + 1] = (rel_off <= 0) ? 0 : 1;
+ }
+ }
+}
+
+void hantro_av1_init_scaling_function(const u8 *values, const u8 *scaling,
+ u8 num_points, u8 *scaling_lut)
+{
+ int i, point;
+
+ if (num_points == 0) {
+ memset(scaling_lut, 0, 256);
+ return;
+ }
+
+ for (point = 0; point < num_points - 1; point++) {
+ int x;
+ s32 delta_y = scaling[point + 1] - scaling[point];
+ s32 delta_x = values[point + 1] - values[point];
+ s64 delta =
+ delta_x ? delta_y * ((65536 + (delta_x >> 1)) /
+ delta_x) : 0;
+
+ for (x = 0; x < delta_x; x++) {
+ scaling_lut[values[point] + x] =
+ scaling[point] +
+ (s32)((x * delta + 32768) >> 16);
+ }
+ }
+
+ for (i = values[num_points - 1]; i < 256; i++)
+ scaling_lut[i] = scaling[num_points - 1];
+}
+
+void hantro_av1_set_tile_info(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
+ const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
+ ctrls->tile_group_entry;
+ u8 *dst = av1_dec->tile_info.cpu;
+ int tile0, tile1;
+
+ memset(dst, 0, av1_dec->tile_info.size);
+
+ for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
+ for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
+ int tile_id = tile1 * tile_info->tile_cols + tile0;
+ u32 start, end;
+ u32 y0 =
+ tile_info->height_in_sbs_minus_1[tile1] + 1;
+ u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
+
+ /* tile size in SB units (width,height) */
+ *dst++ = x0;
+ *dst++ = 0;
+ *dst++ = 0;
+ *dst++ = 0;
+ *dst++ = y0;
+ *dst++ = 0;
+ *dst++ = 0;
+ *dst++ = 0;
+
+ /* tile start position */
+ start = group_entry[tile_id].tile_offset - group_entry[0].tile_offset;
+ *dst++ = start & 255;
+ *dst++ = (start >> 8) & 255;
+ *dst++ = (start >> 16) & 255;
+ *dst++ = (start >> 24) & 255;
+
+ /* number of bytes in tile data */
+ end = start + group_entry[tile_id].tile_size;
+ *dst++ = end & 255;
+ *dst++ = (end >> 8) & 255;
+ *dst++ = (end >> 16) & 255;
+ *dst++ = (end >> 24) & 255;
+ }
+ }
+}
+
+bool hantro_av1_is_lossless(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ const struct v4l2_av1_segmentation *segmentation = &frame->segmentation;
+ const struct v4l2_av1_quantization *quantization = &frame->quantization;
+ int i;
+
+ for (i = 0; i < V4L2_AV1_MAX_SEGMENTS; i++) {
+ int qindex = quantization->base_q_idx;
+
+ if (segmentation->feature_enabled[i] &
+ V4L2_AV1_SEGMENT_FEATURE_ENABLED(V4L2_AV1_SEG_LVL_ALT_Q)) {
+ qindex += segmentation->feature_data[i][V4L2_AV1_SEG_LVL_ALT_Q];
+ }
+ qindex = clamp(qindex, 0, 255);
+
+ if (qindex ||
+ quantization->delta_q_y_dc ||
+ quantization->delta_q_u_dc ||
+ quantization->delta_q_u_ac ||
+ quantization->delta_q_v_dc ||
+ quantization->delta_q_v_ac)
+ return false;
+ }
+
+ return true;
+}
+
+void hantro_av1_update_prob(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ bool frame_is_intra = IS_INTRA(frame->frame_type);
+ struct av1cdfs *out_cdfs = (struct av1cdfs *)av1_dec->prob_tbl_out.cpu;
+ int i;
+
+ if (frame->flags & V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF)
+ return;
+
+ for (i = 0; i < NUM_REF_FRAMES; i++) {
+ if (frame->refresh_frame_flags & BIT(i)) {
+ struct mvcdfs stored_mv_cdf;
+
+ hantro_av1_get_cdfs(ctx, i);
+ stored_mv_cdf = av1_dec->cdfs->mv_cdf;
+ *av1_dec->cdfs = *out_cdfs;
+ if (frame_is_intra) {
+ av1_dec->cdfs->mv_cdf = stored_mv_cdf;
+ *av1_dec->cdfs_ndvc = out_cdfs->mv_cdf;
+ }
+ hantro_av1_store_cdfs(ctx, frame->refresh_frame_flags);
+ break;
+ }
+ }
+}
+
+void hantro_av1_set_prob(struct hantro_ctx *ctx)
+{
+ struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
+ struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
+ const struct v4l2_av1_quantization *quantization = &frame->quantization;
+ bool error_resilient_mode =
+ !!(frame->flags & V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE);
+ bool frame_is_intra = IS_INTRA(frame->frame_type);
+
+ if (error_resilient_mode || frame_is_intra ||
+ frame->primary_ref_frame == AV1_PRIMARY_REF_NONE) {
+ av1_dec->cdfs = &av1_dec->default_cdfs;
+ av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
+ hantro_av1_default_coeff_probs(quantization->base_q_idx,
+ av1_dec->cdfs);
+ } else {
+ if (frame->primary_ref_frame < 0 ||
+ frame->primary_ref_frame >= V4L2_AV1_REFS_PER_FRAME)
+ return;
+
+ hantro_av1_get_cdfs(ctx, frame->ref_frame_idx[frame->primary_ref_frame]);
+ }
+ hantro_av1_store_cdfs(ctx, frame->refresh_frame_flags);
+
+ memcpy(av1_dec->prob_tbl.cpu, av1_dec->cdfs, sizeof(struct av1cdfs));
+
+ if (frame_is_intra) {
+ int mv_offset = offsetof(struct av1cdfs, mv_cdf);
+ /* Overwrite MV context area with intrabc MV context */
+ memcpy(av1_dec->prob_tbl.cpu + mv_offset, av1_dec->cdfs_ndvc,
+ sizeof(struct mvcdfs));
+ }
+}
diff --git a/drivers/media/platform/verisilicon/hantro_av1.h b/drivers/media/platform/verisilicon/hantro_av1.h
new file mode 100644
index 000000000000..d91c814eefcb
--- /dev/null
+++ b/drivers/media/platform/verisilicon/hantro_av1.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _HANTRO_AV1_H_
+#define _HANTRO_AV1_H_
+
+#define AV1_PRIMARY_REF_NONE 7
+#define AV1_REF_SCALE_SHIFT 14
+#define MAX_FRAME_DISTANCE 31
+#define AV1DEC_MAX_PIC_BUFFERS 24
+
+#define SCALE_NUMERATOR 8
+#define SUPERRES_SCALE_DENOMINATOR_MIN (SCALE_NUMERATOR + 1)
+
+#define RS_SCALE_SUBPEL_BITS 14
+#define RS_SCALE_SUBPEL_MASK ((1 << RS_SCALE_SUBPEL_BITS) - 1)
+#define RS_SUBPEL_BITS 6
+#define RS_SUBPEL_MASK ((1 << RS_SUBPEL_BITS) - 1)
+#define RS_SCALE_EXTRA_BITS (RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS)
+#define RS_SCALE_EXTRA_OFF (1 << (RS_SCALE_EXTRA_BITS - 1))
+
+/*
+ * These 3 values aren't defined enum v4l2_av1_segment_feature because
+ * they are not part of the specification
+ */
+#define V4L2_AV1_SEG_LVL_ALT_LF_Y_H 2
+#define V4L2_AV1_SEG_LVL_ALT_LF_U 3
+#define V4L2_AV1_SEG_LVL_ALT_LF_V 4
+
+#define IS_INTRA(type) ((type == V4L2_AV1_KEY_FRAME) || (type == V4L2_AV1_INTRA_ONLY_FRAME))
+
+#define LST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define LST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define LST3_BUF_IDX (V4L2_AV1_REF_LAST3_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define GLD_BUF_IDX (V4L2_AV1_REF_GOLDEN_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define BWD_BUF_IDX (V4L2_AV1_REF_BWDREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define ALT2_BUF_IDX (V4L2_AV1_REF_ALTREF2_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define ALT_BUF_IDX (V4L2_AV1_REF_ALTREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
+
+#define AV1_INVALID_IDX -1
+
+int hantro_av1_get_frame_index(struct hantro_ctx *ctx, int ref);
+int hantro_av1_get_order_hint(struct hantro_ctx *ctx, int ref);
+int hantro_av1_frame_ref(struct hantro_ctx *ctx, u64 timestamp);
+void hantro_av1_clean_refs(struct hantro_ctx *ctx);
+size_t hantro_av1_luma_size(struct hantro_ctx *ctx);
+size_t hantro_av1_chroma_size(struct hantro_ctx *ctx);
+void hantro_av1_exit(struct hantro_ctx *ctx);
+int hantro_av1_init(struct hantro_ctx *ctx);
+int hantro_av1_prepare_run(struct hantro_ctx *ctx);
+void hantro_av1_set_global_model(struct hantro_ctx *ctx);
+int hantro_av1_tile_log2(int target);
+int hantro_av1_get_dist(struct hantro_ctx *ctx, int a, int b);
+void hantro_av1_set_frame_sign_bias(struct hantro_ctx *ctx);
+void hantro_av1_init_scaling_function(const u8 *values, const u8 *scaling,
+ u8 num_points, u8 *scaling_lut);
+void hantro_av1_set_tile_info(struct hantro_ctx *ctx);
+bool hantro_av1_is_lossless(struct hantro_ctx *ctx);
+void hantro_av1_update_prob(struct hantro_ctx *ctx);
+void hantro_av1_set_prob(struct hantro_ctx *ctx);
+
+int hantro_av1_get_hardware_mcomp_filt_type(int interpolation_filter);
+int hantro_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode);
+
+#endif
diff --git a/drivers/media/platform/verisilicon/rockchip_av1_entropymode.c b/drivers/media/platform/verisilicon/hantro_av1_entropymode.c
similarity index 99%
rename from drivers/media/platform/verisilicon/rockchip_av1_entropymode.c
rename to drivers/media/platform/verisilicon/hantro_av1_entropymode.c
index b1ae72ad675e..4f7bfec73668 100644
--- a/drivers/media/platform/verisilicon/rockchip_av1_entropymode.c
+++ b/drivers/media/platform/verisilicon/hantro_av1_entropymode.c
@@ -11,7 +11,7 @@
*/
#include "hantro.h"
-#include "rockchip_av1_entropymode.h"
+#include "hantro_av1_entropymode.h"
#define AOM_ICDF ICDF
#define AOM_CDF2(a0) AOM_ICDF(a0)
@@ -4195,7 +4195,7 @@ static const u16 default_bits_cdf[][10] = {
}
};
-static int rockchip_av1_get_q_ctx(int q)
+static int hantro_av1_get_q_ctx(int q)
{
if (q <= 20)
return 0;
@@ -4206,10 +4206,10 @@ static int rockchip_av1_get_q_ctx(int q)
return 3;
}
-void rockchip_av1_default_coeff_probs(u32 base_qindex, void *ptr)
+void hantro_av1_default_coeff_probs(u32 base_qindex, void *ptr)
{
struct av1cdfs *cdfs = (struct av1cdfs *)ptr;
- const int index = rockchip_av1_get_q_ctx(base_qindex);
+ const int index = hantro_av1_get_q_ctx(base_qindex);
memcpy(cdfs->txb_skip_cdf, av1_default_txb_skip_cdfs[index],
sizeof(av1_default_txb_skip_cdfs[0]));
@@ -4240,8 +4240,8 @@ void rockchip_av1_default_coeff_probs(u32 base_qindex, void *ptr)
sizeof(av1_default_eob_multi1024_cdfs[0]));
}
-void rockchip_av1_set_default_cdfs(struct av1cdfs *cdfs,
- struct mvcdfs *cdfs_ndvc)
+void hantro_av1_set_default_cdfs(struct av1cdfs *cdfs,
+ struct mvcdfs *cdfs_ndvc)
{
memcpy(cdfs->partition_cdf, default_partition_cdf,
sizeof(cdfs->partition_cdf));
@@ -4398,7 +4398,7 @@ void rockchip_av1_set_default_cdfs(struct av1cdfs *cdfs,
sizeof(cdfs->compound_idx_cdf));
}
-void rockchip_av1_get_cdfs(struct hantro_ctx *ctx, u32 ref_idx)
+void hantro_av1_get_cdfs(struct hantro_ctx *ctx, u32 ref_idx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
@@ -4406,8 +4406,8 @@ void rockchip_av1_get_cdfs(struct hantro_ctx *ctx, u32 ref_idx)
av1_dec->cdfs_ndvc = &av1_dec->cdfs_last_ndvc[ref_idx];
}
-void rockchip_av1_store_cdfs(struct hantro_ctx *ctx,
- u32 refresh_frame_flags)
+void hantro_av1_store_cdfs(struct hantro_ctx *ctx,
+ u32 refresh_frame_flags)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
int i;
diff --git a/drivers/media/platform/verisilicon/rockchip_av1_entropymode.h b/drivers/media/platform/verisilicon/hantro_av1_entropymode.h
similarity index 95%
rename from drivers/media/platform/verisilicon/rockchip_av1_entropymode.h
rename to drivers/media/platform/verisilicon/hantro_av1_entropymode.h
index bbf8424c7d2c..abbc660ecce3 100644
--- a/drivers/media/platform/verisilicon/rockchip_av1_entropymode.h
+++ b/drivers/media/platform/verisilicon/hantro_av1_entropymode.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef _ROCKCHIP_AV1_ENTROPYMODE_H_
-#define _ROCKCHIP_AV1_ENTROPYMODE_H_
+#ifndef _HANTRO_AV1_ENTROPYMODE_H_
+#define _HANTRO_AV1_ENTROPYMODE_H_
#include <linux/types.h>
@@ -262,11 +262,11 @@ struct av1cdfs {
u16 dummy3[16];
};
-void rockchip_av1_store_cdfs(struct hantro_ctx *ctx,
- u32 refresh_frame_flags);
-void rockchip_av1_get_cdfs(struct hantro_ctx *ctx, u32 ref_idx);
-void rockchip_av1_set_default_cdfs(struct av1cdfs *cdfs,
- struct mvcdfs *cdfs_ndvc);
-void rockchip_av1_default_coeff_probs(u32 base_qindex, void *ptr);
+void hantro_av1_store_cdfs(struct hantro_ctx *ctx,
+ u32 refresh_frame_flags);
+void hantro_av1_get_cdfs(struct hantro_ctx *ctx, u32 ref_idx);
+void hantro_av1_set_default_cdfs(struct av1cdfs *cdfs,
+ struct mvcdfs *cdfs_ndvc);
+void hantro_av1_default_coeff_probs(u32 base_qindex, void *ptr);
-#endif /* _ROCKCHIP_AV1_ENTROPYMODE_H_ */
+#endif /* _HANTRO_AV1_ENTROPYMODE_H_ */
diff --git a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c b/drivers/media/platform/verisilicon/hantro_av1_filmgrain.c
similarity index 85%
rename from drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c
rename to drivers/media/platform/verisilicon/hantro_av1_filmgrain.c
index f64dea797eff..a1fc40e0218a 100644
--- a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c
+++ b/drivers/media/platform/verisilicon/hantro_av1_filmgrain.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0
-#include "rockchip_av1_filmgrain.h"
+#include "hantro_av1_filmgrain.h"
static const s32 gaussian_sequence[2048] = {
56, 568, -180, 172, 124, -84, 172, -64, -900, 24, 820,
@@ -204,8 +204,8 @@ static inline s32 round_power_of_two(const s32 val, s32 n)
return (val + a) >> n;
}
-static void rockchip_av1_init_random_generator(u8 luma_num, u16 seed,
- u16 *random_register)
+static void hantro_av1_init_random_generator(u8 luma_num, u16 seed,
+ u16 *random_register)
{
u16 random_reg = seed;
@@ -214,7 +214,7 @@ static void rockchip_av1_init_random_generator(u8 luma_num, u16 seed,
*random_register = random_reg;
}
-static inline void rockchip_av1_update_random_register(u16 *random_register)
+static inline void hantro_av1_update_random_register(u16 *random_register)
{
u16 bit;
u16 random_reg = *random_register;
@@ -224,21 +224,20 @@ static inline void rockchip_av1_update_random_register(u16 *random_register)
*random_register = (random_reg >> 1) | (bit << 15);
}
-static inline s32 rockchip_av1_get_random_number(u16 random_register)
+static inline s32 hantro_av1_get_random_number(u16 random_register)
{
return (random_register >> 5) & ((1 << 11) - 1);
}
-void rockchip_av1_generate_luma_grain_block(s32 (*luma_grain_block)[73][82],
- s32 bitdepth,
- u8 num_y_points,
- s32 grain_scale_shift,
- s32 ar_coeff_lag,
- s32 (*ar_coeffs_y)[24],
- s32 ar_coeff_shift,
- s32 grain_min,
- s32 grain_max,
- u16 random_seed)
+void hantro_av1_generate_luma_grain_block(struct hantro_av1_coeffs_grain_block *coeffs,
+ s32 bitdepth,
+ u8 num_y_points,
+ s32 grain_scale_shift,
+ s32 ar_coeff_lag,
+ s32 ar_coeff_shift,
+ s32 grain_min,
+ s32 grain_max,
+ u16 random_seed)
{
s32 gauss_sec_shift = 12 - bitdepth + grain_scale_shift;
u16 grain_random_register = random_seed;
@@ -247,15 +246,15 @@ void rockchip_av1_generate_luma_grain_block(s32 (*luma_grain_block)[73][82],
for (i = 0; i < 73; i++) {
for (j = 0; j < 82; j++) {
if (num_y_points > 0) {
- rockchip_av1_update_random_register
+ hantro_av1_update_random_register
(&grain_random_register);
- (*luma_grain_block)[i][j] =
+ coeffs->luma_grain_block[i][j] =
round_power_of_two(gaussian_sequence
- [rockchip_av1_get_random_number
+ [hantro_av1_get_random_number
(grain_random_register)],
gauss_sec_shift);
} else {
- (*luma_grain_block)[i][j] = 0;
+ coeffs->luma_grain_block[i][j] = 0;
}
}
}
@@ -272,72 +271,68 @@ void rockchip_av1_generate_luma_grain_block(s32 (*luma_grain_block)[73][82],
deltacol <= ar_coeff_lag; deltacol++) {
if (deltarow == 0 && deltacol == 0)
break;
- wsum = wsum + (*ar_coeffs_y)[pos] *
- (*luma_grain_block)[i + deltarow][j + deltacol];
+ wsum = wsum + coeffs->ar_coeffs_y[pos] *
+ coeffs->luma_grain_block[i + deltarow][j + deltacol];
++pos;
}
}
- (*luma_grain_block)[i][j] =
- clamp((*luma_grain_block)[i][j] +
+ coeffs->luma_grain_block[i][j] =
+ clamp(coeffs->luma_grain_block[i][j] +
round_power_of_two(wsum, ar_coeff_shift),
grain_min, grain_max);
}
}
// Calculate chroma grain noise once per frame
-void rockchip_av1_generate_chroma_grain_block(s32 (*luma_grain_block)[73][82],
- s32 (*cb_grain_block)[38][44],
- s32 (*cr_grain_block)[38][44],
- s32 bitdepth,
- u8 num_y_points,
- u8 num_cb_points,
- u8 num_cr_points,
- s32 grain_scale_shift,
- s32 ar_coeff_lag,
- s32 (*ar_coeffs_cb)[25],
- s32 (*ar_coeffs_cr)[25],
- s32 ar_coeff_shift,
- s32 grain_min,
- s32 grain_max,
- u8 chroma_scaling_from_luma,
- u16 random_seed)
+void hantro_av1_generate_chroma_grain_block(struct hantro_av1_coeffs_grain_block *coeffs,
+ s32 bitdepth,
+ u8 num_y_points,
+ u8 num_cb_points,
+ u8 num_cr_points,
+ s32 grain_scale_shift,
+ s32 ar_coeff_lag,
+ s32 ar_coeff_shift,
+ s32 grain_min,
+ s32 grain_max,
+ u8 chroma_scaling_from_luma,
+ u16 random_seed)
{
s32 gauss_sec_shift = 12 - bitdepth + grain_scale_shift;
u16 grain_random_register = 0;
s32 i, j;
- rockchip_av1_init_random_generator(7, random_seed,
- &grain_random_register);
+ hantro_av1_init_random_generator(7, random_seed,
+ &grain_random_register);
for (i = 0; i < 38; i++) {
for (j = 0; j < 44; j++) {
if (num_cb_points || chroma_scaling_from_luma) {
- rockchip_av1_update_random_register
+ hantro_av1_update_random_register
(&grain_random_register);
- (*cb_grain_block)[i][j] =
+ coeffs->cb_grain_block[i][j] =
round_power_of_two(gaussian_sequence
- [rockchip_av1_get_random_number
+ [hantro_av1_get_random_number
(grain_random_register)],
gauss_sec_shift);
} else {
- (*cb_grain_block)[i][j] = 0;
+ coeffs->cb_grain_block[i][j] = 0;
}
}
}
- rockchip_av1_init_random_generator(11, random_seed,
- &grain_random_register);
+ hantro_av1_init_random_generator(11, random_seed,
+ &grain_random_register);
for (i = 0; i < 38; i++) {
for (j = 0; j < 44; j++) {
if (num_cr_points || chroma_scaling_from_luma) {
- rockchip_av1_update_random_register
+ hantro_av1_update_random_register
(&grain_random_register);
- (*cr_grain_block)[i][j] =
+ coeffs->cr_grain_block[i][j] =
round_power_of_two(gaussian_sequence
- [rockchip_av1_get_random_number
+ [hantro_av1_get_random_number
(grain_random_register)],
gauss_sec_shift);
} else {
- (*cr_grain_block)[i][j] = 0;
+ coeffs->cr_grain_block[i][j] = 0;
}
}
}
@@ -355,12 +350,12 @@ void rockchip_av1_generate_chroma_grain_block(s32 (*luma_grain_block)[73][82],
deltacol <= ar_coeff_lag; deltacol++) {
if (deltarow == 0 && deltacol == 0)
break;
- wsum_cb = wsum_cb + (*ar_coeffs_cb)[pos] *
- (*cb_grain_block)[i + deltarow][j + deltacol];
+ wsum_cb = wsum_cb + coeffs->ar_coeffs_cb[pos] *
+ coeffs->cb_grain_block[i + deltarow][j + deltacol];
wsum_cr =
wsum_cr +
- (*ar_coeffs_cr)[pos] *
- (*cr_grain_block)[i + deltarow][j + deltacol];
+ coeffs->ar_coeffs_cr[pos] *
+ coeffs->cr_grain_block[i + deltarow][j + deltacol];
++pos;
}
}
@@ -371,28 +366,28 @@ void rockchip_av1_generate_chroma_grain_block(s32 (*luma_grain_block)[73][82],
s32 luma_coord_x = (j << 1) - 3;
av_luma +=
- (*luma_grain_block)[luma_coord_y][luma_coord_x];
+ coeffs->luma_grain_block[luma_coord_y][luma_coord_x];
av_luma +=
- (*luma_grain_block)[luma_coord_y][luma_coord_x + 1];
+ coeffs->luma_grain_block[luma_coord_y][luma_coord_x + 1];
av_luma +=
- (*luma_grain_block)[luma_coord_y + 1][luma_coord_x];
+ coeffs->luma_grain_block[luma_coord_y + 1][luma_coord_x];
av_luma +=
- (*luma_grain_block)[(luma_coord_y + 1)][luma_coord_x + 1];
+ coeffs->luma_grain_block[(luma_coord_y + 1)][luma_coord_x + 1];
av_luma = round_power_of_two(av_luma, 2);
- wsum_cb = wsum_cb + (*ar_coeffs_cb)[pos] * av_luma;
- wsum_cr = wsum_cr + (*ar_coeffs_cr)[pos] * av_luma;
+ wsum_cb = wsum_cb + coeffs->ar_coeffs_cb[pos] * av_luma;
+ wsum_cr = wsum_cr + coeffs->ar_coeffs_cr[pos] * av_luma;
}
if (num_cb_points || chroma_scaling_from_luma) {
- (*cb_grain_block)[i][j] =
- clamp((*cb_grain_block)[i][j] +
+ coeffs->cb_grain_block[i][j] =
+ clamp(coeffs->cb_grain_block[i][j] +
round_power_of_two(wsum_cb, ar_coeff_shift),
grain_min, grain_max);
}
if (num_cr_points || chroma_scaling_from_luma) {
- (*cr_grain_block)[i][j] =
- clamp((*cr_grain_block)[i][j] +
+ coeffs->cr_grain_block[i][j] =
+ clamp(coeffs->cr_grain_block[i][j] +
round_power_of_two(wsum_cr, ar_coeff_shift),
grain_min, grain_max);
}
diff --git a/drivers/media/platform/verisilicon/hantro_av1_filmgrain.h b/drivers/media/platform/verisilicon/hantro_av1_filmgrain.h
new file mode 100644
index 000000000000..d80be7c011a0
--- /dev/null
+++ b/drivers/media/platform/verisilicon/hantro_av1_filmgrain.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _HANTRO_AV1_FILMGRAIN_H_
+#define _HANTRO_AV1_FILMGRAIN_H_
+
+#include <linux/types.h>
+
+struct hantro_av1_film_grain {
+ u8 scaling_lut_y[256];
+ u8 scaling_lut_cb[256];
+ u8 scaling_lut_cr[256];
+ s16 cropped_luma_grain_block[4096];
+ s16 cropped_chroma_grain_block[1024 * 2];
+};
+
+struct hantro_av1_coeffs_grain_block {
+ s32 ar_coeffs_y[24];
+ s32 ar_coeffs_cb[25];
+ s32 ar_coeffs_cr[25];
+ s32 luma_grain_block[73][82];
+ s32 cb_grain_block[38][44];
+ s32 cr_grain_block[38][44];
+};
+
+void hantro_av1_generate_luma_grain_block(struct hantro_av1_coeffs_grain_block *coeffs,
+ s32 bitdepth,
+ u8 num_y_points,
+ s32 grain_scale_shift,
+ s32 ar_coeff_lag,
+ s32 ar_coeff_shift,
+ s32 grain_min,
+ s32 grain_max,
+ u16 random_seed);
+
+void hantro_av1_generate_chroma_grain_block(struct hantro_av1_coeffs_grain_block *coeffs,
+ s32 bitdepth,
+ u8 num_y_points,
+ u8 num_cb_points,
+ u8 num_cr_points,
+ s32 grain_scale_shift,
+ s32 ar_coeff_lag,
+ s32 ar_coeff_shift,
+ s32 grain_min,
+ s32 grain_max,
+ u8 chroma_scaling_from_luma,
+ u16 random_seed);
+
+#endif
diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h
index 5f2011529f02..d1d39d1df5d2 100644
--- a/drivers/media/platform/verisilicon/hantro_hw.h
+++ b/drivers/media/platform/verisilicon/hantro_hw.h
@@ -15,8 +15,8 @@
#include <media/v4l2-vp9.h>
#include <media/videobuf2-core.h>
-#include "rockchip_av1_entropymode.h"
-#include "rockchip_av1_filmgrain.h"
+#include "hantro_av1_entropymode.h"
+#include "hantro_av1_filmgrain.h"
#define DEC_8190_ALIGN_MASK 0x07U
@@ -459,10 +459,7 @@ void hantro_hevc_ref_init(struct hantro_ctx *ctx);
dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, s32 poc);
int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr);
-int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx);
-void rockchip_vpu981_av1_dec_exit(struct hantro_ctx *ctx);
int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx);
-void rockchip_vpu981_av1_dec_done(struct hantro_ctx *ctx);
static inline unsigned short hantro_vp9_num_sbs(unsigned short dimension)
{
diff --git a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.h b/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.h
deleted file mode 100644
index 31a8b7920c31..000000000000
--- a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef _ROCKCHIP_AV1_FILMGRAIN_H_
-#define _ROCKCHIP_AV1_FILMGRAIN_H_
-
-#include <linux/types.h>
-
-void rockchip_av1_generate_luma_grain_block(s32 (*luma_grain_block)[73][82],
- s32 bitdepth,
- u8 num_y_points,
- s32 grain_scale_shift,
- s32 ar_coeff_lag,
- s32 (*ar_coeffs_y)[24],
- s32 ar_coeff_shift,
- s32 grain_min,
- s32 grain_max,
- u16 random_seed);
-
-void rockchip_av1_generate_chroma_grain_block(s32 (*luma_grain_block)[73][82],
- s32 (*cb_grain_block)[38][44],
- s32 (*cr_grain_block)[38][44],
- s32 bitdepth,
- u8 num_y_points,
- u8 num_cb_points,
- u8 num_cr_points,
- s32 grain_scale_shift,
- s32 ar_coeff_lag,
- s32 (*ar_coeffs_cb)[25],
- s32 (*ar_coeffs_cr)[25],
- s32 ar_coeff_shift,
- s32 grain_min,
- s32 grain_max,
- u8 chroma_scaling_from_luma,
- u16 random_seed);
-
-#endif
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index e4e21ad37323..61e30338422d 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -7,622 +7,35 @@
#include <media/v4l2-mem2mem.h>
#include "hantro.h"
+#include "hantro_av1.h"
#include "hantro_v4l2.h"
#include "rockchip_vpu981_regs.h"
#define AV1_DEC_MODE 17
-#define GM_GLOBAL_MODELS_PER_FRAME 7
-#define GLOBAL_MODEL_TOTAL_SIZE (6 * 4 + 4 * 2)
-#define GLOBAL_MODEL_SIZE ALIGN(GM_GLOBAL_MODELS_PER_FRAME * GLOBAL_MODEL_TOTAL_SIZE, 2048)
-#define AV1_MAX_TILES 128
-#define AV1_TILE_INFO_SIZE (AV1_MAX_TILES * 16)
-#define AV1DEC_MAX_PIC_BUFFERS 24
-#define AV1_REF_SCALE_SHIFT 14
-#define AV1_INVALID_IDX -1
-#define MAX_FRAME_DISTANCE 31
-#define AV1_PRIMARY_REF_NONE 7
-#define AV1_TILE_SIZE ALIGN(32 * 128, 4096)
-/*
- * These 3 values aren't defined enum v4l2_av1_segment_feature because
- * they are not part of the specification
- */
-#define V4L2_AV1_SEG_LVL_ALT_LF_Y_H 2
-#define V4L2_AV1_SEG_LVL_ALT_LF_U 3
-#define V4L2_AV1_SEG_LVL_ALT_LF_V 4
-
-#define SUPERRES_SCALE_BITS 3
-#define SCALE_NUMERATOR 8
-#define SUPERRES_SCALE_DENOMINATOR_MIN (SCALE_NUMERATOR + 1)
-
-#define RS_SUBPEL_BITS 6
-#define RS_SUBPEL_MASK ((1 << RS_SUBPEL_BITS) - 1)
-#define RS_SCALE_SUBPEL_BITS 14
-#define RS_SCALE_SUBPEL_MASK ((1 << RS_SCALE_SUBPEL_BITS) - 1)
-#define RS_SCALE_EXTRA_BITS (RS_SCALE_SUBPEL_BITS - RS_SUBPEL_BITS)
-#define RS_SCALE_EXTRA_OFF (1 << (RS_SCALE_EXTRA_BITS - 1))
-
-#define IS_INTRA(type) ((type == V4L2_AV1_KEY_FRAME) || (type == V4L2_AV1_INTRA_ONLY_FRAME))
-
-#define LST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define LST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define LST3_BUF_IDX (V4L2_AV1_REF_LAST3_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define GLD_BUF_IDX (V4L2_AV1_REF_GOLDEN_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define BWD_BUF_IDX (V4L2_AV1_REF_BWDREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define ALT2_BUF_IDX (V4L2_AV1_REF_ALTREF2_FRAME - V4L2_AV1_REF_LAST_FRAME)
-#define ALT_BUF_IDX (V4L2_AV1_REF_ALTREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
-
-#define DIV_LUT_PREC_BITS 14
-#define DIV_LUT_BITS 8
-#define DIV_LUT_NUM BIT(DIV_LUT_BITS)
-#define WARP_PARAM_REDUCE_BITS 6
-#define WARPEDMODEL_PREC_BITS 16
-
-#define AV1_DIV_ROUND_UP_POW2(value, n) \
-({ \
- typeof(n) _n = n; \
- typeof(value) _value = value; \
- (_value + (BIT(_n) >> 1)) >> _n; \
-})
-
-#define AV1_DIV_ROUND_UP_POW2_SIGNED(value, n) \
-({ \
- typeof(n) _n_ = n; \
- typeof(value) _value_ = value; \
- (((_value_) < 0) ? -AV1_DIV_ROUND_UP_POW2(-(_value_), (_n_)) \
- : AV1_DIV_ROUND_UP_POW2((_value_), (_n_))); \
-})
-
-enum rockchip_av1_tx_mode {
- ROCKCHIP_AV1_TX_MODE_ONLY_4X4 = 0,
- ROCKCHIP_AV1_TX_MODE_8X8 = 1,
- ROCKCHIP_AV1_TX_MODE_16x16 = 2,
- ROCKCHIP_AV1_TX_MODE_32x32 = 3,
- ROCKCHIP_AV1_TX_MODE_SELECT = 4,
-};
-
-struct rockchip_av1_film_grain {
- u8 scaling_lut_y[256];
- u8 scaling_lut_cb[256];
- u8 scaling_lut_cr[256];
- s16 cropped_luma_grain_block[4096];
- s16 cropped_chroma_grain_block[1024 * 2];
-};
-
-static const short div_lut[DIV_LUT_NUM + 1] = {
- 16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
- 15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
- 15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
- 14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
- 13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
- 13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
- 13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
- 12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
- 12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
- 11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
- 11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
- 11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
- 10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
- 10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
- 10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
- 9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
- 9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
- 9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
- 9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
- 9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
- 8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
- 8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
- 8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
- 8240, 8224, 8208, 8192,
-};
-
-static int rockchip_vpu981_get_frame_index(struct hantro_ctx *ctx, int ref)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- u64 timestamp;
- int i, idx = frame->ref_frame_idx[ref];
-
- if (idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME || idx < 0)
- return AV1_INVALID_IDX;
-
- timestamp = frame->reference_frame_ts[idx];
- for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
- if (!av1_dec->frame_refs[i].used)
- continue;
- if (av1_dec->frame_refs[i].timestamp == timestamp)
- return i;
- }
-
- return AV1_INVALID_IDX;
-}
-
-static int rockchip_vpu981_get_order_hint(struct hantro_ctx *ctx, int ref)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- int idx = rockchip_vpu981_get_frame_index(ctx, ref);
-
- if (idx != AV1_INVALID_IDX)
- return av1_dec->frame_refs[idx].order_hint;
-
- return 0;
-}
-
-static int rockchip_vpu981_av1_dec_frame_ref(struct hantro_ctx *ctx,
- u64 timestamp)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- int i;
-
- for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
- int j;
-
- if (av1_dec->frame_refs[i].used)
- continue;
-
- av1_dec->frame_refs[i].width = frame->frame_width_minus_1 + 1;
- av1_dec->frame_refs[i].height = frame->frame_height_minus_1 + 1;
- av1_dec->frame_refs[i].mi_cols = DIV_ROUND_UP(frame->frame_width_minus_1 + 1, 8);
- av1_dec->frame_refs[i].mi_rows = DIV_ROUND_UP(frame->frame_height_minus_1 + 1, 8);
- av1_dec->frame_refs[i].timestamp = timestamp;
- av1_dec->frame_refs[i].frame_type = frame->frame_type;
- av1_dec->frame_refs[i].order_hint = frame->order_hint;
- av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx);
-
- for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++)
- av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j];
- av1_dec->frame_refs[i].used = true;
- av1_dec->current_frame_index = i;
-
- return i;
- }
-
- return AV1_INVALID_IDX;
-}
-
-static void rockchip_vpu981_av1_dec_frame_unref(struct hantro_ctx *ctx, int idx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
-
- if (idx >= 0)
- av1_dec->frame_refs[idx].used = false;
-}
-
-static void rockchip_vpu981_av1_dec_clean_refs(struct hantro_ctx *ctx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
-
- int ref, idx;
-
- for (idx = 0; idx < AV1_MAX_FRAME_BUF_COUNT; idx++) {
- u64 timestamp = av1_dec->frame_refs[idx].timestamp;
- bool used = false;
-
- if (!av1_dec->frame_refs[idx].used)
- continue;
-
- for (ref = 0; ref < V4L2_AV1_TOTAL_REFS_PER_FRAME; ref++) {
- if (ctrls->frame->reference_frame_ts[ref] == timestamp)
- used = true;
- }
-
- if (!used)
- rockchip_vpu981_av1_dec_frame_unref(ctx, idx);
- }
-}
-
-static size_t rockchip_vpu981_av1_dec_luma_size(struct hantro_ctx *ctx)
-{
- return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8;
-}
-
-static size_t rockchip_vpu981_av1_dec_chroma_size(struct hantro_ctx *ctx)
-{
- size_t cr_offset = rockchip_vpu981_av1_dec_luma_size(ctx);
-
- return ALIGN((cr_offset * 3) / 2, 64);
-}
-
-static void rockchip_vpu981_av1_dec_tiles_free(struct hantro_ctx *ctx)
-{
- struct hantro_dev *vpu = ctx->dev;
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
-
- if (av1_dec->db_data_col.cpu)
- dma_free_coherent(vpu->dev, av1_dec->db_data_col.size,
- av1_dec->db_data_col.cpu,
- av1_dec->db_data_col.dma);
- av1_dec->db_data_col.cpu = NULL;
-
- if (av1_dec->db_ctrl_col.cpu)
- dma_free_coherent(vpu->dev, av1_dec->db_ctrl_col.size,
- av1_dec->db_ctrl_col.cpu,
- av1_dec->db_ctrl_col.dma);
- av1_dec->db_ctrl_col.cpu = NULL;
-
- if (av1_dec->cdef_col.cpu)
- dma_free_coherent(vpu->dev, av1_dec->cdef_col.size,
- av1_dec->cdef_col.cpu, av1_dec->cdef_col.dma);
- av1_dec->cdef_col.cpu = NULL;
-
- if (av1_dec->sr_col.cpu)
- dma_free_coherent(vpu->dev, av1_dec->sr_col.size,
- av1_dec->sr_col.cpu, av1_dec->sr_col.dma);
- av1_dec->sr_col.cpu = NULL;
-
- if (av1_dec->lr_col.cpu)
- dma_free_coherent(vpu->dev, av1_dec->lr_col.size,
- av1_dec->lr_col.cpu, av1_dec->lr_col.dma);
- av1_dec->lr_col.cpu = NULL;
-}
-
-static int rockchip_vpu981_av1_dec_tiles_reallocate(struct hantro_ctx *ctx)
-{
- struct hantro_dev *vpu = ctx->dev;
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
- unsigned int num_tile_cols = tile_info->tile_cols;
- unsigned int height = ALIGN(ctrls->frame->frame_height_minus_1 + 1, 64);
- unsigned int height_in_sb = height / 64;
- unsigned int stripe_num = ((height + 8) + 63) / 64;
- size_t size;
-
- if (av1_dec->db_data_col.size >=
- ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols)
- return 0;
-
- rockchip_vpu981_av1_dec_tiles_free(ctx);
-
- size = ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols;
- av1_dec->db_data_col.cpu = dma_alloc_coherent(vpu->dev, size,
- &av1_dec->db_data_col.dma,
- GFP_KERNEL);
- if (!av1_dec->db_data_col.cpu)
- goto buffer_allocation_error;
- av1_dec->db_data_col.size = size;
-
- size = ALIGN(height * 2 * 16 / 4, 128) * num_tile_cols;
- av1_dec->db_ctrl_col.cpu = dma_alloc_coherent(vpu->dev, size,
- &av1_dec->db_ctrl_col.dma,
- GFP_KERNEL);
- if (!av1_dec->db_ctrl_col.cpu)
- goto buffer_allocation_error;
- av1_dec->db_ctrl_col.size = size;
-
- size = ALIGN(height_in_sb * 44 * ctx->bit_depth * 16 / 8, 128) * num_tile_cols;
- av1_dec->cdef_col.cpu = dma_alloc_coherent(vpu->dev, size,
- &av1_dec->cdef_col.dma,
- GFP_KERNEL);
- if (!av1_dec->cdef_col.cpu)
- goto buffer_allocation_error;
- av1_dec->cdef_col.size = size;
-
- size = ALIGN(height_in_sb * (3040 + 1280), 128) * num_tile_cols;
- av1_dec->sr_col.cpu = dma_alloc_coherent(vpu->dev, size,
- &av1_dec->sr_col.dma,
- GFP_KERNEL);
- if (!av1_dec->sr_col.cpu)
- goto buffer_allocation_error;
- av1_dec->sr_col.size = size;
-
- size = ALIGN(stripe_num * 1536 * ctx->bit_depth / 8, 128) * num_tile_cols;
- av1_dec->lr_col.cpu = dma_alloc_coherent(vpu->dev, size,
- &av1_dec->lr_col.dma,
- GFP_KERNEL);
- if (!av1_dec->lr_col.cpu)
- goto buffer_allocation_error;
- av1_dec->lr_col.size = size;
-
- av1_dec->num_tile_cols_allocated = num_tile_cols;
- return 0;
-
-buffer_allocation_error:
- rockchip_vpu981_av1_dec_tiles_free(ctx);
- return -ENOMEM;
-}
-
-void rockchip_vpu981_av1_dec_exit(struct hantro_ctx *ctx)
-{
- struct hantro_dev *vpu = ctx->dev;
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
-
- if (av1_dec->global_model.cpu)
- dma_free_coherent(vpu->dev, av1_dec->global_model.size,
- av1_dec->global_model.cpu,
- av1_dec->global_model.dma);
- av1_dec->global_model.cpu = NULL;
-
- if (av1_dec->tile_info.cpu)
- dma_free_coherent(vpu->dev, av1_dec->tile_info.size,
- av1_dec->tile_info.cpu,
- av1_dec->tile_info.dma);
- av1_dec->tile_info.cpu = NULL;
-
- if (av1_dec->film_grain.cpu)
- dma_free_coherent(vpu->dev, av1_dec->film_grain.size,
- av1_dec->film_grain.cpu,
- av1_dec->film_grain.dma);
- av1_dec->film_grain.cpu = NULL;
-
- if (av1_dec->prob_tbl.cpu)
- dma_free_coherent(vpu->dev, av1_dec->prob_tbl.size,
- av1_dec->prob_tbl.cpu, av1_dec->prob_tbl.dma);
- av1_dec->prob_tbl.cpu = NULL;
-
- if (av1_dec->prob_tbl_out.cpu)
- dma_free_coherent(vpu->dev, av1_dec->prob_tbl_out.size,
- av1_dec->prob_tbl_out.cpu,
- av1_dec->prob_tbl_out.dma);
- av1_dec->prob_tbl_out.cpu = NULL;
-
- if (av1_dec->tile_buf.cpu)
- dma_free_coherent(vpu->dev, av1_dec->tile_buf.size,
- av1_dec->tile_buf.cpu, av1_dec->tile_buf.dma);
- av1_dec->tile_buf.cpu = NULL;
-
- rockchip_vpu981_av1_dec_tiles_free(ctx);
-}
-
-int rockchip_vpu981_av1_dec_init(struct hantro_ctx *ctx)
-{
- struct hantro_dev *vpu = ctx->dev;
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
-
- memset(av1_dec, 0, sizeof(*av1_dec));
-
- av1_dec->global_model.cpu = dma_alloc_coherent(vpu->dev, GLOBAL_MODEL_SIZE,
- &av1_dec->global_model.dma,
- GFP_KERNEL);
- if (!av1_dec->global_model.cpu)
- return -ENOMEM;
- av1_dec->global_model.size = GLOBAL_MODEL_SIZE;
-
- av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_TILE_INFO_SIZE,
- &av1_dec->tile_info.dma,
- GFP_KERNEL);
- if (!av1_dec->tile_info.cpu)
- return -ENOMEM;
- av1_dec->tile_info.size = AV1_TILE_INFO_SIZE;
-
- av1_dec->film_grain.cpu = dma_alloc_coherent(vpu->dev,
- ALIGN(sizeof(struct rockchip_av1_film_grain), 2048),
- &av1_dec->film_grain.dma,
- GFP_KERNEL);
- if (!av1_dec->film_grain.cpu)
- return -ENOMEM;
- av1_dec->film_grain.size = ALIGN(sizeof(struct rockchip_av1_film_grain), 2048);
-
- av1_dec->prob_tbl.cpu = dma_alloc_coherent(vpu->dev,
- ALIGN(sizeof(struct av1cdfs), 2048),
- &av1_dec->prob_tbl.dma,
- GFP_KERNEL);
- if (!av1_dec->prob_tbl.cpu)
- return -ENOMEM;
- av1_dec->prob_tbl.size = ALIGN(sizeof(struct av1cdfs), 2048);
-
- av1_dec->prob_tbl_out.cpu = dma_alloc_coherent(vpu->dev,
- ALIGN(sizeof(struct av1cdfs), 2048),
- &av1_dec->prob_tbl_out.dma,
- GFP_KERNEL);
- if (!av1_dec->prob_tbl_out.cpu)
- return -ENOMEM;
- av1_dec->prob_tbl_out.size = ALIGN(sizeof(struct av1cdfs), 2048);
- av1_dec->cdfs = &av1_dec->default_cdfs;
- av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
-
- rockchip_av1_set_default_cdfs(av1_dec->cdfs, av1_dec->cdfs_ndvc);
-
- av1_dec->tile_buf.cpu = dma_alloc_coherent(vpu->dev,
- AV1_TILE_SIZE,
- &av1_dec->tile_buf.dma,
- GFP_KERNEL);
- if (!av1_dec->tile_buf.cpu)
- return -ENOMEM;
- av1_dec->tile_buf.size = AV1_TILE_SIZE;
-
- return 0;
-}
-
-static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
-
- ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
- if (WARN_ON(!ctrls->sequence))
- return -EINVAL;
-
- ctrls->tile_group_entry =
- hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
- if (WARN_ON(!ctrls->tile_group_entry))
- return -EINVAL;
-
- ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
- if (WARN_ON(!ctrls->frame))
- return -EINVAL;
-
- ctrls->film_grain =
- hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
-
- return rockchip_vpu981_av1_dec_tiles_reallocate(ctx);
-}
-
-static inline int rockchip_vpu981_av1_dec_get_msb(u32 n)
-{
- if (n == 0)
- return 0;
- return 31 ^ __builtin_clz(n);
-}
-
-static short rockchip_vpu981_av1_dec_resolve_divisor_32(u32 d, short *shift)
-{
- int f;
- u64 e;
-
- *shift = rockchip_vpu981_av1_dec_get_msb(d);
- /* e is obtained from D after resetting the most significant 1 bit. */
- e = d - ((u32)1 << *shift);
- /* Get the most significant DIV_LUT_BITS (8) bits of e into f */
- if (*shift > DIV_LUT_BITS)
- f = AV1_DIV_ROUND_UP_POW2(e, *shift - DIV_LUT_BITS);
- else
- f = e << (DIV_LUT_BITS - *shift);
- if (f > DIV_LUT_NUM)
- return -1;
- *shift += DIV_LUT_PREC_BITS;
- /* Use f as lookup into the precomputed table of multipliers */
- return div_lut[f];
-}
-
-static void
-rockchip_vpu981_av1_dec_get_shear_params(const u32 *params, s64 *alpha,
- s64 *beta, s64 *gamma, s64 *delta)
-{
- const int *mat = params;
- short shift;
- short y;
- long long gv, dv;
-
- if (mat[2] <= 0)
- return;
-
- *alpha = clamp_val(mat[2] - (1 << WARPEDMODEL_PREC_BITS), S16_MIN, S16_MAX);
- *beta = clamp_val(mat[3], S16_MIN, S16_MAX);
-
- y = rockchip_vpu981_av1_dec_resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1);
-
- gv = ((long long)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y;
-
- *gamma = clamp_val((int)AV1_DIV_ROUND_UP_POW2_SIGNED(gv, shift), S16_MIN, S16_MAX);
-
- dv = ((long long)mat[3] * mat[4]) * y;
- *delta = clamp_val(mat[5] -
- (int)AV1_DIV_ROUND_UP_POW2_SIGNED(dv, shift) - (1 << WARPEDMODEL_PREC_BITS),
- S16_MIN, S16_MAX);
-
- *alpha = AV1_DIV_ROUND_UP_POW2_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS)
- * (1 << WARP_PARAM_REDUCE_BITS);
- *beta = AV1_DIV_ROUND_UP_POW2_SIGNED(*beta, WARP_PARAM_REDUCE_BITS)
- * (1 << WARP_PARAM_REDUCE_BITS);
- *gamma = AV1_DIV_ROUND_UP_POW2_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS)
- * (1 << WARP_PARAM_REDUCE_BITS);
- *delta = AV1_DIV_ROUND_UP_POW2_SIGNED(*delta, WARP_PARAM_REDUCE_BITS)
- * (1 << WARP_PARAM_REDUCE_BITS);
-}
static void rockchip_vpu981_av1_dec_set_global_model(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- const struct v4l2_av1_global_motion *gm = &frame->global_motion;
- u8 *dst = av1_dec->global_model.cpu;
struct hantro_dev *vpu = ctx->dev;
- int ref_frame, i;
-
- memset(dst, 0, GLOBAL_MODEL_SIZE);
- for (ref_frame = 0; ref_frame < V4L2_AV1_REFS_PER_FRAME; ++ref_frame) {
- s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
-
- for (i = 0; i < 6; ++i) {
- if (i == 2)
- *(s32 *)dst =
- gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][3];
- else if (i == 3)
- *(s32 *)dst =
- gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][2];
- else
- *(s32 *)dst =
- gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][i];
- dst += 4;
- }
-
- if (gm->type[V4L2_AV1_REF_LAST_FRAME + ref_frame] <= V4L2_AV1_WARP_MODEL_AFFINE)
- rockchip_vpu981_av1_dec_get_shear_params(&gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][0],
- &alpha, &beta, &gamma, &delta);
-
- *(s16 *)dst = alpha;
- dst += 2;
- *(s16 *)dst = beta;
- dst += 2;
- *(s16 *)dst = gamma;
- dst += 2;
- *(s16 *)dst = delta;
- dst += 2;
- }
+ hantro_av1_set_global_model(ctx);
hantro_write_addr(vpu, AV1_GLOBAL_MODEL, av1_dec->global_model.dma);
}
-static int rockchip_vpu981_av1_tile_log2(int target)
-{
- int k;
-
- /*
- * returns the smallest value for k such that 1 << k is greater
- * than or equal to target
- */
- for (k = 0; (1 << k) < target; k++);
-
- return k;
-}
-
static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
- const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
- ctrls->tile_group_entry;
int context_update_y =
tile_info->context_update_tile_id / tile_info->tile_cols;
int context_update_x =
tile_info->context_update_tile_id % tile_info->tile_cols;
int context_update_tile_id =
context_update_x * tile_info->tile_rows + context_update_y;
- u8 *dst = av1_dec->tile_info.cpu;
struct hantro_dev *vpu = ctx->dev;
- int tile0, tile1;
-
- memset(dst, 0, av1_dec->tile_info.size);
-
- for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
- for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
- int tile_id = tile1 * tile_info->tile_cols + tile0;
- u32 start, end;
- u32 y0 =
- tile_info->height_in_sbs_minus_1[tile1] + 1;
- u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
-
- /* tile size in SB units (width,height) */
- *dst++ = x0;
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = y0;
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = 0;
-
- /* tile start position */
- start = group_entry[tile_id].tile_offset - group_entry[0].tile_offset;
- *dst++ = start & 255;
- *dst++ = (start >> 8) & 255;
- *dst++ = (start >> 16) & 255;
- *dst++ = (start >> 24) & 255;
-
- /* number of bytes in tile data */
- end = start + group_entry[tile_id].tile_size;
- *dst++ = end & 255;
- *dst++ = (end >> 8) & 255;
- *dst++ = (end >> 16) & 255;
- *dst++ = (end >> 24) & 255;
- }
- }
+
+ hantro_av1_set_tile_info(ctx);
hantro_reg_write(vpu, &av1_multicore_expect_context_update, !!(context_update_x == 0));
hantro_reg_write(vpu, &av1_tile_enable,
@@ -631,8 +44,8 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
hantro_reg_write(vpu, &av1_num_tile_rows_8k, tile_info->tile_rows);
hantro_reg_write(vpu, &av1_context_update_tile_id, context_update_tile_id);
hantro_reg_write(vpu, &av1_tile_transpose, 1);
- if (rockchip_vpu981_av1_tile_log2(tile_info->tile_cols) ||
- rockchip_vpu981_av1_tile_log2(tile_info->tile_rows))
+ if (hantro_av1_tile_log2(tile_info->tile_cols) ||
+ hantro_av1_tile_log2(tile_info->tile_rows))
hantro_reg_write(vpu, &av1_dec_tile_size_mag, tile_info->tile_size_bytes - 1);
else
hantro_reg_write(vpu, &av1_dec_tile_size_mag, 3);
@@ -640,50 +53,6 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
hantro_write_addr(vpu, AV1_TILE_BASE, av1_dec->tile_info.dma);
}
-static int rockchip_vpu981_av1_dec_get_dist(struct hantro_ctx *ctx,
- int a, int b)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- int bits = ctrls->sequence->order_hint_bits - 1;
- int diff, m;
-
- if (!ctrls->sequence->order_hint_bits)
- return 0;
-
- diff = a - b;
- m = 1 << bits;
- diff = (diff & (m - 1)) - (diff & m);
-
- return diff;
-}
-
-static void rockchip_vpu981_av1_dec_set_frame_sign_bias(struct hantro_ctx *ctx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- const struct v4l2_ctrl_av1_sequence *sequence = ctrls->sequence;
- int i;
-
- if (!sequence->order_hint_bits || IS_INTRA(frame->frame_type)) {
- for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++)
- av1_dec->ref_frame_sign_bias[i] = 0;
-
- return;
- }
- // Identify the nearest forward and backward references.
- for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME - 1; i++) {
- if (rockchip_vpu981_get_frame_index(ctx, i) >= 0) {
- int rel_off =
- rockchip_vpu981_av1_dec_get_dist(ctx,
- rockchip_vpu981_get_order_hint(ctx, i),
- frame->order_hint);
- av1_dec->ref_frame_sign_bias[i + 1] = (rel_off <= 0) ? 0 : 1;
- }
- }
-}
-
static bool
rockchip_vpu981_av1_dec_set_ref(struct hantro_ctx *ctx, int ref, int idx,
int width, int height)
@@ -806,12 +175,12 @@ static void rockchip_vpu981_av1_dec_set_segmentation(struct hantro_ctx *ctx)
if (!!(seg->flags & V4L2_AV1_SEGMENTATION_FLAG_ENABLED) &&
frame->primary_ref_frame < V4L2_AV1_REFS_PER_FRAME) {
- int idx = rockchip_vpu981_get_frame_index(ctx, frame->primary_ref_frame);
+ int idx = hantro_av1_get_frame_index(ctx, frame->primary_ref_frame);
- if (idx >= 0) {
+ if (idx != AV1_INVALID_IDX) {
dma_addr_t luma_addr, mv_addr = 0;
struct hantro_decoded_buffer *seg;
- size_t mv_offset = rockchip_vpu981_av1_dec_chroma_size(ctx);
+ size_t mv_offset = hantro_av1_chroma_size(ctx);
seg = vb2_to_hantro_decoded_buf(&av1_dec->frame_refs[idx].vb2_ref->vb2_buf);
luma_addr = hantro_get_dec_buf_addr(ctx, &seg->base.vb.vb2_buf);
@@ -1041,35 +410,6 @@ static void rockchip_vpu981_av1_dec_set_segmentation(struct hantro_ctx *ctx)
segval[7][V4L2_AV1_SEG_LVL_REF_GLOBALMV]);
}
-static bool rockchip_vpu981_av1_dec_is_lossless(struct hantro_ctx *ctx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- const struct v4l2_av1_segmentation *segmentation = &frame->segmentation;
- const struct v4l2_av1_quantization *quantization = &frame->quantization;
- int i;
-
- for (i = 0; i < V4L2_AV1_MAX_SEGMENTS; i++) {
- int qindex = quantization->base_q_idx;
-
- if (segmentation->feature_enabled[i] &
- V4L2_AV1_SEGMENT_FEATURE_ENABLED(V4L2_AV1_SEG_LVL_ALT_Q)) {
- qindex += segmentation->feature_data[i][V4L2_AV1_SEG_LVL_ALT_Q];
- }
- qindex = clamp(qindex, 0, 255);
-
- if (qindex ||
- quantization->delta_q_y_dc ||
- quantization->delta_q_u_dc ||
- quantization->delta_q_u_ac ||
- quantization->delta_q_v_dc ||
- quantization->delta_q_v_ac)
- return false;
- }
- return true;
-}
-
static void rockchip_vpu981_av1_dec_set_loopfilter(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
@@ -1089,7 +429,7 @@ static void rockchip_vpu981_av1_dec_set_loopfilter(struct hantro_ctx *ctx)
hantro_reg_write(vpu, &av1_filt_level3, loop_filter->level[3]);
if (loop_filter->flags & V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED &&
- !rockchip_vpu981_av1_dec_is_lossless(ctx) &&
+ !hantro_av1_is_lossless(ctx) &&
!(frame->flags & V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC)) {
hantro_reg_write(vpu, &av1_filt_ref_adj_0,
loop_filter->ref_deltas[0]);
@@ -1128,121 +468,27 @@ static void rockchip_vpu981_av1_dec_set_loopfilter(struct hantro_ctx *ctx)
hantro_write_addr(vpu, AV1_DB_CTRL_COL, av1_dec->db_ctrl_col.dma);
}
-static void rockchip_vpu981_av1_dec_update_prob(struct hantro_ctx *ctx)
-{
- struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- bool frame_is_intra = IS_INTRA(frame->frame_type);
- struct av1cdfs *out_cdfs = (struct av1cdfs *)av1_dec->prob_tbl_out.cpu;
- int i;
-
- if (frame->flags & V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF)
- return;
-
- for (i = 0; i < NUM_REF_FRAMES; i++) {
- if (frame->refresh_frame_flags & BIT(i)) {
- struct mvcdfs stored_mv_cdf;
-
- rockchip_av1_get_cdfs(ctx, i);
- stored_mv_cdf = av1_dec->cdfs->mv_cdf;
- *av1_dec->cdfs = *out_cdfs;
- if (frame_is_intra) {
- av1_dec->cdfs->mv_cdf = stored_mv_cdf;
- *av1_dec->cdfs_ndvc = out_cdfs->mv_cdf;
- }
- rockchip_av1_store_cdfs(ctx,
- frame->refresh_frame_flags);
- break;
- }
- }
-}
-
-void rockchip_vpu981_av1_dec_done(struct hantro_ctx *ctx)
-{
- rockchip_vpu981_av1_dec_update_prob(ctx);
-}
-
static void rockchip_vpu981_av1_dec_set_prob(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
- struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
- const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
- const struct v4l2_av1_quantization *quantization = &frame->quantization;
struct hantro_dev *vpu = ctx->dev;
- bool error_resilient_mode =
- !!(frame->flags & V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE);
- bool frame_is_intra = IS_INTRA(frame->frame_type);
-
- if (error_resilient_mode || frame_is_intra ||
- frame->primary_ref_frame == AV1_PRIMARY_REF_NONE) {
- av1_dec->cdfs = &av1_dec->default_cdfs;
- av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
- rockchip_av1_default_coeff_probs(quantization->base_q_idx,
- av1_dec->cdfs);
- } else {
- rockchip_av1_get_cdfs(ctx, frame->ref_frame_idx[frame->primary_ref_frame]);
- }
- rockchip_av1_store_cdfs(ctx, frame->refresh_frame_flags);
-
- memcpy(av1_dec->prob_tbl.cpu, av1_dec->cdfs, sizeof(struct av1cdfs));
-
- if (frame_is_intra) {
- int mv_offset = offsetof(struct av1cdfs, mv_cdf);
- /* Overwrite MV context area with intrabc MV context */
- memcpy(av1_dec->prob_tbl.cpu + mv_offset, av1_dec->cdfs_ndvc,
- sizeof(struct mvcdfs));
- }
+ hantro_av1_set_prob(ctx);
hantro_write_addr(vpu, AV1_PROP_TABLE_OUT, av1_dec->prob_tbl_out.dma);
hantro_write_addr(vpu, AV1_PROP_TABLE, av1_dec->prob_tbl.dma);
}
-static void
-rockchip_vpu981_av1_dec_init_scaling_function(const u8 *values, const u8 *scaling,
- u8 num_points, u8 *scaling_lut)
-{
- int i, point;
-
- if (num_points == 0) {
- memset(scaling_lut, 0, 256);
- return;
- }
-
- for (point = 0; point < num_points - 1; point++) {
- int x;
- s32 delta_y = scaling[point + 1] - scaling[point];
- s32 delta_x = values[point + 1] - values[point];
- s64 delta =
- delta_x ? delta_y * ((65536 + (delta_x >> 1)) /
- delta_x) : 0;
-
- for (x = 0; x < delta_x; x++) {
- scaling_lut[values[point] + x] =
- scaling[point] +
- (s32)((x * delta + 32768) >> 16);
- }
- }
-
- for (i = values[num_points - 1]; i < 256; i++)
- scaling_lut[i] = scaling[num_points - 1];
-}
static void rockchip_vpu981_av1_dec_set_fgs(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
const struct v4l2_ctrl_av1_film_grain *film_grain = ctrls->film_grain;
- struct rockchip_av1_film_grain *fgmem = av1_dec->film_grain.cpu;
+ struct hantro_av1_film_grain *fgmem = av1_dec->film_grain.cpu;
struct hantro_dev *vpu = ctx->dev;
bool scaling_from_luma =
!!(film_grain->flags & V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA);
- s32 (*ar_coeffs_y)[24];
- s32 (*ar_coeffs_cb)[25];
- s32 (*ar_coeffs_cr)[25];
- s32 (*luma_grain_block)[73][82];
- s32 (*cb_grain_block)[38][44];
- s32 (*cr_grain_block)[38][44];
+ struct hantro_av1_coeffs_grain_block *coeffs;
s32 ar_coeff_lag, ar_coeff_shift;
s32 grain_scale_shift, bitdepth;
s32 grain_center, grain_min, grain_max;
@@ -1269,18 +515,9 @@ static void rockchip_vpu981_av1_dec_set_fgs(struct hantro_ctx *ctx)
return;
}
- ar_coeffs_y = kzalloc(sizeof(int32_t) * 24, GFP_KERNEL);
- ar_coeffs_cb = kzalloc(sizeof(int32_t) * 25, GFP_KERNEL);
- ar_coeffs_cr = kzalloc(sizeof(int32_t) * 25, GFP_KERNEL);
- luma_grain_block = kzalloc(sizeof(int32_t) * 73 * 82, GFP_KERNEL);
- cb_grain_block = kzalloc(sizeof(int32_t) * 38 * 44, GFP_KERNEL);
- cr_grain_block = kzalloc(sizeof(int32_t) * 38 * 44, GFP_KERNEL);
-
- if (!ar_coeffs_y || !ar_coeffs_cb || !ar_coeffs_cr ||
- !luma_grain_block || !cb_grain_block || !cr_grain_block) {
- pr_warn("Fail allocating memory for film grain parameters\n");
- goto alloc_fail;
- }
+ coeffs = kzalloc(sizeof(*coeffs), GFP_KERNEL);
+ if (!coeffs)
+ return;
hantro_reg_write(vpu, &av1_apply_grain, 1);
@@ -1316,10 +553,10 @@ static void rockchip_vpu981_av1_dec_set_fgs(struct hantro_ctx *ctx)
hantro_reg_write(vpu, &av1_chroma_scaling_from_luma, scaling_from_luma);
hantro_reg_write(vpu, &av1_random_seed, film_grain->grain_seed);
- rockchip_vpu981_av1_dec_init_scaling_function(film_grain->point_y_value,
- film_grain->point_y_scaling,
- film_grain->num_y_points,
- fgmem->scaling_lut_y);
+ hantro_av1_init_scaling_function(film_grain->point_y_value,
+ film_grain->point_y_scaling,
+ film_grain->num_y_points,
+ fgmem->scaling_lut_y);
if (film_grain->flags &
V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA) {
@@ -1328,19 +565,19 @@ static void rockchip_vpu981_av1_dec_set_fgs(struct hantro_ctx *ctx)
memcpy(fgmem->scaling_lut_cr, fgmem->scaling_lut_y,
sizeof(*fgmem->scaling_lut_y) * 256);
} else {
- rockchip_vpu981_av1_dec_init_scaling_function
+ hantro_av1_init_scaling_function
(film_grain->point_cb_value, film_grain->point_cb_scaling,
film_grain->num_cb_points, fgmem->scaling_lut_cb);
- rockchip_vpu981_av1_dec_init_scaling_function
+ hantro_av1_init_scaling_function
(film_grain->point_cr_value, film_grain->point_cr_scaling,
film_grain->num_cr_points, fgmem->scaling_lut_cr);
}
for (i = 0; i < V4L2_AV1_AR_COEFFS_SIZE; i++) {
if (i < 24)
- (*ar_coeffs_y)[i] = film_grain->ar_coeffs_y_plus_128[i] - 128;
- (*ar_coeffs_cb)[i] = film_grain->ar_coeffs_cb_plus_128[i] - 128;
- (*ar_coeffs_cr)[i] = film_grain->ar_coeffs_cr_plus_128[i] - 128;
+ coeffs->ar_coeffs_y[i] = film_grain->ar_coeffs_y_plus_128[i] - 128;
+ coeffs->ar_coeffs_cb[i] = film_grain->ar_coeffs_cb_plus_128[i] - 128;
+ coeffs->ar_coeffs_cr[i] = film_grain->ar_coeffs_cr_plus_128[i] - 128;
}
ar_coeff_lag = film_grain->ar_coeff_lag;
@@ -1351,46 +588,38 @@ static void rockchip_vpu981_av1_dec_set_fgs(struct hantro_ctx *ctx)
grain_min = 0 - grain_center;
grain_max = (256 << (bitdepth - 8)) - 1 - grain_center;
- rockchip_av1_generate_luma_grain_block(luma_grain_block, bitdepth,
- film_grain->num_y_points, grain_scale_shift,
- ar_coeff_lag, ar_coeffs_y, ar_coeff_shift,
- grain_min, grain_max, film_grain->grain_seed);
-
- rockchip_av1_generate_chroma_grain_block(luma_grain_block, cb_grain_block,
- cr_grain_block, bitdepth,
- film_grain->num_y_points,
- film_grain->num_cb_points,
- film_grain->num_cr_points,
- grain_scale_shift, ar_coeff_lag, ar_coeffs_cb,
- ar_coeffs_cr, ar_coeff_shift, grain_min,
- grain_max,
- scaling_from_luma,
- film_grain->grain_seed);
+ hantro_av1_generate_luma_grain_block(coeffs, bitdepth,
+ film_grain->num_y_points, grain_scale_shift,
+ ar_coeff_lag, ar_coeff_shift,
+ grain_min, grain_max, film_grain->grain_seed);
+
+ hantro_av1_generate_chroma_grain_block(coeffs, bitdepth,
+ film_grain->num_y_points,
+ film_grain->num_cb_points,
+ film_grain->num_cr_points,
+ grain_scale_shift, ar_coeff_lag,
+ ar_coeff_shift, grain_min,
+ grain_max,
+ scaling_from_luma,
+ film_grain->grain_seed);
for (i = 0; i < 64; i++) {
for (j = 0; j < 64; j++)
fgmem->cropped_luma_grain_block[i * 64 + j] =
- (*luma_grain_block)[i + 9][j + 9];
+ coeffs->luma_grain_block[i + 9][j + 9];
}
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
fgmem->cropped_chroma_grain_block[i * 64 + 2 * j] =
- (*cb_grain_block)[i + 6][j + 6];
+ coeffs->cb_grain_block[i + 6][j + 6];
fgmem->cropped_chroma_grain_block[i * 64 + 2 * j + 1] =
- (*cr_grain_block)[i + 6][j + 6];
+ coeffs->cr_grain_block[i + 6][j + 6];
}
}
+ kfree(coeffs);
hantro_write_addr(vpu, AV1_FILM_GRAIN, av1_dec->film_grain.dma);
-
-alloc_fail:
- kfree(ar_coeffs_y);
- kfree(ar_coeffs_cb);
- kfree(ar_coeffs_cr);
- kfree(luma_grain_block);
- kfree(cb_grain_block);
- kfree(cr_grain_block);
}
static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
@@ -1617,13 +846,13 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
int ref_ind = 0;
int rf, idx;
- alt_frame_offset = rockchip_vpu981_get_order_hint(ctx, ALT_BUF_IDX);
- gld_frame_offset = rockchip_vpu981_get_order_hint(ctx, GLD_BUF_IDX);
- bwd_frame_offset = rockchip_vpu981_get_order_hint(ctx, BWD_BUF_IDX);
- alt2_frame_offset = rockchip_vpu981_get_order_hint(ctx, ALT2_BUF_IDX);
+ alt_frame_offset = hantro_av1_get_order_hint(ctx, ALT_BUF_IDX);
+ gld_frame_offset = hantro_av1_get_order_hint(ctx, GLD_BUF_IDX);
+ bwd_frame_offset = hantro_av1_get_order_hint(ctx, BWD_BUF_IDX);
+ alt2_frame_offset = hantro_av1_get_order_hint(ctx, ALT2_BUF_IDX);
- idx = rockchip_vpu981_get_frame_index(ctx, LST_BUF_IDX);
- if (idx >= 0) {
+ idx = hantro_av1_get_frame_index(ctx, LST_BUF_IDX);
+ if (idx != AV1_INVALID_IDX) {
int alt_frame_offset_in_lst =
av1_dec->frame_refs[idx].order_hints[V4L2_AV1_REF_ALTREF_FRAME];
bool is_lst_overlay =
@@ -1644,8 +873,9 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
ref_stamp--;
}
- idx = rockchip_vpu981_get_frame_index(ctx, BWD_BUF_IDX);
- if (rockchip_vpu981_av1_dec_get_dist(ctx, bwd_frame_offset, cur_frame_offset) > 0) {
+ idx = hantro_av1_get_frame_index(ctx, BWD_BUF_IDX);
+ if (idx != AV1_INVALID_IDX &&
+ hantro_av1_get_dist(ctx, bwd_frame_offset, cur_frame_offset) > 0) {
int bwd_mi_cols = av1_dec->frame_refs[idx].mi_cols;
int bwd_mi_rows = av1_dec->frame_refs[idx].mi_rows;
bool bwd_intra_only =
@@ -1659,8 +889,9 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
}
}
- idx = rockchip_vpu981_get_frame_index(ctx, ALT2_BUF_IDX);
- if (rockchip_vpu981_av1_dec_get_dist(ctx, alt2_frame_offset, cur_frame_offset) > 0) {
+ idx = hantro_av1_get_frame_index(ctx, ALT2_BUF_IDX);
+ if (idx != AV1_INVALID_IDX &&
+ hantro_av1_get_dist(ctx, alt2_frame_offset, cur_frame_offset) > 0) {
int alt2_mi_cols = av1_dec->frame_refs[idx].mi_cols;
int alt2_mi_rows = av1_dec->frame_refs[idx].mi_rows;
bool alt2_intra_only =
@@ -1674,8 +905,9 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
}
}
- idx = rockchip_vpu981_get_frame_index(ctx, ALT_BUF_IDX);
- if (rockchip_vpu981_av1_dec_get_dist(ctx, alt_frame_offset, cur_frame_offset) > 0 &&
+ idx = hantro_av1_get_frame_index(ctx, ALT_BUF_IDX);
+ if (idx != AV1_INVALID_IDX &&
+ hantro_av1_get_dist(ctx, alt_frame_offset, cur_frame_offset) > 0 &&
ref_stamp >= 0) {
int alt_mi_cols = av1_dec->frame_refs[idx].mi_cols;
int alt_mi_rows = av1_dec->frame_refs[idx].mi_rows;
@@ -1690,8 +922,8 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
}
}
- idx = rockchip_vpu981_get_frame_index(ctx, LST2_BUF_IDX);
- if (idx >= 0 && ref_stamp >= 0) {
+ idx = hantro_av1_get_frame_index(ctx, LST2_BUF_IDX);
+ if (idx != AV1_INVALID_IDX && ref_stamp >= 0) {
int lst2_mi_cols = av1_dec->frame_refs[idx].mi_cols;
int lst2_mi_rows = av1_dec->frame_refs[idx].mi_rows;
bool lst2_intra_only =
@@ -1706,14 +938,14 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
}
for (rf = 0; rf < V4L2_AV1_TOTAL_REFS_PER_FRAME - 1; ++rf) {
- idx = rockchip_vpu981_get_frame_index(ctx, rf);
- if (idx >= 0) {
- int rf_order_hint = rockchip_vpu981_get_order_hint(ctx, rf);
+ idx = hantro_av1_get_frame_index(ctx, rf);
+ if (idx != AV1_INVALID_IDX) {
+ int rf_order_hint = hantro_av1_get_order_hint(ctx, rf);
cur_offset[rf] =
- rockchip_vpu981_av1_dec_get_dist(ctx, cur_frame_offset, rf_order_hint);
+ hantro_av1_get_dist(ctx, cur_frame_offset, rf_order_hint);
cur_roffset[rf] =
- rockchip_vpu981_av1_dec_get_dist(ctx, rf_order_hint, cur_frame_offset);
+ hantro_av1_get_dist(ctx, rf_order_hint, cur_frame_offset);
} else {
cur_offset[rf] = 0;
cur_roffset[rf] = 0;
@@ -1736,35 +968,41 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
if (use_ref_frame_mvs && ref_ind > 0 &&
cur_offset[mf_types[0] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
cur_offset[mf_types[0] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
- int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[0]);
- int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[0]);
- u32 *oh = av1_dec->frame_refs[idx].order_hints;
+ int rf = hantro_av1_get_order_hint(ctx, refs_selected[0]);
+ int idx = hantro_av1_get_frame_index(ctx, refs_selected[0]);
+ u32 *oh;
int val;
+ if (idx == AV1_INVALID_IDX)
+ goto second_ref;
+
+ oh = av1_dec->frame_refs[idx].order_hints;
+
hantro_reg_write(vpu, &av1_use_temporal0_mvs, 1);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
hantro_reg_write(vpu, &av1_mf1_last_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
hantro_reg_write(vpu, &av1_mf1_last2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
hantro_reg_write(vpu, &av1_mf1_last3_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
hantro_reg_write(vpu, &av1_mf1_golden_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
hantro_reg_write(vpu, &av1_mf1_bwdref_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
hantro_reg_write(vpu, &av1_mf1_altref2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
hantro_reg_write(vpu, &av1_mf1_altref_offset, val);
}
+second_ref:
hantro_reg_write(vpu, &av1_mf2_last_offset, 0);
hantro_reg_write(vpu, &av1_mf2_last2_offset, 0);
hantro_reg_write(vpu, &av1_mf2_last3_offset, 0);
@@ -1776,35 +1014,41 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
if (use_ref_frame_mvs && ref_ind > 1 &&
cur_offset[mf_types[1] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
cur_offset[mf_types[1] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
- int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[1]);
- int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[1]);
- u32 *oh = av1_dec->frame_refs[idx].order_hints;
+ int rf = hantro_av1_get_order_hint(ctx, refs_selected[1]);
+ int idx = hantro_av1_get_frame_index(ctx, refs_selected[1]);
+ u32 *oh;
int val;
+ if (idx == AV1_INVALID_IDX)
+ goto third_ref;
+
+ oh = av1_dec->frame_refs[idx].order_hints;
+
hantro_reg_write(vpu, &av1_use_temporal1_mvs, 1);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
hantro_reg_write(vpu, &av1_mf2_last_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
hantro_reg_write(vpu, &av1_mf2_last2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
hantro_reg_write(vpu, &av1_mf2_last3_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
hantro_reg_write(vpu, &av1_mf2_golden_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
hantro_reg_write(vpu, &av1_mf2_bwdref_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
hantro_reg_write(vpu, &av1_mf2_altref2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
hantro_reg_write(vpu, &av1_mf2_altref_offset, val);
}
+third_ref:
hantro_reg_write(vpu, &av1_mf3_last_offset, 0);
hantro_reg_write(vpu, &av1_mf3_last2_offset, 0);
hantro_reg_write(vpu, &av1_mf3_last3_offset, 0);
@@ -1816,35 +1060,41 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
if (use_ref_frame_mvs && ref_ind > 2 &&
cur_offset[mf_types[2] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
cur_offset[mf_types[2] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
- int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[2]);
- int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[2]);
- u32 *oh = av1_dec->frame_refs[idx].order_hints;
+ int rf = hantro_av1_get_order_hint(ctx, refs_selected[2]);
+ int idx = hantro_av1_get_frame_index(ctx, refs_selected[2]);
+ u32 *oh;
int val;
+ if (idx == AV1_INVALID_IDX)
+ goto offsets;
+
+ oh = av1_dec->frame_refs[idx].order_hints;
+
hantro_reg_write(vpu, &av1_use_temporal2_mvs, 1);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
hantro_reg_write(vpu, &av1_mf3_last_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
hantro_reg_write(vpu, &av1_mf3_last2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
hantro_reg_write(vpu, &av1_mf3_last3_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
hantro_reg_write(vpu, &av1_mf3_golden_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
hantro_reg_write(vpu, &av1_mf3_bwdref_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
hantro_reg_write(vpu, &av1_mf3_altref2_offset, val);
- val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
+ val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
hantro_reg_write(vpu, &av1_mf3_altref_offset, val);
}
+offsets:
hantro_reg_write(vpu, &av1_cur_last_offset, cur_offset[0]);
hantro_reg_write(vpu, &av1_cur_last2_offset, cur_offset[1]);
hantro_reg_write(vpu, &av1_cur_last3_offset, cur_offset[2]);
@@ -1883,9 +1133,9 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
if (!allow_intrabc) {
for (i = 0; i < V4L2_AV1_REFS_PER_FRAME; i++) {
- int idx = rockchip_vpu981_get_frame_index(ctx, i);
+ int idx = hantro_av1_get_frame_index(ctx, i);
- if (idx >= 0)
+ if (idx != AV1_INVALID_IDX)
ref_count[idx]++;
}
@@ -1898,7 +1148,7 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
}
hantro_reg_write(vpu, &av1_ref_frames, ref_frames);
- rockchip_vpu981_av1_dec_set_frame_sign_bias(ctx);
+ hantro_av1_set_frame_sign_bias(ctx);
for (i = V4L2_AV1_REF_LAST_FRAME; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++) {
u32 ref = i - 1;
@@ -1910,8 +1160,8 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
width = frame->frame_width_minus_1 + 1;
height = frame->frame_height_minus_1 + 1;
} else {
- if (rockchip_vpu981_get_frame_index(ctx, ref) > 0)
- idx = rockchip_vpu981_get_frame_index(ctx, ref);
+ if (hantro_av1_get_frame_index(ctx, ref) != AV1_INVALID_IDX)
+ idx = hantro_av1_get_frame_index(ctx, ref);
width = av1_dec->frame_refs[idx].width;
height = av1_dec->frame_refs[idx].height;
}
@@ -1943,20 +1193,6 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
rockchip_vpu981_av1_dec_set_other_frames(ctx);
}
-static int rockchip_vpu981_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode)
-{
- switch (tx_mode) {
- case V4L2_AV1_TX_MODE_ONLY_4X4:
- return ROCKCHIP_AV1_TX_MODE_ONLY_4X4;
- case V4L2_AV1_TX_MODE_LARGEST:
- return ROCKCHIP_AV1_TX_MODE_32x32;
- case V4L2_AV1_TX_MODE_SELECT:
- return ROCKCHIP_AV1_TX_MODE_SELECT;
- }
-
- return ROCKCHIP_AV1_TX_MODE_32x32;
-}
-
static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
@@ -2029,7 +1265,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
hantro_reg_write(vpu, &av1_comp_pred_mode,
(ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
- tx_mode = rockchip_vpu981_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
+ tx_mode = hantro_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
hantro_reg_write(vpu, &av1_transform_mode, tx_mode);
hantro_reg_write(vpu, &av1_max_cb_size,
(ctrls->sequence->flags
@@ -2061,7 +1297,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
hantro_reg_write(vpu, &av1_qmlevel_v, 0xff);
}
- hantro_reg_write(vpu, &av1_lossless_e, rockchip_vpu981_av1_dec_is_lossless(ctx));
+ hantro_reg_write(vpu, &av1_lossless_e, hantro_av1_is_lossless(ctx));
hantro_reg_write(vpu, &av1_quant_delta_v_dc, ctrls->frame->quantization.delta_q_v_dc);
hantro_reg_write(vpu, &av1_quant_delta_v_ac, ctrls->frame->quantization.delta_q_v_ac);
@@ -2109,8 +1345,8 @@ rockchip_vpu981_av1_dec_set_output_buffer(struct hantro_ctx *ctx)
struct hantro_decoded_buffer *dst;
struct vb2_v4l2_buffer *vb2_dst;
dma_addr_t luma_addr, chroma_addr, mv_addr = 0;
- size_t cr_offset = rockchip_vpu981_av1_dec_luma_size(ctx);
- size_t mv_offset = rockchip_vpu981_av1_dec_chroma_size(ctx);
+ size_t cr_offset = hantro_av1_luma_size(ctx);
+ size_t mv_offset = hantro_av1_chroma_size(ctx);
vb2_dst = av1_dec->frame_refs[av1_dec->current_frame_index].vb2_ref;
dst = vb2_to_hantro_decoded_buf(&vb2_dst->vb2_buf);
@@ -2134,7 +1370,7 @@ int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx)
hantro_start_prepare_run(ctx);
- ret = rockchip_vpu981_av1_dec_prepare_run(ctx);
+ ret = hantro_av1_prepare_run(ctx);
if (ret)
goto prepare_error;
@@ -2144,8 +1380,8 @@ int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx)
goto prepare_error;
}
- rockchip_vpu981_av1_dec_clean_refs(ctx);
- rockchip_vpu981_av1_dec_frame_ref(ctx, vb2_src->vb2_buf.timestamp);
+ hantro_av1_clean_refs(ctx);
+ hantro_av1_frame_ref(ctx, vb2_src->vb2_buf.timestamp);
rockchip_vpu981_av1_dec_set_parameters(ctx);
rockchip_vpu981_av1_dec_set_global_model(ctx);
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 02673be9878e..f50a3e38097e 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include "hantro.h"
+#include "hantro_av1.h"
#include "hantro_jpeg.h"
#include "hantro_g1_regs.h"
#include "hantro_h1_regs.h"
@@ -608,9 +609,9 @@ static const struct hantro_codec_ops rk3568_vepu_codec_ops[] = {
static const struct hantro_codec_ops rk3588_vpu981_codec_ops[] = {
[HANTRO_MODE_AV1_DEC] = {
.run = rockchip_vpu981_av1_dec_run,
- .init = rockchip_vpu981_av1_dec_init,
- .exit = rockchip_vpu981_av1_dec_exit,
- .done = rockchip_vpu981_av1_dec_done,
+ .init = hantro_av1_init,
+ .exit = hantro_av1_exit,
+ .done = hantro_av1_update_prob,
},
};
/*
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v4 2/2] drm/mediatek: dsi: Add compatible for mt8167-dsi
From: CK Hu (胡俊光) @ 2026-05-12 9:26 UTC (permalink / raw)
To: linux-mediatek@lists.infradead.org, l.scorcia@gmail.com
Cc: dri-devel@lists.freedesktop.org, chunkuang.hu@kernel.org,
simona@ffwll.ch, AngeloGioacchino Del Regno, robh@kernel.org,
airlied@gmail.com, krzk+dt@kernel.org,
linux-arm-kernel@lists.infradead.org, p.zabel@pengutronix.de,
conor+dt@kernel.org, matthias.bgg@gmail.com,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <20260505214541.333657-3-l.scorcia@gmail.com>
On Tue, 2026-05-05 at 22:45 +0100, Luca Leonardo Scorcia wrote:
> External email : Please do not click links or open attachments until you have verified the sender or the content.
>
>
> The mt8167 DSI controller is fully compatible with the one found in
> mt2701. Unfortunately the device tree has a dedicated compatible for
> mt8167 since 2022 and it cannot be changed with a fallback nor removed at
> this point. The only way to get the device to work is to add the
> compatible to the driver.
Reviewed-by: CK Hu <ck.hu@mediatek.com>
>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> ---
> drivers/gpu/drm/mediatek/mtk_dsi.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 5aa71fcdcfab..167e33fef025 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -1305,6 +1305,7 @@ static const struct mtk_dsi_driver_data mt8188_dsi_driver_data = {
>
> static const struct of_device_id mtk_dsi_of_match[] = {
> { .compatible = "mediatek,mt2701-dsi", .data = &mt2701_dsi_driver_data },
> + { .compatible = "mediatek,mt8167-dsi", .data = &mt2701_dsi_driver_data },
> { .compatible = "mediatek,mt8173-dsi", .data = &mt8173_dsi_driver_data },
> { .compatible = "mediatek,mt8183-dsi", .data = &mt8183_dsi_driver_data },
> { .compatible = "mediatek,mt8186-dsi", .data = &mt8186_dsi_driver_data },
> --
> 2.43.0
>
>
^ permalink raw reply
* [PATCH] arm64: dts: rockchip: fix emmc reset polarity on px30-cobra
From: Jakob Unterwurzacher @ 2026-05-12 9:22 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Quentin Schulz, Jakob Unterwurzacher
Cc: stable, Heiko Stuebner, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel
Technically, the reset signal is active low - it's called RST_n after all.
But it is ignored completely unless RST_n_FUNCTION=1 (byte 162 in extcsd)
is set in the emmc. It is 0 per default.
For emmcs that have RST_n_FUNCTION=1 we failed like this:
[ 3.074480] mmc1: Failed to initialize a non-removable card
With this change they work normally.
Cc: stable@vger.kernel.org
Fixes: bb510ddc9d3e ("arm64: dts: rockchip: add px30-cobra base dtsi and board variants")
Signed-off-by: Jakob Unterwurzacher <jakob.unterwurzacher@cherry.de>
---
arch/arm64/boot/dts/rockchip/px30-cobra.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
index b7e669d8ba4d..90751b04f95c 100644
--- a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
@@ -35,7 +35,7 @@ emmc_pwrseq: emmc-pwrseq {
compatible = "mmc-pwrseq-emmc";
pinctrl-0 = <&emmc_reset>;
pinctrl-names = "default";
- reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
};
gpio-leds {
--
2.47.3
^ permalink raw reply related
* Re: [PATCH 3/4] remoteproc: add helper for optional ELF resource tables
From: Arnaud POULIQUEN @ 2026-05-12 9:22 UTC (permalink / raw)
To: Daniel Baluta, Ben Levinsky, Bjorn Andersson, Mathieu Poirier,
linux-remoteproc
Cc: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Geert Uytterhoeven, Magnus Damm, Patrice Chotard, Maxime Coquelin,
Alexandre Torgue, imx, linux-arm-kernel, linux-kernel,
linux-renesas-soc, linux-stm32, tanmay.shah
In-Reply-To: <3b7f009c-dc4b-4fc0-becc-4d07eb4ff016@oss.nxp.com>
On 5/12/26 09:55, Daniel Baluta wrote:
> On 5/12/26 00:18, Ben Levinsky wrote:
>> [You don't often get email from ben.levinsky@amd.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>
>> Add a small helper around rproc_elf_load_rsc_table() for remoteproc
>> drivers that treat a missing ELF resource table as optional. The helper
>> returns success on -EINVAL and propagates other failures unchanged.
>>
>> Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
>> ---
>> drivers/remoteproc/remoteproc_internal.h | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
>> index 3724a47a9748..dff87e468837 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -146,6 +146,18 @@ static inline int rproc_mem_entry_iounmap(struct rproc *rproc,
>> return 0;
>> }
>>
>> +static inline int rproc_elf_load_rsc_table_optional(struct rproc *rproc,
>> + const struct firmware *fw)
>> +{
>> + int ret;
>> +
>> + ret = rproc_elf_load_rsc_table(rproc, fw);
>> + if (ret == -EINVAL)
>> + dev_dbg(&rproc->dev, "no resource table found\n");
>
> You are changing loglevel here. Initial drivers use dev_info or dev_warn. At least I'm used
> with seeing this messages in the logs.
>
> So, what do you think on adding at least dev_info to this instead of dev_dbg?
+1 for dev_info (dev_warn is used in stm32_rproc_parse_fw(), but ok to
move to dev_info)
Regards,
Arnaud
>
>> +
>> + return ret == -EINVAL ? 0 : ret;
>> +}
>> +
>> static inline int rproc_prepare_device(struct rproc *rproc)
>> {
>> if (rproc->ops->prepare)
>> --
>> 2.34.1
>>
>>
>
>
^ permalink raw reply
* Re: [PATCH v3 1/5] arm_mpam: resctrl: Pick classes for use as mbm counters
From: Ben Horgan @ 2026-05-12 9:21 UTC (permalink / raw)
To: Shaopeng Tan (Fujitsu)
Cc: amitsinght@marvell.com, baisheng.gao@unisoc.com,
baolin.wang@linux.alibaba.com, carl@os.amperecomputing.com,
dave.martin@arm.com, david@kernel.org, dfustini@baylibre.com,
fenghuay@nvidia.com, gshan@redhat.com, james.morse@arm.com,
jonathan.cameron@huawei.com, kobak@nvidia.com,
lcherian@marvell.com, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, peternewman@google.com,
punit.agrawal@oss.qualcomm.com, quic_jiles@quicinc.com,
reinette.chatre@intel.com, rohit.mathew@arm.com,
scott@os.amperecomputing.com, sdonthineni@nvidia.com,
xhao@linux.alibaba.com, zengheng4@huawei.com, x86@kernel.org
In-Reply-To: <TY4PR01MB1693044EDBBF023317F9059A98B392@TY4PR01MB16930.jpnprd01.prod.outlook.com>
Hi Shaopeng,
On 5/12/26 07:50, Shaopeng Tan (Fujitsu) wrote:
> Hello Ben,
>
>> From: James Morse <james.morse@arm.com>
>>
>> resctrl has two types of counters, NUMA-local and global. MPAM can only
>> count global either using MSC at the L3 cache or in the memory controllers.
>> When global and local equate to the same thing continue just to call it
>> global.
>>
>> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
>> Tested-by: Zeng Heng <zengheng4@huawei.com>
>> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
>> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
>> Signed-off-by: James Morse <james.morse@arm.com>
>> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
>> ---
>> Changes since rfc v1:
>> Move finding any_mon_comp into monitor boilerplate patch
>> Move mpam_resctrl_get_domain_from_cpu() into monitor boilerplate
>> Remove free running check
>> Trim commit message
>> ---
>> drivers/resctrl/mpam_resctrl.c | 26 ++++++++++++++++++++++++++
>> 1 file changed, 26 insertions(+)
>>
>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>> index 226ff6f532fa..f70fa65d39e4 100644
>> --- a/drivers/resctrl/mpam_resctrl.c
>> +++ b/drivers/resctrl/mpam_resctrl.c
>> @@ -606,6 +606,16 @@ static bool cache_has_usable_csu(struct mpam_class *class)
>> return true;
>> }
>>
>> +static bool class_has_usable_mbwu(struct mpam_class *class)
>> +{
>> + struct mpam_props *cprops = &class->props;
>> +
>> + if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
>> + return false;
>> +
>> + return true;
>> +}
>> +
>> /*
>> * Calculate the worst-case percentage change from each implemented step
>> * in the control.
>> @@ -983,6 +993,22 @@ static void mpam_resctrl_pick_counters(void)
>> break;
>> }
>> }
>> +
>> + if (class_has_usable_mbwu(class) &&
>> + topology_matches_l3(class) &&
>> + traffic_matches_l3(class)) {
>> + pr_debug("class %u has usable MBWU, and matches L3 topology and traffic\n",
>> + class->level);
>> +
>> + /*
>> + * We can't distinguish traffic by destination so
>> + * we don't know if it's staying on the same NUMA
>> + * node. Hence, we can't calculate mbm_local except
>> + * when we only have one L3 and it's equivalent to
>> + * mbm_total and so always use mbm_total.
>> + */
>> + counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID, class);
>> + }
>> }
>> }
>>
>> --
>> 2.43.0
>
> https://lore.kernel.org/lkml/599617aa-aade-4fde-9efa-79d592f1ff3f@arm.com/
>
> This concerns the comment I received last time.
> I may not have fully understood it, so I'd like to clarify it once more.
I'll try and explain better.
>
> Even if the system as a whole has multiple L3 caches and multiple NUMA nodes,
> ABMC will be enabled as long as there is a single L3 cache and a single corresponding NUMA node.
> Is my understanding correct?
> If my understanding is correct, within the 'traffic_matches_l3()' function,
> ABMC is enabled only when the entire system has a single NUMA node and a single L3 cache.
These restrictions only apply when the MSC containing the bandwidth counters is
at the memory, as advertised by ACPI. When the counters are on the L3 cache
there can be multiple L3 and multiple NUMA nodes and a domain with AMBC memory
bandwidth counters will be exposed for each instance of the L3 cache.
As resctrl, currently, expects all monitors to be on the L3 cache we can only
use counters if they can be considered to be at the L3. The user just sees an
L3_MON directory. When the monitors/counters are at the memory we can only
pretend they are at the L3 when there is a single L3 and a single NUMA node.
This is because the topology needs to match, the same cpus are affine to the L3
instance and corresponding NUMA instance and the traffic measured also needs to
match. If there is multiple NUMA and L3 then cross NUMA traffic means that the
traffic seen at the NUMA node is different from what is seen at the L3.
If a workload runs on cpus affine to the L3, instance A, but allows cross NUMA
traffic then the memory bandwidth leaving the L3, instance A, will be different
from that entering NUMA instance A.
L3_A --> NUMA_A
\
\
🡖
L3_B NUMA_B
This is still the case if the traffic goes via the L3 to the other NUMA node.
L3_A --> NUMA_A
|
|
⌄
L3_B --> NUMA_B
The future plan, is to add support for monitoring scoped to the NUMA node in
resctrl. This means we can we can more accurately expose the counters later on
without being held back by inaccurate descriptions. Ideally, we would have added
proper support for monitors at the memory scoped by NUMA node rather than adding
traffic_matches_l3() and topology_matches_l3(), which are there to allow us to
support platforms where the traffic entering the memory controller is the same
as that leaving the L3. To cope with the case when memory is powered down we
need to introduce memory hotplug locking to resctrl as well as the support for
understanding the NUMA scope.
>
> 870 static bool traffic_matches_l3(struct mpam_class *class)
> 871 {
> ...
> 901
> 902 if (!cpumask_equal(tmp_cpumask, cpu_possible_mask)) {
> 903 pr_debug("There is more than one L3\n");
> 904 return false; *
> 905 }
> ...
> 912
> 913 if (num_possible_nodes() > 1) {
> 914 pr_debug("There is more than one numa node\n");
> 915 return false; *
> 916 }
> 917
> ...
> 926 }
>
>
> Also, I'd also like to confirm one more thing.
> The mpam_resctrl_pick_mba() function also calls traffic_matches_l3().
> This suggests that, except in scenarios where the entire system has a single L3 cache and a single NUMA node (ABMC is disabled),
> the Memory Bandwidth allocation will also be disabled.
> Is this the intended behavior? If so, could you explain why?
Yes, but only when the memory allocation control, mbw_max, is on the memory
controller and not the L3 cache. There is no restriction when the MSC is on the
L3 cache. This is for the same reasons as for the memory bandwidth counters. The
traffic that we say is coming from the L3 may not be the same as that entering
the memory controller and resctrl assumes that the MBA is at the L3. Memory
hotplug locking in resctrl would also be needed here.
Reinete is creating a proof of concept for a structured way to add new schemata
into resctrl, some discussion of initial ideas [1]. I'm also looking to see how
the generic schemata ideas can fit with MPAM and what resctrl support we'd require.
Zeng has indicated [2] that he might look into adding the MB support at NUMA nodes.
I hope this makes things a bit clearer.
[1] https://lore.kernel.org/lkml/fb1e2686-237b-4536-acd6-15159abafcba@intel.com/
[2]
https://lore.kernel.org/linux-arm-kernel/f6f865bc-319c-8944-9989-4fd83a59d4b8@huawei.com/
Thanks,
Ben
>
> Best regards,
> Shaopeng TAN
>
>
>
>
^ permalink raw reply
* [PATCH v2] drm/bridge: imx93-mipi-dsi: Fix mode validation
From: Liu Ying @ 2026-05-12 9:18 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Luca Ceresoli
Cc: Dmitry Baryshkov, dri-devel, imx, linux-arm-kernel, linux-kernel,
Liu Ying
i.MX93 MIPI DPHY PLL has limitation for matching with some pixel clock
rates, e.g., the best DPHY PLL frequency is 445.333333MHz for a typical
1920x1080p@60Hz CEA/DMT display modes with a pixel clock rate running
at 148.5MHz with 4 data lanes + RGB888 pixel in MIPI DSI sync pulse mode,
while the expected PLL frequency is (148.5 * 24) / 4 / 2 MHz = 445.5MHz.
Fortunately, VESA Display Monitor Timing Standard allows +/-0.5% pixel
clock rate deviation for timings. So, for those display modes read
from EDID through a bridge with DRM_BRIDGE_OP_DETECT and DRM_BRIDGE_OP_EDID
operation bit masks set, pixel clock rate could be adjusted to match
with the PLL frequency(for the above example, the pixel clock rate is
adjusted to be 148.444444MHz with about -0.03% deviation from the 148.5MHz
nominal rate so that the adjusted rate matches with the 445.333333MHz PLL
frequency).
Instead of checking the last bridge's operation bit masks against
DRM_BRIDGE_OP_DETECT and DRM_BRIDGE_OP_EDID to determine if allowing
+/-0.5% pixel clock rate deviation, check any bridge after this bridge,
because the last bridge is usually a display connector bridge without
any operation bit mask when the clock rate deviation is allowed.
Fixes: ce62f8ea7e3f ("drm/bridge: imx: Add i.MX93 MIPI DSI support")
Fixes: 5849eff7f067 ("drm/bridge: imx93-mipi-dsi: use drm_bridge_chain_get_last_bridge()")
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Liu Ying <victor.liu@nxp.com>
---
Changes in v2:
- Collect Frank's R-b tag.
- Add an explanation to commit message about the reason why mode validation
checks bridge's operation bit masks. (Dmitry)
- Copy Dmitry.
- Link to v1: https://lore.kernel.org/r/20260227-imx93-mipi-dsi-fix-mode-validation-v1-1-a9cd67991280@nxp.com
To: Liu Ying <victor.liu@nxp.com>
To: Andrzej Hajda <andrzej.hajda@intel.com>
To: Neil Armstrong <neil.armstrong@linaro.org>
To: Robert Foss <rfoss@kernel.org>
To: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
To: Jonas Karlman <jonas@kwiboo.se>
To: Jernej Skrabec <jernej.skrabec@gmail.com>
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: Maxime Ripard <mripard@kernel.org>
To: Thomas Zimmermann <tzimmermann@suse.de>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
To: Frank Li <Frank.Li@nxp.com>
To: Sascha Hauer <s.hauer@pengutronix.de>
To: Pengutronix Kernel Team <kernel@pengutronix.de>
To: Fabio Estevam <festevam@gmail.com>
To: Luca Ceresoli <luca.ceresoli@bootlin.com>
Cc: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Cc: dri-devel@lists.freedesktop.org
Cc: imx@lists.linux.dev
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c
index 8f312f9edf97..6d65df9ed970 100644
--- a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c
@@ -493,21 +493,24 @@ static enum drm_mode_status
imx93_dsi_validate_mode(struct imx93_dsi *dsi, const struct drm_display_mode *mode)
{
struct drm_bridge *dmd_bridge = dw_mipi_dsi_get_bridge(dsi->dmd);
- struct drm_bridge *last_bridge __free(drm_bridge_put) =
- drm_bridge_chain_get_last_bridge(dmd_bridge->encoder);
- if ((last_bridge->ops & DRM_BRIDGE_OP_DETECT) &&
- (last_bridge->ops & DRM_BRIDGE_OP_EDID)) {
- unsigned long pixel_clock_rate = mode->clock * 1000;
- unsigned long rounded_rate;
+ drm_for_each_bridge_in_chain_from(dmd_bridge, bridge) {
+ if ((bridge->ops & DRM_BRIDGE_OP_DETECT) &&
+ (bridge->ops & DRM_BRIDGE_OP_EDID)) {
+ unsigned long pixel_clock_rate = mode->clock * 1000;
+ unsigned long rounded_rate;
- /* Allow +/-0.5% pixel clock rate deviation */
- rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate);
- if (rounded_rate < pixel_clock_rate * 995 / 1000 ||
- rounded_rate > pixel_clock_rate * 1005 / 1000) {
- dev_dbg(dsi->dev, "failed to round clock for mode " DRM_MODE_FMT "\n",
- DRM_MODE_ARG(mode));
- return MODE_NOCLOCK;
+ /* Allow +/-0.5% pixel clock rate deviation */
+ rounded_rate = clk_round_rate(dsi->clk_pixel, pixel_clock_rate);
+ if (rounded_rate < pixel_clock_rate * 995 / 1000 ||
+ rounded_rate > pixel_clock_rate * 1005 / 1000) {
+ dev_dbg(dsi->dev,
+ "failed to round clock for mode " DRM_MODE_FMT "\n",
+ DRM_MODE_ARG(mode));
+ return MODE_NOCLOCK;
+ }
+
+ break;
}
}
---
base-commit: 877552aa875839314afad7154b5a561889e87ea9
change-id: 20260227-imx93-mipi-dsi-fix-mode-validation-425c872a2493
Best regards,
--
Regards,
Liu Ying
^ permalink raw reply related
* Re: [PATCH 2/2] arm64: dts: mediatek: mt8188-geralt: enable Wi-Fi card
From: Chen-Yu Tsai @ 2026-05-12 9:10 UTC (permalink / raw)
To: Icenowy Zheng
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Hui Liu, linux-gpio,
devicetree, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <4a43edb8c7ae3f96f77272db89ec6450ffa28876.camel@iscas.ac.cn>
On Wed, May 6, 2026 at 10:14 PM Icenowy Zheng <zhengxingda@iscas.ac.cn> wrote:
>
> 在 2026-05-04一的 15:34 +0800,Chen-Yu Tsai写道:
> > Hi,
> >
> > On Mon, May 4, 2026 at 3:28 PM Icenowy Zheng
> > <zhengxingda@iscas.ac.cn> wrote:
> > >
> > > The mainline pcie-mediatek-gen3 driver does not have code managing
> > > downstream device power / reset.
> > >
> > > As the Wi-Fi card on ciri is a fixed device, set the related
> > > regulator
> > > to always-on and use GPIO hog to set the status of its reset pin.
> >
> > The plan now is to model it as an M.2 E-key slot (even though the
> > chip
> > is actually soldered on the main board).
>
> Interestingly I saw a "PCI_PWRCTRL_GENERIC" driver in 7.1, although it
> does not support toggling #PERST now -- maybe this should be done and
> used instead? (Well it looks like the driver had existed for some time,
> but it was for "slots" previously)
#PERST currently is still left to the PCI controller drivers, since some
of them have dedicated functions for it, while others use the GPIO API.
If you check the history of the "PCI pwrctrl framework" [1], you will
see the design choice.
[1] https://lore.kernel.org/all/20260115-pci-pwrctrl-rework-v5-0-9d26da3ce903@oss.qualcomm.com/
> Thanks,
> Icenowy
>
> >
> > I have some of the patches ready, but I'm still working out the USB
> > side of it.
> >
> >
> > ChenYu
> >
> > > Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
> > > ---
> > > arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi | 11 +++++++++++
> > > 1 file changed, 11 insertions(+)
> > >
> > > diff --git a/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
> > > b/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
> > > index 8e423504ec052..c25780098103b 100644
> > > --- a/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
> > > +++ b/arch/arm64/boot/dts/mediatek/mt8188-geralt.dtsi
> > > @@ -544,6 +544,11 @@ &mt6359codec {
> > > mediatek,mic-type-2 = <2>; /* DMIC */
> > > };
> > >
> > > +&mt6359_vcn18_ldo_reg {
> > > + /* Used by WLAN */
> > > + regulator-always-on;
> > > +};
> > > +
> > > &mt6359_vcore_buck_reg {
> > > regulator-always-on;
> > > };
> > > @@ -1145,6 +1150,12 @@ pins-en-pp3300-wlan {
> > > output-low;
> > > };
> > > };
> > > +
> > > + wlan-reset-hog {
> > > + gpio-hog;
> > > + gpios = <145 GPIO_ACTIVE_HIGH>;
> > > + output-high;
> > > + };
> > > };
> > >
> > > &pmic {
> > > --
> > > 2.52.0
> > >
> > >
>
^ permalink raw reply
* Re: [PATCH 2/2] drm/verisilicon: add support for Nuvoton MA35D1 DCUltra Lite display controller
From: Joey Lu @ 2026-05-12 9:10 UTC (permalink / raw)
To: Thomas Zimmermann, zhengxingda, maarten.lankhorst, mripard,
airlied, simona, robh, krzk+dt, conor+dt
Cc: ychuang3, schung, yclu4, dri-devel, devicetree, linux-arm-kernel,
linux-kernel
In-Reply-To: <5157ab4d-3195-49f3-a3e9-aef6d58e869e@suse.de>
On 5/12/2026 4:24 PM, Thomas Zimmermann wrote:
> Hi,
>
> instead of this if-else branchery, I strongly recommend to add a new
> file with a new mode-setting pipeline for the new chipset. You can
> share existing helpers where possible, and implement variants where
> chips differ. It's a bit more code, but will be a lot easier to
> maintain in the future.
>
> See ast and mgag200 for example. Both drivers support various
> revisions of their chipset, where each rev has its oddities.
>
> Best regards
> Thomas
Thank you for the detailed suggestion.
I see your point and will refactor by adding a new file with a
mode-setting pipeline for the chipset, reusing helpers where possible
and handling variants as needed.
>
> Am 11.05.26 um 09:51 schrieb Joey Lu:
>> The Nuvoton MA35D1 SoC integrates a Verisilicon DCUltra Lite display
>> controller, which is a previous generation of the DC8000 series. While
>> the general register layout is similar to the DC8000, there are several
>> key differences that require per-variant handling in the driver.
>>
>> Add a vs_dc_info platform data structure (in vs_hwdb.h) to describe
>> per-IP-variant capabilities, and use it throughout the driver to select
>> the correct code paths at runtime.
>>
>> Key differences between DC8000 and DCUltra Lite handled:
>>
>> 1. No chip identity registers (0x0020-0x0030): DCUltra Lite uses static
>> platform data instead of reading model/revision/customer_id from HW.
>>
>> 2. No CONFIG_EX commit mechanism: DC8000 uses registers at 0x1CC0
>> (FB_CONFIG_EX), 0x24D8 (FB_TOP_LEFT), 0x24E0 (FB_BOTTOM_RIGHT),
>> 0x2510 (FB_BLEND_CONFIG), 0x2518 (PANEL_CONFIG_EX). DCUltra Lite
>> omits all of these and instead uses enable/reset bits in FB_CONFIG
>> (bit 0 = enable, bit 4 = reset) for direct framebuffer updates.
>>
>> 3. No PANEL_START register (0x1CCC): DCUltra Lite panel output starts
>> when PANEL_CONFIG.RUNNING is set; no separate multi-display sync
>> start register is needed.
>>
>> 4. Different IRQ registers: DCUltra Lite uses 0x147C (IRQ_STA) /
>> 0x1480 (IRQ_EN); DC8000 uses 0x0010 (IRQ_ACK) / 0x0014 (IRQ_EN).
>>
>> 5. Different clock/reset topology: DCUltra Lite requires only "core"
>> (bus gate) and "pix0" (pixel divider) clocks with no reset lines
>> managed by the driver. DC8000 needs core/axi/ahb clocks and three
>> resets.
>>
>> 6. Single output only: DCUltra Lite has one display output; per-output
>> index logic is still in place but display_count is fixed at 1.
>>
>> 7. Reduced register space: max_register is 0x2000 vs DC8000's 0x2544.
>>
>> Add the "nuvoton,ma35d1-dcu" compatible string to the OF match table,
>> extend Kconfig to allow building on ARCH_MA35 platforms, and expose
>> vs_formats_no_yuv444 as the default format table for DCUltra Lite
>> (YUV444 blending is a DC8000-only feature).
>>
>> All changes have been tested on Nuvoton MA35D1 hardware and are
>> functioning correctly.
>>
>> Signed-off-by: Joey Lu <a0987203069@gmail.com>
>> ---
>> drivers/gpu/drm/verisilicon/Kconfig | 2 +-
>> drivers/gpu/drm/verisilicon/vs_bridge.c | 28 ++--
>> drivers/gpu/drm/verisilicon/vs_crtc.c | 13 +-
>> drivers/gpu/drm/verisilicon/vs_dc.c | 129 ++++++++++++------
>> drivers/gpu/drm/verisilicon/vs_dc.h | 1 +
>> drivers/gpu/drm/verisilicon/vs_drm.c | 16 ++-
>> drivers/gpu/drm/verisilicon/vs_hwdb.c | 2 +-
>> drivers/gpu/drm/verisilicon/vs_hwdb.h | 25 ++++
>> .../gpu/drm/verisilicon/vs_primary_plane.c | 43 +++---
>> .../drm/verisilicon/vs_primary_plane_regs.h | 2 +
>> 10 files changed, 187 insertions(+), 74 deletions(-)
>>
>>
>
^ permalink raw reply
* [PATCH v4 13/13] x86/amd-gart: preserve the direct DMA address until GART mapping succeeds
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
gart_alloc_coherent() first allocates memory through dma_direct_alloc(),
which returns a direct-mapped DMA address in dma_addr. When force_iommu is
enabled, the buffer is then remapped.
Do not overwrite dma_addr before dma_map_area() has succeeded. Keep the
dma_map_area result in a temporary variable so the direct DMA address
remains available for dma_direct_free() on the error path.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/x86/kernel/amd_gart_64.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c
index b5f1f031d45b..a109649c5649 100644
--- a/arch/x86/kernel/amd_gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
@@ -467,18 +467,20 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr,
gfp_t flag, unsigned long attrs)
{
void *vaddr;
+ dma_addr_t dma_map_addr;
vaddr = dma_direct_alloc(dev, size, dma_addr, flag, attrs);
if (!vaddr ||
!force_iommu || dev->coherent_dma_mask <= DMA_BIT_MASK(24))
return vaddr;
- *dma_addr = dma_map_area(dev, virt_to_phys(vaddr), size,
- DMA_BIDIRECTIONAL,
- (1UL << get_order(size)) - 1, attrs);
+ dma_map_addr = dma_map_area(dev, virt_to_phys(vaddr), size,
+ DMA_BIDIRECTIONAL,
+ (1UL << get_order(size)) - 1, attrs);
flush_gart();
- if (unlikely(*dma_addr == DMA_MAPPING_ERROR))
+ if (unlikely(dma_map_addr == DMA_MAPPING_ERROR))
goto out_free;
+ *dma_addr = dma_map_addr;
return vaddr;
out_free:
dma_direct_free(dev, size, vaddr, *dma_addr, attrs);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 2/2] drm/verisilicon: add support for Nuvoton MA35D1 DCUltra Lite display controller
From: Joey Lu @ 2026-05-12 9:06 UTC (permalink / raw)
To: Icenowy Zheng, maarten.lankhorst, mripard, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt
Cc: ychuang3, schung, yclu4, dri-devel, devicetree, linux-arm-kernel,
linux-kernel
In-Reply-To: <3b94806073de8bd1d79aa7ec956493f67679e46b.camel@iscas.ac.cn>
On 5/12/2026 4:11 PM, Icenowy Zheng wrote:
> 在 2026-05-12二的 15:45 +0800,Joey Lu写道:
>> On 5/11/2026 5:47 PM, Icenowy Zheng wrote:
>>> 在 2026-05-11一的 15:51 +0800,Joey Lu写道:
>>>> The Nuvoton MA35D1 SoC integrates a Verisilicon DCUltra Lite
>>>> display
>>>> controller, which is a previous generation of the DC8000 series.
>>>> While
>>>> the general register layout is similar to the DC8000, there are
>>>> several
>>>> key differences that require per-variant handling in the driver.
>>>>
>>>> Add a vs_dc_info platform data structure (in vs_hwdb.h) to
>>>> describe
>>>> per-IP-variant capabilities, and use it throughout the driver to
>>>> select
>>>> the correct code paths at runtime.
>>>>
>>>> Key differences between DC8000 and DCUltra Lite handled:
>>> What the driver supports now is DC8200, DC8000 have the following
>>> point
>>> 1~4 the same with DCUltraLite (different to DC8200).
>> Understood. I'll rename all `vs_dc8000_*` identifiers to
>> `vs_dc8200_*` in v2. The commit message will also be corrected to say
>> that points 1~4 are differences from DC8200, not DC8000.
>>>> 1. No chip identity registers (0x0020-0x0030): DCUltra Lite uses
>>>> static
>>>> platform data instead of reading model/revision/customer_id
>>>> from
>>>> HW.
>>> My test shows that revision and customer_id is correctly present,
>>> only
>>> model is 0 -- I think this can be also considered as a valid model
>>> value because the IP name has also no model number.
>>>
>>> The revision number is 0x5560 and customer id is 0x305 .
>> Thank you for testing. I'll drop the `has_chip_id` flag
>> entirely. In v2, `vs_fill_chip_identity()` will be called for all
>> variants. A new entry will be added to `vs_chip_identities[]` in
>> vs_hwdb.c with model=0x0, revision=0x5560, customer_id=0x305,
>> display_count=1, and `vs_formats_no_yuv444`.
>> e.g. verisilicon-dc 40260000.display: Found DC0 rev 5560 customer 305
>>>> 2. No CONFIG_EX commit mechanism: DC8000 uses registers at 0x1CC0
>>>> (FB_CONFIG_EX), 0x24D8 (FB_TOP_LEFT), 0x24E0
>>>> (FB_BOTTOM_RIGHT),
>>>> 0x2510 (FB_BLEND_CONFIG), 0x2518 (PANEL_CONFIG_EX). DCUltra
>>>> Lite
>>>> omits all of these and instead uses enable/reset bits in
>>>> FB_CONFIG
>>>> (bit 0 = enable, bit 4 = reset) for direct framebuffer
>>>> updates.
>>>>
>>>> 3. No PANEL_START register (0x1CCC): DCUltra Lite panel output
>>>> starts
>>>> when PANEL_CONFIG.RUNNING is set; no separate multi-display
>>>> sync
>>>> start register is needed.
>>>>
>>>> 4. Different IRQ registers: DCUltra Lite uses 0x147C (IRQ_STA) /
>>>> 0x1480 (IRQ_EN); DC8000 uses 0x0010 (IRQ_ACK) / 0x0014
>>>> (IRQ_EN).
>>>>
>>>> 5. Different clock/reset topology: DCUltra Lite requires only
>>>> "core"
>>>> (bus gate) and "pix0" (pixel divider) clocks with no reset
>>>> lines
>>>> managed by the driver. DC8000 needs core/axi/ahb clocks and
>>>> three
>>>> resets.
>>> It's possible that your SoC integration combines core clock gate
>>> with
>>> bus clock gate instead of bus clock gate not existing.
>> Agreed. In v2 I'll remove the family-gated clock handling and
>> instead use `devm_clk_get_optional_enabled()` for the axi and ahb
>> clocks, so they are simply skipped if not present in DT. Resets are
>> already optional. This keeps the probe path uniform and handles any
>> SoC-specific clock combinations naturally.
> Maybe this could be splitted as another patch, to make single commits
> smaller.
Got it.
>>>> 6. Single output only: DCUltra Lite has one display output; per-
>>>> output
>>>> index logic is still in place but display_count is fixed at
>>>> 1.
>>>>
>>>> 7. Reduced register space: max_register is 0x2000 vs DC8000's
>>>> 0x2544.
>>>>
>>>> Add the "nuvoton,ma35d1-dcu" compatible string to the OF match
>>>> table,
>>>> extend Kconfig to allow building on ARCH_MA35 platforms, and
>>>> expose
>>>> vs_formats_no_yuv444 as the default format table for DCUltra Lite
>>>> (YUV444 blending is a DC8000-only feature).
>>>>
>>>> All changes have been tested on Nuvoton MA35D1 hardware and are
>>>> functioning correctly.
>>>>
>>>> Signed-off-by: Joey Lu <a0987203069@gmail.com>
>>>> ---
>>>> drivers/gpu/drm/verisilicon/Kconfig | 2 +-
>>>> drivers/gpu/drm/verisilicon/vs_bridge.c | 28 ++--
>>>> drivers/gpu/drm/verisilicon/vs_crtc.c | 13 +-
>>>> drivers/gpu/drm/verisilicon/vs_dc.c | 129
>>>> ++++++++++++----
>>>> --
>>>> drivers/gpu/drm/verisilicon/vs_dc.h | 1 +
>>>> drivers/gpu/drm/verisilicon/vs_drm.c | 16 ++-
>>>> drivers/gpu/drm/verisilicon/vs_hwdb.c | 2 +-
>>>> drivers/gpu/drm/verisilicon/vs_hwdb.h | 25 ++++
>>>> .../gpu/drm/verisilicon/vs_primary_plane.c | 43 +++---
>>>> .../drm/verisilicon/vs_primary_plane_regs.h | 2 +
>>>> 10 files changed, 187 insertions(+), 74 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/verisilicon/Kconfig
>>>> b/drivers/gpu/drm/verisilicon/Kconfig
>>>> index 7cce86ec8603..295d246eb4b4 100644
>>>> --- a/drivers/gpu/drm/verisilicon/Kconfig
>>>> +++ b/drivers/gpu/drm/verisilicon/Kconfig
>>>> @@ -2,7 +2,7 @@
>>>> config DRM_VERISILICON_DC
>>>> tristate "DRM Support for Verisilicon DC-series display
>>>> controllers"
>>>> depends on DRM && COMMON_CLK
>>>> - depends on RISCV || COMPILE_TEST
>>>> + depends on RISCV || ARCH_MA35 || COMPILE_TEST
>>>> select DRM_BRIDGE_CONNECTOR
>>>> select DRM_CLIENT_SELECTION
>>>> select DRM_DISPLAY_HELPER
>>>> diff --git a/drivers/gpu/drm/verisilicon/vs_bridge.c
>>>> b/drivers/gpu/drm/verisilicon/vs_bridge.c
>>>> index 7a93049368db..225af322de32 100644
>>>> --- a/drivers/gpu/drm/verisilicon/vs_bridge.c
>>>> +++ b/drivers/gpu/drm/verisilicon/vs_bridge.c
>>>> @@ -164,13 +164,16 @@ static void vs_bridge_enable_common(struct
>>>> vs_crtc *crtc,
>>>> VSDC_DISP_PANEL_CONFIG_CLK_EN);
>>>> regmap_set_bits(dc->regs,
>>>> VSDC_DISP_PANEL_CONFIG(output),
>>>> VSDC_DISP_PANEL_CONFIG_RUNNING);
>>>> - regmap_clear_bits(dc->regs, VSDC_DISP_PANEL_START,
>>>> -
>>>> VSDC_DISP_PANEL_START_MULTI_DISP_SYNC);
>>>> - regmap_set_bits(dc->regs, VSDC_DISP_PANEL_START,
>>>> - VSDC_DISP_PANEL_START_RUNNING(output));
>>>>
>>>> - regmap_set_bits(dc->regs,
>>>> VSDC_DISP_PANEL_CONFIG_EX(crtc-
>>>>> id),
>>>> - VSDC_DISP_PANEL_CONFIG_EX_COMMIT);
>>>> + if (dc->info->has_config_ex) {
>>>> + regmap_clear_bits(dc->regs,
>>>> VSDC_DISP_PANEL_START,
>>>> +
>>>> VSDC_DISP_PANEL_START_MULTI_DISP_SYNC);
>>>> + regmap_set_bits(dc->regs, VSDC_DISP_PANEL_START,
>>>> + VSDC_DISP_PANEL_START_RUNNING(ou
>>>> tput
>>>> ));
>>>> +
>>>> + regmap_set_bits(dc->regs,
>>>> VSDC_DISP_PANEL_CONFIG_EX(crtc->id),
>>>> + VSDC_DISP_PANEL_CONFIG_EX_COMMIT
>>>> );
>>> Should the commit operation happen on DC8000/DCUltraLite too? (By
>>> writing to DcregFrameBufferConfig0.VALID).
>>>
>>> Many registers written has "Note: This field is double buffered" in
>>> the
>>> DCUltraLite documentation.
>>>
>>> I suggest create a static function for commit -- write to the
>>> corresponding commit bit on DC8200, and write to
>>> DcregFrameBufferConfig0.VALID on DC8000/DCUltraLite.
>> [a] There is no commit operation for DCUltra Lite.
>> I'll not add a `VSDC_FB_CONFIG_VALID` macro. VALID (BIT(3)) is a
>> hardware-managed double-buffer status bit: hardware writes 1=PENDING
>> when a new register set is ready and clears to 0=WORKING after the
>> VBLANK copy. Software must never write it, and there is no polling
>> use
> It seems to be writable and controls whether register buffering is
> enabled, see [1].
>
> The description of this bit in MA35D1 TRM says "This ensures a frame
> will always start with a valid working set if this register is
> programmed last, which reduces the need for SW to wait for the start of
> a VBLANK signal in order to ensure all states are loaded before the
> next VBLANK", which indicates some kind of "committing write", although
> the code at [1] seems to indicate that double buffering is only enabled
> when bit is cleared.
>
> Anyway this bit should be programmable, and "Software must never write
> it" contradicts with the MA35D1 TRM.
>
> Thanks,
> Icenowy
>
> [1]
> https://github.com/rockos-riscv/rockos-kernel/blob/rockos-v6.6.y/drivers/gpu/drm/eswin/es_dc_hw.c#L993
Thank you for the correction. I'll add
`#define VSDC_FB_CONFIG_VALID BIT(3)` to vs_primary_plane_regs.h and
write it in `vs_primary_plane_commit()` for non-config_ex variants.
>> case in the driver that requires a named constant. For non-config_ex
>> variants, `vs_primary_plane_commit()` performs no commit operation —
>> `VSDC_FB_CONFIG_ENABLE` (OUTPUT, BIT(0)) is set in
>> `vs_crtc_atomic_enable()` and `VSDC_FB_CONFIG_RESET` (BIT(4)) is
>> set/cleared in the bridge enable/disable paths.
> ========= 8< ==========
>
^ permalink raw reply
* [PATCH v4 12/13] dma-direct: return struct page from dma_direct_alloc_from_pool()
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86, stable
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
Commit 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool
helper") changed dma_direct_alloc_from_pool() to return the CPU address
from dma_alloc_from_pool(). That fits dma_direct_alloc(), but
dma_direct_alloc_pages() also uses the helper and expects a struct page *.
Fix this by making dma_direct_alloc_from_pool() return the struct page *
again, and pass the CPU address back through an out-parameter for the
dma_direct_alloc() caller.
Fixes: 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper")
Cc: stable@vger.kernel.org
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/direct.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 902008e40ea1..5103a04df99f 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -165,24 +165,24 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp)
return !gfpflags_allow_blocking(gfp) && !is_swiotlb_for_alloc(dev);
}
-static void *dma_direct_alloc_from_pool(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
+static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, void **cpu_addr, gfp_t gfp,
+ unsigned long attrs)
{
struct page *page;
u64 phys_limit;
- void *ret;
if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_DMA_COHERENT_POOL)))
return NULL;
gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit);
- page = dma_alloc_from_pool(dev, size, &ret, gfp, attrs,
+ page = dma_alloc_from_pool(dev, size, cpu_addr, gfp, attrs,
dma_coherent_ok);
if (!page)
return NULL;
*dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
!!(attrs & DMA_ATTR_CC_SHARED));
- return ret;
+ return page;
}
static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
@@ -278,9 +278,12 @@ void *dma_direct_alloc(struct device *dev, size_t size,
* the atomic pools instead if we aren't allowed block.
*/
if ((remap || (attrs & DMA_ATTR_CC_SHARED)) &&
- dma_direct_use_pool(dev, gfp))
- return dma_direct_alloc_from_pool(dev, size, dma_handle,
- gfp, attrs);
+ dma_direct_use_pool(dev, gfp)) {
+ page = dma_direct_alloc_from_pool(dev, size,
+ dma_handle, &cpu_addr,
+ gfp, attrs);
+ return page ? cpu_addr : NULL;
+ }
if (is_swiotlb_for_alloc(dev)) {
page = dma_direct_alloc_swiotlb(dev, size, attrs);
@@ -443,7 +446,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
if ((attrs & DMA_ATTR_CC_SHARED) && dma_direct_use_pool(dev, gfp))
return dma_direct_alloc_from_pool(dev, size, dma_handle,
- gfp, attrs);
+ &cpu_addr, gfp, attrs);
if (is_swiotlb_for_alloc(dev)) {
page = dma_direct_alloc_swiotlb(dev, size, attrs);
--
2.43.0
^ permalink raw reply related
* [PATCH v4 11/13] dma-direct: rename ret to cpu_addr in alloc helpers
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
ret in dma_direct_alloc() and dma_direct_alloc_pages() holds the returned
CPU mapping, not a generic return value. Rename it to cpu_addr and update
the remaining uses to match.
This makes the allocation paths easier to follow and keeps the local naming
consistent with what the variable actually represents.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/direct.c | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 1e9f9ff7b9d3..902008e40ea1 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -212,7 +212,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
bool mark_mem_decrypt = false;
bool allow_highmem = true;
struct page *page;
- void *ret;
+ void *cpu_addr;
/*
* DMA_ATTR_CC_SHARED is not a caller-visible dma_alloc_*()
@@ -326,34 +326,33 @@ void *dma_direct_alloc(struct device *dev, size_t size,
arch_dma_prep_coherent(page, size);
/* create a coherent mapping */
- ret = dma_common_contiguous_remap(page, size, prot,
- __builtin_return_address(0));
- if (!ret)
+ cpu_addr = dma_common_contiguous_remap(page, size, prot,
+ __builtin_return_address(0));
+ if (!cpu_addr)
goto out_encrypt_pages;
} else {
- ret = page_address(page);
+ cpu_addr = page_address(page);
}
- memset(ret, 0, size);
+ memset(cpu_addr, 0, size);
if (set_uncached) {
void *uncached_cpu_addr;
arch_dma_prep_coherent(page, size);
- uncached_cpu_addr = arch_dma_set_uncached(ret, size);
+ uncached_cpu_addr = arch_dma_set_uncached(cpu_addr, size);
if (IS_ERR(uncached_cpu_addr))
goto out_free_remap_pages;
- ret = uncached_cpu_addr;
+ cpu_addr = uncached_cpu_addr;
}
*dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
!!(attrs & DMA_ATTR_CC_SHARED));
- return ret;
-
+ return cpu_addr;
out_free_remap_pages:
if (remap)
- dma_common_free_remap(ret, size);
+ dma_common_free_remap(cpu_addr, size);
out_encrypt_pages:
if (mark_mem_decrypt &&
@@ -437,7 +436,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
{
unsigned long attrs = 0;
struct page *page;
- void *ret;
+ void *cpu_addr;
if (force_dma_unencrypted(dev))
attrs |= DMA_ATTR_CC_SHARED;
@@ -455,7 +454,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
swiotlb_free(dev, page, size);
return NULL;
}
- ret = page_address(page);
+ cpu_addr = page_address(page);
goto setup_page;
}
@@ -463,11 +462,11 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
if (!page)
return NULL;
- ret = page_address(page);
- if ((attrs & DMA_ATTR_CC_SHARED) && dma_set_decrypted(dev, ret, size))
+ cpu_addr = page_address(page);
+ if ((attrs & DMA_ATTR_CC_SHARED) && dma_set_decrypted(dev, cpu_addr, size))
goto out_leak_pages;
setup_page:
- memset(ret, 0, size);
+ memset(cpu_addr, 0, size);
*dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
!!(attrs & DMA_ATTR_CC_SHARED));
return page;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 4/4] drm/mediatek: mtk_hdmi_ddc: Fix non-static global variable
From: CK Hu (胡俊光) @ 2026-05-12 9:06 UTC (permalink / raw)
To: chunkuang.hu@kernel.org, simona@ffwll.ch, Alexandre Mergnat,
AngeloGioacchino Del Regno, airlied@gmail.com,
p.zabel@pengutronix.de, matthias.bgg@gmail.com,
Louis-Alexis Eyraud
Cc: dri-devel@lists.freedesktop.org,
linux-mediatek@lists.infradead.org,
linux-arm-kernel@lists.infradead.org, kernel@collabora.com,
linux-kernel@vger.kernel.org
In-Reply-To: <20260429-mediatek-drm-fix-sparse-warnings-v1-4-d95c4d118b83@collabora.com>
On Wed, 2026-04-29 at 11:59 +0200, Louis-Alexis Eyraud wrote:
> The struct 'mtk_hdmi_ddc_driver' is not used outside of the
> mtk_hdmi_ddc.c file, so make it static to silence sparse warning:
> ```
> drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c:331:24: sparse: warning: symbol
> 'mtk_hdmi_ddc_driver' was not declared. Should it be static?
> ```
Reviewed-by: CK Hu <ck.hu@mediatek.com>
>
> Fixes: c241118b6216 ("drm/mediatek: mtk_hdmi_ddc: Switch to register as module_platform_driver")
> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
> ---
> drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
> index 6358e1af69b4..2acbdb025d89 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
> @@ -328,7 +328,7 @@ static const struct of_device_id mtk_hdmi_ddc_match[] = {
> };
> MODULE_DEVICE_TABLE(of, mtk_hdmi_ddc_match);
>
> -struct platform_driver mtk_hdmi_ddc_driver = {
> +static struct platform_driver mtk_hdmi_ddc_driver = {
> .probe = mtk_hdmi_ddc_probe,
> .remove = mtk_hdmi_ddc_remove,
> .driver = {
>
^ permalink raw reply
* [PATCH v4 10/13] dma-pool: fix page leak in atomic_pool_expand() cleanup
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
atomic_pool_expand() frees the allocated pages from the remove_mapping
error path only when CONFIG_DMA_DIRECT_REMAP is enabled.
When CONFIG_DMA_DIRECT_REMAP is disabled, failures after page allocation,
such as gen_pool_add_virt(), jump to remove_mapping and return without
freeing the pages.
Move __free_pages(page, order) out of the CONFIG_DMA_DIRECT_REMAP block so
that cleanup paths always release the allocation.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/pool.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
index 75f0eba48a23..5abd30c5119f 100644
--- a/kernel/dma/pool.c
+++ b/kernel/dma/pool.c
@@ -149,8 +149,8 @@ static int atomic_pool_expand(struct dma_gen_pool *dma_pool, size_t pool_size,
#ifdef CONFIG_DMA_DIRECT_REMAP
dma_common_free_remap(addr, pool_size);
free_page:
- __free_pages(page, order);
#endif
+ __free_pages(page, order);
out:
return ret;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v4 09/13] dma-direct: select DMA address encoding from DMA_ATTR_CC_SHARED
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
Make the dma-direct helpers derive the DMA address encoding from
DMA_ATTR_CC_SHARED instead of implicitly relying on
force_dma_unencrypted() inside phys_to_dma_direct()
Pass an explicit unencrypted/decrypted state into phys_to_dma_direct(),
make the alloc paths return DMA addresses that match the requested
buffer encryption state. Also only call dma_set_decrypted()
DMA_ATTR_CC_SHARED is actually set.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/direct.c | 48 ++++++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index f5da6e992d83..1e9f9ff7b9d3 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -24,11 +24,11 @@
u64 zone_dma_limit __ro_after_init = DMA_BIT_MASK(24);
static inline dma_addr_t phys_to_dma_direct(struct device *dev,
- phys_addr_t phys)
+ phys_addr_t phys, bool unencrypted)
{
- if (force_dma_unencrypted(dev))
+ if (unencrypted)
return phys_to_dma_unencrypted(dev, phys);
- return phys_to_dma(dev, phys);
+ return phys_to_dma_encrypted(dev, phys);
}
static inline struct page *dma_direct_to_page(struct device *dev,
@@ -39,8 +39,9 @@ static inline struct page *dma_direct_to_page(struct device *dev,
u64 dma_direct_get_required_mask(struct device *dev)
{
+ bool require_decrypted = force_dma_unencrypted(dev);
phys_addr_t phys = (phys_addr_t)(max_pfn - 1) << PAGE_SHIFT;
- u64 max_dma = phys_to_dma_direct(dev, phys);
+ u64 max_dma = phys_to_dma_direct(dev, phys, require_decrypted);
return (1ULL << (fls64(max_dma) - 1)) * 2 - 1;
}
@@ -69,7 +70,8 @@ static gfp_t dma_direct_optimal_gfp_mask(struct device *dev, u64 *phys_limit)
bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
{
- dma_addr_t dma_addr = phys_to_dma_direct(dev, phys);
+ bool require_decrypted = force_dma_unencrypted(dev);
+ dma_addr_t dma_addr = phys_to_dma_direct(dev, phys, require_decrypted);
if (dma_addr == DMA_MAPPING_ERROR)
return false;
@@ -79,17 +81,18 @@ bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
static int dma_set_decrypted(struct device *dev, void *vaddr, size_t size)
{
- if (!force_dma_unencrypted(dev))
- return 0;
- return set_memory_decrypted((unsigned long)vaddr, PFN_UP(size));
+ int ret;
+
+ ret = set_memory_decrypted((unsigned long)vaddr, PFN_UP(size));
+ if (ret)
+ pr_warn_ratelimited("leaking DMA memory that can't be decrypted\n");
+ return ret;
}
static int dma_set_encrypted(struct device *dev, void *vaddr, size_t size)
{
int ret;
- if (!force_dma_unencrypted(dev))
- return 0;
ret = set_memory_encrypted((unsigned long)vaddr, PFN_UP(size));
if (ret)
pr_warn_ratelimited("leaking DMA memory that can't be re-encrypted\n");
@@ -177,7 +180,8 @@ static void *dma_direct_alloc_from_pool(struct device *dev, size_t size,
dma_coherent_ok);
if (!page)
return NULL;
- *dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
+ *dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
+ !!(attrs & DMA_ATTR_CC_SHARED));
return ret;
}
@@ -193,9 +197,11 @@ static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size,
/* remove any dirty cache lines on the kernel alias */
if (!PageHighMem(page))
arch_dma_prep_coherent(page, size);
-
- /* return the page pointer as the opaque cookie */
- *dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
+ /*
+ * return the page pointer as the opaque cookie.
+ * Never used for unencrypted allocation
+ */
+ *dma_handle = phys_to_dma_encrypted(dev, page_to_phys(page));
return page;
}
@@ -340,7 +346,8 @@ void *dma_direct_alloc(struct device *dev, size_t size,
ret = uncached_cpu_addr;
}
- *dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
+ *dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
+ !!(attrs & DMA_ATTR_CC_SHARED));
return ret;
@@ -457,11 +464,12 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
return NULL;
ret = page_address(page);
- if (dma_set_decrypted(dev, ret, size))
+ if ((attrs & DMA_ATTR_CC_SHARED) && dma_set_decrypted(dev, ret, size))
goto out_leak_pages;
setup_page:
memset(ret, 0, size);
- *dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
+ *dma_handle = phys_to_dma_direct(dev, page_to_phys(page),
+ !!(attrs & DMA_ATTR_CC_SHARED));
return page;
out_leak_pages:
return NULL;
@@ -471,8 +479,12 @@ void dma_direct_free_pages(struct device *dev, size_t size,
struct page *page, dma_addr_t dma_addr,
enum dma_data_direction dir)
{
+ /*
+ * if the device had requested for an unencrypted buffer,
+ * convert it to encrypted on free
+ */
+ bool mark_mem_encrypted = force_dma_unencrypted(dev);
void *vaddr = page_address(page);
- bool mark_mem_encrypted = true;
/* If cpu_addr is not from an atomic pool, dma_free_from_pool() fails */
if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) &&
--
2.43.0
^ permalink raw reply related
* [PATCH v4 08/13] dma-direct: set decrypted flag for remapped DMA allocations
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
Devices that are DMA non-coherent and require a remap were skipping
dma_set_decrypted(), leaving DMA buffers encrypted even when the device
requires unencrypted access. Move the call after the if (remap) branch
so that both the direct and remapped allocation paths correctly mark the
allocation as decrypted (or fail cleanly) before use.
Fix dma_direct_alloc() and dma_direct_free() to apply set_memory_*() to
the linear-map alias of the backing pages instead of the remapped CPU
address. Also disallow highmem pages for DMA_ATTR_CC_SHARED, because
highmem buffers do not provide a usable linear-map address.
Fixes: f3c962226dbe ("dma-direct: clean up the remapping checks in dma_direct_alloc")
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/direct.c | 56 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 45 insertions(+), 11 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 5aaa813c5509..f5da6e992d83 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -204,6 +204,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
{
bool remap = false, set_uncached = false;
bool mark_mem_decrypt = false;
+ bool allow_highmem = true;
struct page *page;
void *ret;
@@ -222,6 +223,15 @@ void *dma_direct_alloc(struct device *dev, size_t size,
mark_mem_decrypt = true;
}
+ if (attrs & DMA_ATTR_CC_SHARED)
+ /*
+ * Unencrypted/shared DMA requires a linear-mapped buffer
+ * address to look up the PFN and set architecture-required PFN
+ * attributes. This is not possible with HighMem. Avoid HighMem
+ * allocation.
+ */
+ allow_highmem = false;
+
size = PAGE_ALIGN(size);
if (attrs & DMA_ATTR_NO_WARN)
gfp |= __GFP_NOWARN;
@@ -280,7 +290,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
}
/* we always manually zero the memory once we are done */
- page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO, true);
+ page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO, allow_highmem);
if (!page)
return NULL;
@@ -295,6 +305,14 @@ void *dma_direct_alloc(struct device *dev, size_t size,
set_uncached = false;
}
+ if (mark_mem_decrypt) {
+ void *lm_addr;
+
+ lm_addr = page_address(page);
+ if (set_memory_decrypted((unsigned long)lm_addr, PFN_UP(size)))
+ goto out_leak_pages;
+ }
+
if (remap) {
pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
@@ -305,31 +323,39 @@ void *dma_direct_alloc(struct device *dev, size_t size,
ret = dma_common_contiguous_remap(page, size, prot,
__builtin_return_address(0));
if (!ret)
- goto out_free_pages;
+ goto out_encrypt_pages;
} else {
ret = page_address(page);
- if (mark_mem_decrypt && dma_set_decrypted(dev, ret, size))
- goto out_leak_pages;
}
memset(ret, 0, size);
if (set_uncached) {
+ void *uncached_cpu_addr;
+
arch_dma_prep_coherent(page, size);
- ret = arch_dma_set_uncached(ret, size);
- if (IS_ERR(ret))
- goto out_encrypt_pages;
+ uncached_cpu_addr = arch_dma_set_uncached(ret, size);
+ if (IS_ERR(uncached_cpu_addr))
+ goto out_free_remap_pages;
+ ret = uncached_cpu_addr;
}
*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
return ret;
+
+out_free_remap_pages:
+ if (remap)
+ dma_common_free_remap(ret, size);
+
out_encrypt_pages:
- if (mark_mem_decrypt && dma_set_encrypted(dev, page_address(page), size))
- return NULL;
-out_free_pages:
+ if (mark_mem_decrypt &&
+ dma_set_encrypted(dev, page_address(page), size))
+ goto out_leak_pages;
+
__dma_direct_free_pages(dev, page, size);
return NULL;
+
out_leak_pages:
return NULL;
}
@@ -384,8 +410,16 @@ void dma_direct_free(struct device *dev, size_t size,
} else {
if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED))
arch_dma_clear_uncached(cpu_addr, size);
- if (mark_mem_encrypted && dma_set_encrypted(dev, cpu_addr, size))
+ }
+
+ if (mark_mem_encrypted) {
+ void *lm_addr;
+
+ lm_addr = phys_to_virt(dma_to_phys(dev, dma_addr));
+ if (set_memory_encrypted((unsigned long)lm_addr, PFN_UP(size))) {
+ pr_warn_ratelimited("leaking DMA memory that can't be re-encrypted\n");
return;
+ }
}
__dma_direct_free_pages(dev, dma_direct_to_page(dev, dma_addr), size);
--
2.43.0
^ permalink raw reply related
* [PATCH v4 07/13] dma-direct: make dma_direct_map_phys() honor DMA_ATTR_CC_SHARED
From: Aneesh Kumar K.V (Arm) @ 2026-05-12 9:04 UTC (permalink / raw)
To: iommu, linux-arm-kernel, linux-kernel, linux-coco
Cc: Aneesh Kumar K.V (Arm), Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Catalin Marinas, Jiri Pirko, Jason Gunthorpe, Mostafa Saleh,
Petr Tesarik, Alexey Kardashevskiy, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260512090408.794195-1-aneesh.kumar@kernel.org>
Teach dma_direct_map_phys() to select the DMA address encoding based on
DMA_ATTR_CC_SHARED.
Use phys_to_dma_unencrypted() for decrypted mappings and
phys_to_dma_encrypted() otherwise. If a device requires unencrypted DMA
but the source physical address is still encrypted, force the mapping
through swiotlb so the DMA address and backing memory attributes remain
consistent.
Update the arm64, x86, s390 and powerpc secure-guest setup to not use
swiotlb force option
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
Changes from v3:
* Handle DMA_ATTR_MMIO
---
arch/arm64/mm/init.c | 4 +--
arch/powerpc/platforms/pseries/svm.c | 2 +-
arch/s390/mm/init.c | 2 +-
arch/x86/kernel/pci-dma.c | 4 +--
kernel/dma/direct.c | 4 ++-
kernel/dma/direct.h | 38 +++++++++++++---------------
6 files changed, 24 insertions(+), 30 deletions(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 97987f850a33..acf67c7064db 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -338,10 +338,8 @@ void __init arch_mm_preinit(void)
unsigned int flags = SWIOTLB_VERBOSE;
bool swiotlb = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
- if (is_realm_world()) {
+ if (is_realm_world())
swiotlb = true;
- flags |= SWIOTLB_FORCE;
- }
if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb) {
/*
diff --git a/arch/powerpc/platforms/pseries/svm.c b/arch/powerpc/platforms/pseries/svm.c
index 384c9dc1899a..7a403dbd35ee 100644
--- a/arch/powerpc/platforms/pseries/svm.c
+++ b/arch/powerpc/platforms/pseries/svm.c
@@ -29,7 +29,7 @@ static int __init init_svm(void)
* need to use the SWIOTLB buffer for DMA even if dma_capable() says
* otherwise.
*/
- ppc_swiotlb_flags |= SWIOTLB_ANY | SWIOTLB_FORCE;
+ ppc_swiotlb_flags |= SWIOTLB_ANY;
/* Share the SWIOTLB buffer with the host. */
swiotlb_update_mem_attributes();
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 1f72efc2a579..843dbd445124 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -149,7 +149,7 @@ static void __init pv_init(void)
virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc);
/* make sure bounce buffers are shared */
- swiotlb_init(true, SWIOTLB_FORCE | SWIOTLB_VERBOSE);
+ swiotlb_init(true, SWIOTLB_VERBOSE);
swiotlb_update_mem_attributes();
}
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 6267363e0189..75cf8f6ae8cd 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -59,10 +59,8 @@ static void __init pci_swiotlb_detect(void)
* bounce buffers as the hypervisor can't access arbitrary VM memory
* that is not explicitly shared with it.
*/
- if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+ if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
x86_swiotlb_enable = true;
- x86_swiotlb_flags |= SWIOTLB_FORCE;
- }
}
#else
static inline void __init pci_swiotlb_detect(void)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index ac315dd046c4..5aaa813c5509 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -691,8 +691,10 @@ size_t dma_direct_max_mapping_size(struct device *dev)
{
/* If SWIOTLB is active, use its maximum mapping size */
if (is_swiotlb_active(dev) &&
- (dma_addressing_limited(dev) || is_swiotlb_force_bounce(dev)))
+ (dma_addressing_limited(dev) || is_swiotlb_force_bounce(dev) ||
+ force_dma_unencrypted(dev)))
return swiotlb_max_mapping_size(dev);
+
return SIZE_MAX;
}
diff --git a/kernel/dma/direct.h b/kernel/dma/direct.h
index e05dc7649366..4e35264ab6f8 100644
--- a/kernel/dma/direct.h
+++ b/kernel/dma/direct.h
@@ -89,36 +89,32 @@ static inline dma_addr_t dma_direct_map_phys(struct device *dev,
dma_addr_t dma_addr;
if (is_swiotlb_force_bounce(dev)) {
- if (!(attrs & DMA_ATTR_CC_SHARED)) {
- if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
- return DMA_MAPPING_ERROR;
+ if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
+ return DMA_MAPPING_ERROR;
- return swiotlb_map(dev, phys, size, dir, attrs);
- }
- } else if (attrs & DMA_ATTR_CC_SHARED) {
- return DMA_MAPPING_ERROR;
+ return swiotlb_map(dev, phys, size, dir, attrs);
}
- if (attrs & DMA_ATTR_MMIO) {
- dma_addr = phys;
- if (unlikely(!dma_capable(dev, dma_addr, size, false, attrs)))
- goto err_overflow;
- } else if (attrs & DMA_ATTR_CC_SHARED) {
+ if (attrs & DMA_ATTR_CC_SHARED)
dma_addr = phys_to_dma_unencrypted(dev, phys);
+ else
+ dma_addr = phys_to_dma_encrypted(dev, phys);
+
+ if (attrs & DMA_ATTR_MMIO) {
if (unlikely(!dma_capable(dev, dma_addr, size, false, attrs)))
goto err_overflow;
- } else {
- dma_addr = phys_to_dma(dev, phys);
- if (unlikely(!dma_capable(dev, dma_addr, size, true, attrs)) ||
- dma_kmalloc_needs_bounce(dev, size, dir)) {
- if (is_swiotlb_active(dev) &&
- !(attrs & DMA_ATTR_REQUIRE_COHERENT))
- return swiotlb_map(dev, phys, size, dir, attrs);
+ goto dma_mapped;
+ }
- goto err_overflow;
- }
+ if (unlikely(!dma_capable(dev, dma_addr, size, true, attrs)) ||
+ dma_kmalloc_needs_bounce(dev, size, dir)) {
+ if (is_swiotlb_active(dev) &&
+ !(attrs & DMA_ATTR_REQUIRE_COHERENT))
+ return swiotlb_map(dev, phys, size, dir, attrs);
+ goto err_overflow;
}
+dma_mapped:
if (!dev_is_dma_coherent(dev) &&
!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
arch_sync_dma_for_device(phys, size, dir);
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox