* Re: [PATCH v5 1/7] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
From: Ian Rogers @ 2026-05-15 16:30 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: adrian.hunter, dapeng1.mi, james.clark, namhyung,
Florian Fainelli, Li Guan, 9erthalion6, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, howardchu95, john.g.garry, jolsa,
leo.yan, libunwind-devel, linux-arm-kernel, linux-kernel,
linux-perf-users, linux-riscv, mingo, palmer, peterz, pjw,
shimin.guo, tglozar, tmricht, will
In-Reply-To: <agcDOac0qbP1KZ4Y@x1>
On Fri, May 15, 2026 at 4:27 AM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Thu, May 14, 2026 at 09:12:40PM -0300, Arnaldo Carvalho de Melo wrote:
> > On Wed, May 13, 2026 at 04:31:45PM -0700, Ian Rogers wrote:
>
> <SNIP>
>
> > > +++ b/tools/perf/util/unwind.h
>
> <SNIP>
>
> > > +static inline int libdw__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
> > > + struct thread *thread __maybe_unused,
> > > + struct perf_sample *data __maybe_unused,
> > > + int max_stack __maybe_unused,
> > > + bool best_effort __maybe_unused)
> > > +{
> > > + pr_err("Error: libdw dwarf unwinding not built into perf\n");
> > > + return 0;
> > > +}
> > > +#endif
>
> I also addressed this local sashiko review comment:
>
> -------------------------------------------------------------------------
> Since unwinding is performed per-sample in the hot path, will using pr_err()
> here cause console flooding if the user explicitly configures an unsupported
> unwind style?
> Should this use pr_warning_once() instead, similar to the UNWIND_STYLE_UNKNOWN
> fallback behavior in unwind.c?
> -------------------------------------------------------------------------
>
> And in one other place, please ack,
Acked-by: Ian Rogers <irogers@google.com>
I think Sashiko is heavily biased toward warning about too much
printing due to how the kernel handles printk, log spam, etc. For perf
we have a problem that there's lots of verbose logging and logging
something just once may lose the warning. This is somewhat the
opposite problem to the kernel's. Do I care about the change that
much? Not really. If someone is having a bad time, perhaps it makes it
a little harder for them to know why but the priority is to not make
people have a bad time.
Thanks,
Ian
> - Arnaldo
>
> diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
> index 28db3e3b9b513401..69ba08afda792d17 100644
> --- a/tools/perf/util/unwind.h
> +++ b/tools/perf/util/unwind.h
> @@ -53,7 +53,7 @@ static inline int libdw__get_entries(unwind_entry_cb_t cb __maybe_unused, void *
> int max_stack __maybe_unused,
> bool best_effort __maybe_unused)
> {
> - pr_err("Error: libdw dwarf unwinding not built into perf\n");
> + pr_warning_once("Error: libdw dwarf unwinding not built into perf\n");
> return 0;
> }
> #endif
> @@ -81,7 +81,7 @@ static inline int libunwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
> int max_stack __maybe_unused,
> bool best_effort __maybe_unused)
> {
> - pr_err("Error: libunwind dwarf unwinding not built into perf\n");
> + pr_warning_once("Error: libunwind dwarf unwinding not built into perf\n");
> return 0;
> }
>
^ permalink raw reply
* Re: [RFC v1 PATCH 0/11] Optimize this_cpu_*() ops for non-x86 (ARM64 for this series)
From: Heiko Carstens @ 2026-05-15 16:28 UTC (permalink / raw)
To: Yang Shi
Cc: David Hildenbrand (Arm), cl, dennis, tj, urezki, catalin.marinas,
will, ryan.roberts, akpm, gor, agordeev, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <583d5984-fc21-4204-9845-8ceabacf823f@os.amperecomputing.com>
On Wed, May 13, 2026 at 05:00:19PM -0700, Yang Shi wrote:
> On 5/12/26 2:02 AM, David Hildenbrand (Arm) wrote:
> > There was quite some feedback during the LSF/MM session, what's the current plan?
...
> I'm not sure whether S390 folks will implement this on S390 or not, anyway
> they are cc'ed.
I'm not sure yet, however after I had a look at the architecture documentation
a couple of weeks ago, I think it shouldn't be too hard to get this working on
s390 as well. I was a bit concerned about TLB flushing, if changes to the
kernel mapping happen with per-cpu page tables, but as of now I believe this
shouldn't cause any harm (famous last words...).
^ permalink raw reply
* [PATCH 6.6 372/474] arm64/mm: Enable batched TLB flush in unmap_hotplug_range()
From: Greg Kroah-Hartman @ 2026-05-15 15:48 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Will Deacon, linux-arm-kernel,
linux-kernel, David Hildenbrand (Arm), Ryan Roberts,
Anshuman Khandual, Catalin Marinas, Sasha Levin
In-Reply-To: <20260515154715.053014143@linuxfoundation.org>
6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <anshuman.khandual@arm.com>
[ Upstream commit 48478b9f791376b4b89018d7afdfd06865498f65 ]
During a memory hot remove operation, both linear and vmemmap mappings for
the memory range being removed, get unmapped via unmap_hotplug_range() but
mapped pages get freed only for vmemmap mapping. This is just a sequential
operation where each table entry gets cleared, followed by a leaf specific
TLB flush, and then followed by memory free operation when applicable.
This approach was simple and uniform both for vmemmap and linear mappings.
But linear mapping might contain CONT marked block memory where it becomes
necessary to first clear out all entire in the range before a TLB flush.
This is as per the architecture requirement. Hence batch all TLB flushes
during the table tear down walk and finally do it in unmap_hotplug_range().
Prior to this fix, it was hypothetically possible for a speculative access
to a higher address in the contiguous block to fill the TLB with shattered
entries for the entire contiguous range after a lower address had already
been cleared and invalidated. Due to the table entries being shattered, the
subsequent TLB invalidation for the higher address would not then clear the
TLB entries for the lower address, meaning stale TLB entries could persist.
Besides it also helps in improving the performance via TLBI range operation
along with reduced synchronization instructions. The time spent executing
unmap_hotplug_range() improved 97% measured over a 2GB memory hot removal
in KVM guest.
This scheme is not applicable during vmemmap mapping tear down where memory
needs to be freed and hence a TLB flush is required after clearing out page
table entry.
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Closes: https://lore.kernel.org/all/aWZYXhrT6D2M-7-N@willie-the-truck/
Fixes: bbd6ec605c0f ("arm64/mm: Enable memory hot remove")
Cc: stable@vger.kernel.org
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
[ replaced `__pte_clear()` with `pte_clear()` ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
arch/arm64/mm/mmu.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -870,10 +870,14 @@ static void unmap_hotplug_pte_range(pmd_
WARN_ON(!pte_present(pte));
pte_clear(&init_mm, addr, ptep);
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ /* CONT blocks are not supported in the vmemmap */
+ WARN_ON(pte_cont(pte));
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
free_hotplug_page_range(pte_page(pte),
PAGE_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
} while (addr += PAGE_SIZE, addr < end);
}
@@ -894,15 +898,14 @@ static void unmap_hotplug_pmd_range(pud_
WARN_ON(!pmd_present(pmd));
if (pmd_sect(pmd)) {
pmd_clear(pmdp);
-
- /*
- * One TLBI should be sufficient here as the PMD_SIZE
- * range is mapped with a single block entry.
- */
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ /* CONT blocks are not supported in the vmemmap */
+ WARN_ON(pmd_cont(pmd));
+ flush_tlb_kernel_range(addr, addr + PMD_SIZE);
free_hotplug_page_range(pmd_page(pmd),
PMD_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
continue;
}
WARN_ON(!pmd_table(pmd));
@@ -927,15 +930,12 @@ static void unmap_hotplug_pud_range(p4d_
WARN_ON(!pud_present(pud));
if (pud_sect(pud)) {
pud_clear(pudp);
-
- /*
- * One TLBI should be sufficient here as the PUD_SIZE
- * range is mapped with a single block entry.
- */
- flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
- if (free_mapped)
+ if (free_mapped) {
+ flush_tlb_kernel_range(addr, addr + PUD_SIZE);
free_hotplug_page_range(pud_page(pud),
PUD_SIZE, altmap);
+ }
+ /* unmap_hotplug_range() flushes TLB for !free_mapped */
continue;
}
WARN_ON(!pud_table(pud));
@@ -965,6 +965,7 @@ static void unmap_hotplug_p4d_range(pgd_
static void unmap_hotplug_range(unsigned long addr, unsigned long end,
bool free_mapped, struct vmem_altmap *altmap)
{
+ unsigned long start = addr;
unsigned long next;
pgd_t *pgdp, pgd;
@@ -986,6 +987,9 @@ static void unmap_hotplug_range(unsigned
WARN_ON(!pgd_present(pgd));
unmap_hotplug_p4d_range(pgdp, addr, next, free_mapped, altmap);
} while (addr = next, addr < end);
+
+ if (!free_mapped)
+ flush_tlb_kernel_range(start, end);
}
static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,
^ permalink raw reply
* Re: [PATCH] arm64: dts: allwinner: Cubie A5E: enable SPI flash
From: Chen-Yu Tsai @ 2026-05-15 16:12 UTC (permalink / raw)
To: Andre Przywara
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jernej Skrabec,
Samuel Holland, devicetree, linux-arm-kernel, linux-sunxi
In-Reply-To: <ee9fca66-d079-4ad7-9cb3-5077e8a4f6d6@arm.com>
On Wed, May 13, 2026 at 5:19 PM Andre Przywara <andre.przywara@arm.com> wrote:
>
> Hi Chen-Yu,
>
> thanks for chipping in!
>
> On 5/13/26 07:21, Chen-Yu Tsai wrote:
> > Hi,
> >
> > On Tue, May 12, 2026 at 6:18 AM Andre Przywara <andre.przywara@arm.com> wrote:
> >>
> >> The Cubie A5E board comes with 16MiB of SPI NOR flash.
> >>
> >> Enable the SPI0 DT node and describe the configuration.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >> .../boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 15 +++++++++++++++
> >> 1 file changed, 15 insertions(+)
> >>
> >> diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
> >> index bfdf1728cd14b..7ad22fc85d1fd 100644
> >> --- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
> >> +++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
> >> @@ -344,6 +344,21 @@ &r_pio {
> >> vcc-pm-supply = <®_aldo3>;
> >> };
> >>
> >> +&spi0 {
> >> + pinctrl-names = "default";
> >> + pinctrl-0 = <&spi0_pc_pins>, <&spi0_cs0_pc_pin>,
> >> + <&spi0_hold_pc_pin>, <&spi0_wp_pc_pin>;
> >
> > This whole thing needs to be an overlay. The HOLD and WP pins
> > conflict with eMMC usage, so it seems that Radxa only populates
> > one or the other.
> >
> > If you look at the pictures on their official website, you'll see the
> > SPI NOR chip populated, but not the eMMC chip. On the linux-sunxi wiki
> > page, you'll see the opposite.
>
> Well, I have a hard time spotting any actual eMMC SKUs in the shops anyway.
> But you are right, the hold and WP pins conflict with eMMC, whereas the
> other pins are not.
>
> > And you probably want to enable QSPI, like Sashiko mentioned.
>
> Well, in the interest of keeping this simple and enabling the usage of
> SPI flash for all the users out there, I'd rather drop the extra pins.
> This is mostly really useful for booting the firmware, maybe loading a
> tiny kernel or other data once, so performance is not a big concern in
> this use case. The BootROM surely does not use QSPI.
Given that the pins are tied on physically, if someone then enables mmc2
for a potentially present eMMC, the two pins could be toggled by the
MMC controller, causing the flash to misbehave. I'm slightly concerned
about this possibility.
ChenYu
> And as you say, if people are really interested in the last bit of
> performance, they can use an overlay.
>
> Cheers,
> Andre
>
> >
> >
> > ChenYu
> >
> >
> >> + status = "okay";
> >> +
> >> + flash@0 {
> >> + compatible = "winbond,w25q128", "jedec,spi-nor";
> >> + reg = <0>;
> >> + spi-max-frequency = <40000000>;
> >> + #address-cells = <1>;
> >> + #size-cells = <1>;
> >> + };
> >> +};
> >> +
> >> &uart0 {
> >> pinctrl-names = "default";
> >> pinctrl-0 = <&uart0_pb_pins>;
> >> --
> >> 2.46.4
> >>
> >
>
^ permalink raw reply
* Re: [PATCH 3/5] arm_mpam: add MPAM-Fb MSC firmware access support
From: Andre Przywara @ 2026-05-15 16:04 UTC (permalink / raw)
To: Ben Horgan, Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla,
Catalin Marinas, Will Deacon, Rafael J . Wysocki, Len Brown,
James Morse, Reinette Chatre, Fenghua Yu
Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <53bb22b8-c968-4643-9db0-2586b335f66b@arm.com>
Hi Ben,
On 5/8/26 12:33, Ben Horgan wrote:
> Hi Andre,
>
> On 4/29/26 15:13, Andre Przywara wrote:
>> The Arm MPAM Firmware-backed (Fb) Profile document[1] describes an
>> alternative way of accessing the "Memory System Components" (MSC) in an
>> MPAM enabled system.
>> Normally the MSCs are MMIO mapped, but in some implementations this
>> might not be possible (MSC located outside of the local socket, MSC
>> mapped secure-only) or desirable (direct MMIO access too slow or needs
>> to be mediated through a control processor). MPAM-fb standardises a
>> protocol to abstract MSC accesses, building on the SCMI protocol.
>>
>> Add functions that do an MSC read or write access by redirecting the
>> request through a firmware interface. For now this done via an ACPI
>> PCC shared memory and mailbox combination.
>>
>> Since the protocol used is only a small subset of the full SCMI spec,
>> and the SCMI protocol has no full ACPI support anyway, open-code the
>> SCMI message generation and handshake, for just the fields we need.
>>
>> [1] https://developer.arm.com/documentation/den0144/latest
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>> drivers/resctrl/Makefile | 2 +-
>> drivers/resctrl/mpam_devices.c | 16 +++-
>> drivers/resctrl/mpam_fb.c | 158 ++++++++++++++++++++++++++++++++
>> drivers/resctrl/mpam_fb.h | 17 ++++
>> drivers/resctrl/mpam_internal.h | 5 +
>> include/linux/arm_mpam.h | 2 +-
>> 6 files changed, 196 insertions(+), 4 deletions(-)
>> create mode 100644 drivers/resctrl/mpam_fb.c
>> create mode 100644 drivers/resctrl/mpam_fb.h
>>
>> diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
>> index 4f6d0e81f9b8..097c036724e9 100644
>> --- a/drivers/resctrl/Makefile
>> +++ b/drivers/resctrl/Makefile
>> @@ -1,5 +1,5 @@
>> obj-$(CONFIG_ARM64_MPAM_DRIVER) += mpam.o
>> -mpam-y += mpam_devices.o
>> +mpam-y += mpam_devices.o mpam_fb.o
>> mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS) += mpam_resctrl.o
>>
>> ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG) += -DDEBUG
>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>> index 3be09b0c46ae..90b49bfd5caa 100644
>> --- a/drivers/resctrl/mpam_devices.c
>> +++ b/drivers/resctrl/mpam_devices.c
>> @@ -28,6 +28,7 @@
>> #include <linux/workqueue.h>
>>
>> #include "mpam_internal.h"
>> +#include "mpam_fb.h"
>>
>> /* Values for the T241 errata workaround */
>> #define T241_CHIPS_MAX 4
>> @@ -175,6 +176,13 @@ static u32 __mpam_read_reg(struct mpam_msc *msc, u16 reg)
>> {
>> WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
>>
>> + if (msc->iface == MPAM_IFACE_PCC) {
>> + u32 ret;
>> +
>> + mpam_fb_send_read_request(msc, reg, &ret);
>> + return ret;
>
> On failure, aren't we returning ret while it's still uninitialized?
Ah yes, good point.
> In general, we need some strategy for handling errors. Are errors rare and serious enough
> that we can just disable mpam on error, or can we, while keeping any state correct, propagate
> the error up to the user interface?
Yes, error handling is an interesting point. MMIO accesses cannot really
fail, so this is new. I tried to introduce error handling to everything
that involves an MSC access, but this quickly led into a rabbit hole,
because it requires changing so many functions that touch MSCs at some
point. So that patch is quite intrusive.
What made me somewhat hesitant to continue with this, was the "and then
what?" question. Some functions end up being called by something that
already handles errors, so the chain ends there. But in other cases it's
not that easy, and it's not really clear what to do in case this fails.
Plus the question remains *why* it would fail in case of MPAM-Fb? Is
that a transient error, or something that would mean we lose access to
just that MSC (maybe manageable)? But more likely it's a problem with
either the mailbox or some broken state machine, which would then affect
all MPAM-Fb mananged MSCs.
So if people think we need this, I can dig this up and finish it, but be
warned it's not pretty.
Cheers,
Andre
>> + }
>> +
>> return readl_relaxed(msc->mapped_hwpage + reg);
>> }
>>
>> @@ -188,10 +196,14 @@ static inline u32 _mpam_read_partsel_reg(struct mpam_msc *msc, u16 reg)
>>
>> static void __mpam_write_reg(struct mpam_msc *msc, u16 reg, u32 val)
>> {
>> - WARN_ON_ONCE(reg + sizeof(u32) > msc->mapped_hwpage_sz);
>> WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
>>
>> - writel_relaxed(val, msc->mapped_hwpage + reg);
>> + if (msc->iface == MPAM_IFACE_PCC) {
>> + mpam_fb_send_write_request(msc, reg, val);
>> + } else {
>> + WARN_ON_ONCE(reg + sizeof(u32) > msc->mapped_hwpage_sz);
>> + writel_relaxed(val, msc->mapped_hwpage + reg);
>> + }
>> }
>>
>> static inline void _mpam_write_partsel_reg(struct mpam_msc *msc, u16 reg, u32 val)
>> diff --git a/drivers/resctrl/mpam_fb.c b/drivers/resctrl/mpam_fb.c
>> new file mode 100644
>> index 000000000000..bfb5798c74b0
>> --- /dev/null
>> +++ b/drivers/resctrl/mpam_fb.c
>> @@ -0,0 +1,158 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (C) 2024 Arm Ltd.
>> +
>> +#include <linux/arm_mpam.h>
>> +#include <linux/cleanup.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/gfp.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/list.h>
>> +#include <linux/mailbox_client.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/printk.h>
>> +#include <linux/processor.h>
>> +#include <linux/slab.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +
>> +#include <acpi/pcc.h>
>> +
>> +#include <asm/mpam.h>
>> +
>> +#include "mpam_fb.h"
>> +
>> +#define MPAM_FB_PROTOCOL_ID 0x1a
>> +#define MPAM_MSC_ATTRIBUTES_CMD 0x3
>> +#define MPAM_MSC_READ_CMD 0x4
>> +#define MPAM_MSC_WRITE_CMD 0x5
>> +
>> +#define MPAM_MSC_PROT_ID_MASK GENMASK(17, 10)
>> +#define MPAM_MSC_TOKEN_MASK GENMASK(27, 18)
>> +
>> +#define SCMI_CHAN_RSVD_OFS 0x00
>> +#define SCMI_CHAN_STATUS_OFS 0x04
>> +#define SCMI_CHAN_STATUS_FREE_BIT BIT(0)
>> +#define SCMI_CHAN_FLAGS_OFS 0x10
>> +#define SCMI_CHAN_FLAGS_IRQ BIT(0)
>> +#define SCMI_MSG_LENGTH_OFS 0x14
>> +#define SCMI_MSG_HEADER_OFS 0x18
>> +#define SCMI_MSG_PAYLOAD_OFS 0x1c
>> +
>> +#define MPAM_READ_MSG_SIZE (SCMI_MSG_PAYLOAD_OFS + 3 * sizeof(u32))
>> +#define MPAM_WRITE_MSG_SIZE (SCMI_MSG_PAYLOAD_OFS + 4 * sizeof(u32))
>> +
>> +static atomic_t mpam_fb_token = ATOMIC_INIT(0);
>> +
>> +static int mpam_fb_build_read_message(int msc_id, int reg, unsigned int token,
>> + void __iomem *msg_buf)
>> +{
>> + writel_relaxed(SCMI_CHAN_FLAGS_IRQ, msg_buf + SCMI_CHAN_FLAGS_OFS);
>> + writel_relaxed(MPAM_READ_MSG_SIZE, msg_buf + SCMI_MSG_LENGTH_OFS);
>> + writel_relaxed(MPAM_MSC_READ_CMD |
>> + FIELD_PREP(MPAM_MSC_TOKEN_MASK, token) |
>> + FIELD_PREP(MPAM_MSC_PROT_ID_MASK, MPAM_FB_PROTOCOL_ID),
>> + msg_buf + SCMI_MSG_HEADER_OFS);
>> +
>> + writel_relaxed(cpu_to_le32(msc_id), msg_buf + SCMI_MSG_PAYLOAD_OFS);
>> + writel_relaxed(0, msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x4);
>> + writel_relaxed(cpu_to_le32(reg), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x8);
>> +
>> + return MPAM_READ_MSG_SIZE;
>> +}
>> +
>> +static int mpam_fb_build_write_message(int msc_id, int reg, u32 val,
>> + unsigned int token,
>> + void __iomem *msg_buf)
>> +{
>> + writel_relaxed(MPAM_WRITE_MSG_SIZE, msg_buf + SCMI_MSG_LENGTH_OFS);
>> + writel_relaxed(MPAM_MSC_WRITE_CMD |
>> + FIELD_PREP(MPAM_MSC_TOKEN_MASK, token) |
>> + FIELD_PREP(MPAM_MSC_PROT_ID_MASK, MPAM_FB_PROTOCOL_ID),
>> + msg_buf + SCMI_MSG_HEADER_OFS);
>> +
>> + writel_relaxed(cpu_to_le32(msc_id), msg_buf + SCMI_MSG_PAYLOAD_OFS);
>> + writel_relaxed(0, msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x4);
>> + writel_relaxed(cpu_to_le32(reg), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x8);
>> + writel_relaxed(cpu_to_le32(val), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0xc);
>> +
>> + return MPAM_WRITE_MSG_SIZE;
>> +}
>> +
>> +#define SCMI_CHANNEL_FREE true
>> +#define SCMI_CHANNEL_BUSY false
>> +static int mpam_fb_wait_for_channel(struct pcc_mbox_chan *chan,
>> + bool free)
>> +{
>> + u32 status = free ? SCMI_CHAN_STATUS_FREE_BIT : 0;
>> + u32 val;
>> +
>> + /*
>> + * The channel should really be free always at this point, as we take
>> + * a lock for every read or write request. Check the free bit anyway,
>> + * for good measure and to catch corner cases.
>> + */
>> + return readl_poll_timeout(chan->shmem + SCMI_CHAN_STATUS_OFS, val,
>> + (val & SCMI_CHAN_STATUS_FREE_BIT) == status,
>> + 1, 10000);
>> +}
>> +
>> +static int mpam_fb_send_request(struct mpam_msc *msc, u16 reg, u32 *result,
>> + bool is_write)
>> +{
>> + unsigned int token = atomic_inc_return(&mpam_fb_token);
>> + struct pcc_mbox_chan *chan = msc->pcc_chan;
>> + u32 status;
>> + int ret;
>> +
>> + guard(mutex)(&msc->pcc_chan_lock);
>> + ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
>> + if (ret < 0)
>> + return ret;
>> +
>> + /* Clear error bit and mark the channel as belonging to the callee */
>> + writel(0, chan->shmem + SCMI_CHAN_STATUS_OFS);
>> +
>> + if (is_write)
>> + ret = mpam_fb_build_write_message(msc->mpam_fb_msc_id, reg,
>> + *result, token, chan->shmem);
>> + else
>> + ret = mpam_fb_build_read_message(msc->mpam_fb_msc_id, reg,
>> + token, chan->shmem);
>> + if (ret < 0)
>> + return ret;
>> +
>> + ret = mbox_send_message(chan->mchan, NULL);
>> + if (ret < 0)
>> + return ret;
>> +
>> + ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
>> + if (ret)
>> + return ret;
>> +
>> + status = readl(chan->shmem + SCMI_MSG_HEADER_OFS);
>> + if (FIELD_GET(MPAM_MSC_TOKEN_MASK, status) != token)
>> + return -ETIMEDOUT;
>> +
>> + ret = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x0);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (!is_write)
>> + *result = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x4);
>> +
>> + return 0;
>> +}
>> +
>> +int mpam_fb_send_read_request(struct mpam_msc *msc, u16 reg, u32 *result)
>> +{
>> + return mpam_fb_send_request(msc, reg, result, false);
>> +}
>> +
>> +int mpam_fb_send_write_request(struct mpam_msc *msc, u16 reg, u32 value)
>> +{
>> + return mpam_fb_send_request(msc, reg, &value, true);
>> +}
>> diff --git a/drivers/resctrl/mpam_fb.h b/drivers/resctrl/mpam_fb.h
>> new file mode 100644
>> index 000000000000..c3d1a239e16f
>> --- /dev/null
>> +++ b/drivers/resctrl/mpam_fb.h
>> @@ -0,0 +1,17 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +// Copyright (C) 2024-2025 Arm Ltd.
>> +
>> +#ifndef MPAM_FB_H_
>> +#define MPAM_FB_H_
>> +
>> +#include <linux/types.h>
>> +#include "mpam_internal.h"
>> +
>> +#define SCMI_MSG_PAYLOAD_OFS 0x1c
>> +#define MPAM_WRITE_MSG_SIZE (SCMI_MSG_PAYLOAD_OFS + 4 * sizeof(u32))
>> +#define MPAM_FB_MAX_MSG_SIZE MPAM_WRITE_MSG_SIZE
>> +
>> +int mpam_fb_send_read_request(struct mpam_msc *msc, u16 reg, u32 *result);
>> +int mpam_fb_send_write_request(struct mpam_msc *msc, u16 reg, u32 value);
>> +
>> +#endif
>> diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
>> index 80213af10a64..3f524cd4fc81 100644
>> --- a/drivers/resctrl/mpam_internal.h
>> +++ b/drivers/resctrl/mpam_internal.h
>> @@ -11,6 +11,7 @@
>> #include <linux/io.h>
>> #include <linux/jump_label.h>
>> #include <linux/llist.h>
>> +#include <linux/mailbox_client.h>
>> #include <linux/mutex.h>
>> #include <linux/resctrl.h>
>> #include <linux/spinlock.h>
>> @@ -66,6 +67,10 @@ struct mpam_msc {
>>
>> /* Not modified after mpam_is_enabled() becomes true */
>> enum mpam_msc_iface iface;
>> + struct mbox_client pcc_cl;
>> + struct pcc_mbox_chan *pcc_chan;
>> + struct mutex pcc_chan_lock; /* only one message at a time */
>> + int mpam_fb_msc_id; /* in its own name space */
>> u32 nrdy_usec;
>> cpumask_t accessibility;
>> bool has_extd_esr;
>> diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
>> index f92a36187a52..002f56e15362 100644
>> --- a/include/linux/arm_mpam.h
>> +++ b/include/linux/arm_mpam.h
>> @@ -12,7 +12,7 @@ struct mpam_msc;
>>
>> enum mpam_msc_iface {
>> MPAM_IFACE_MMIO, /* a real MPAM MSC */
>> - MPAM_IFACE_PCC, /* a fake MPAM MSC */
>> + MPAM_IFACE_PCC, /* using the MPAM-Fb firmware redirection */
>> };
>>
>> enum mpam_class_types {
>
^ permalink raw reply
* [PATCH v6 06/28] media: rockchip: rga: fix too small buffer size
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Fix the command buffer size being only a quarter of the actual size.
The RGA_CMDBUF_SIZE macro was potentially intended to specify the length
of the cmdbuf u32 array pointer. But as it's used to specify the size of
the allocation, which is counted in bytes. Therefore adjust the macro
size to bytes as it better matches the variable name and adjust it's
users accordingly.
As the command buffer is relatively small, it probably didn't caused
an issue due to being smaller than a single page.
Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support")
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Flagged by Sashiko:
https://sashiko.dev/#/patchset/20260325-spu-rga3-v4-0-e90ec1c61354%40pengutronix.de?part=10
---
drivers/media/platform/rockchip/rga/rga-hw.c | 2 +-
drivers/media/platform/rockchip/rga/rga-hw.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 43ed742a16492..d1618bb247501 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -414,7 +414,7 @@ static void rga_cmd_set(struct rga_ctx *ctx,
{
struct rockchip_rga *rga = ctx->rga;
- memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+ memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE);
rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
/*
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index cc6bd7f5b0300..2b8537a5fd0d7 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -6,7 +6,7 @@
#ifndef __RGA_HW_H__
#define __RGA_HW_H__
-#define RGA_CMDBUF_SIZE 0x20
+#define RGA_CMDBUF_SIZE 0x80
/* Hardware limits */
#define MAX_WIDTH 8192
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v12 23/28] coresight: Control path during CPU idle
From: Suzuki K Poulose @ 2026-05-15 15:45 UTC (permalink / raw)
To: Leo Yan, Mike Leach, James Clark, Yeoreum Yun, Mark Rutland,
Will Deacon, Yabin Cui, Keita Morisaki, Jie Gan, Yuanfang Zhang,
Greg Kroah-Hartman, Alexander Shishkin, Tamas Petz,
Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel
In-Reply-To: <20260511-arm_coresight_path_power_management_improvement-v12-23-1c9dcb1de8c9@arm.com>
On 11/05/2026 12:11, Leo Yan wrote:
> Extend the CPU PM flow to control the path: disable from source up to
> the node before the sink, then re-enable the same range on restore.
> To avoid latency, control it up to the node before the sink.
>
> Track per-CPU PM restore failures using percpu_pm_failed. Once a CPU
> hits a restore failure, set the percpu_pm_failed and return NOTIFY_BAD
> on subsequent notifications to avoid repeating half-completed
> transitions.
>
> Setting percpu_pm_failed permanently blocks CPU PM on that CPU. Such
> failures are typically seen during development; disabling PM operations
> simplifies the implementation, and a warning highlights the issue.
>
> Reviewed-by: James Clark <james.clark@linaro.org>
> Tested-by: Jie Gan <jie.gan@oss.qualcomm.com>
> Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
> Tested-by: James Clark <james.clark@linaro.org>
> Signed-off-by: Leo Yan <leo.yan@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-core.c | 90 +++++++++++++++++++++++-----
> 1 file changed, 75 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
> index f07f6f28b9162911cdc673a454702f3ac4dc29ad..674fc375ff44e732405563af7be9dc8fae118e41 100644
> --- a/drivers/hwtracing/coresight/coresight-core.c
> +++ b/drivers/hwtracing/coresight/coresight-core.c
> @@ -38,6 +38,7 @@ static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
>
> static DEFINE_RAW_SPINLOCK(coresight_dev_lock);
> static DEFINE_PER_CPU(struct coresight_device *, csdev_source);
> +static DEFINE_PER_CPU(bool, percpu_pm_failed);
We have to reset this when the ETM4x module is taken off or the etmN
device is unregistered ?
Rest looks fine to me.
Suzuki
>
> /**
> * struct coresight_node - elements of a path, from source to sink
> @@ -1840,7 +1841,7 @@ static void coresight_release_device_list(void)
> }
> }
>
> -static struct coresight_device *coresight_cpu_get_active_source(void)
> +static struct coresight_path *coresight_cpu_get_active_path(void)
> {
> struct coresight_device *source;
> bool is_active = false;
> @@ -1856,22 +1857,32 @@ static struct coresight_device *coresight_cpu_get_active_source(void)
>
> /*
> * It is expected to run in atomic context, so it cannot be preempted
> - * to disable the source. Here returns the active source pointer
> - * without concern that its state may change. Since the build path has
> - * taken a reference on the component, the source can be safely used
> - * by the caller.
> + * to disable the path. Here returns the active path pointer without
> + * concern that its state may change. Since the build path has taken
> + * a reference on the component, the path can be safely used by the
> + * caller.
> */
> - return is_active ? source : NULL;
> + return is_active ? source->path : NULL;
> }
>
> -static int coresight_pm_is_needed(struct coresight_device *csdev)
> +/* Return: 1 if PM is required, 0 if skip, or a negative error */
> +static int coresight_pm_is_needed(struct coresight_path *path)
> {
> - if (!csdev)
> + struct coresight_device *source;
> +
> + if (this_cpu_read(percpu_pm_failed))
> + return -EIO;
> +
> + if (!path)
> + return 0;
> +
> + source = coresight_get_source(path);
> + if (!source)
> return 0;
>
> /* pm_save_disable() and pm_restore_enable() must be paired */
> - if (coresight_ops(csdev)->pm_save_disable &&
> - coresight_ops(csdev)->pm_restore_enable)
> + if (coresight_ops(source)->pm_save_disable &&
> + coresight_ops(source)->pm_restore_enable)
> return 1;
>
> return 0;
> @@ -1887,22 +1898,71 @@ static void coresight_pm_device_restore(struct coresight_device *csdev)
> coresight_ops(csdev)->pm_restore_enable(csdev);
> }
>
> +static int coresight_pm_save(struct coresight_path *path)
> +{
> + struct coresight_device *source = coresight_get_source(path);
> + struct coresight_node *from, *to;
> + int ret;
> +
> + ret = coresight_pm_device_save(source);
> + if (ret)
> + return ret;
> +
> + from = coresight_path_first_node(path);
> + /* Disable up to the node before sink */
> + to = list_prev_entry(coresight_path_last_node(path), link);
> + coresight_disable_path_from_to(path, from, to);
> +
> + return 0;
> +}
> +
> +static void coresight_pm_restore(struct coresight_path *path)
> +{
> + struct coresight_device *source = coresight_get_source(path);
> + struct coresight_node *from, *to;
> + int ret;
> +
> + from = coresight_path_first_node(path);
> + /* Enable up to the node before sink */
> + to = list_prev_entry(coresight_path_last_node(path), link);
> + ret = coresight_enable_path_from_to(path, coresight_get_mode(source),
> + from, to);
> + if (ret)
> + goto path_failed;
> +
> + coresight_pm_device_restore(source);
> + return;
> +
> +path_failed:
> + pr_err("Failed in coresight PM restore on CPU%d: %d\n",
> + smp_processor_id(), ret);
> +
> + /*
> + * Once PM fails on a CPU, set percpu_pm_failed and leave it set until
> + * reboot. This prevents repeated partial transitions during idle
> + * entry and exit.
> + */
> + this_cpu_write(percpu_pm_failed, true);
> +}
> +
> static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
> void *v)
> {
> - struct coresight_device *csdev = coresight_cpu_get_active_source();
> + struct coresight_path *path = coresight_cpu_get_active_path();
> + int ret;
>
> - if (!coresight_pm_is_needed(csdev))
> - return NOTIFY_DONE;
> + ret = coresight_pm_is_needed(path);
> + if (ret <= 0)
> + return ret ? NOTIFY_BAD : NOTIFY_DONE;
>
> switch (cmd) {
> case CPU_PM_ENTER:
> - if (coresight_pm_device_save(csdev))
> + if (coresight_pm_save(path))
> return NOTIFY_BAD;
> break;
> case CPU_PM_EXIT:
> case CPU_PM_ENTER_FAILED:
> - coresight_pm_device_restore(csdev);
> + coresight_pm_restore(path);
> break;
> default:
> return NOTIFY_DONE;
>
^ permalink raw reply
* Re: [PATCH/RFC 05/14] firmware: arm_scmi: Add scmi_get_base_info()
From: Geert Uytterhoeven @ 2026-05-15 15:39 UTC (permalink / raw)
To: Cristian Marussi, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Sudeep Holla, Magnus Damm, Saravana Kannan, Michael Turquette,
Stephen Boyd, Philipp Zabel, Ulf Hansson, Rafael J . Wysocki,
Kevin Hilman, Florian Fainelli, Wolfram Sang, Marek Vasut,
Kuninori Morimoto, arm-scmi, linux-arm-kernel, linux-renesas-soc,
linux-clk, devicetree, linux-pm, linux-kernel
In-Reply-To: <aekXUvIPb8nkhdKu@pluto>
Hi Christian,
On Wed, 22 Apr 2026 at 20:45, Cristian Marussi <cristian.marussi@arm.com> wrote:
> On Tue, Apr 21, 2026 at 08:11:38PM +0200, Geert Uytterhoeven wrote:
> > Currently non-SCMI drivers cannot find out what the specific versions of
> > each SCMI provider implementation on the running system are.
>
> Thanks for your patches....this is not a proper full review of the series,
> BUT this patch catched my eye..
>
> Indeed, yes, it is deliberate that the SCMI version information is NOT
> exposed out of the SCMI world, since being the SCMI an attempt to
> standardize a common FW interface (as in [1] of course), you should not
> know what runs inside the black-box, it should be irrelevant...
>
> ...indeed the versioning is used inside the SCMI stack to deal properly
> with different protocol versions implemented by the server OR to apply
> proper quirks when needed, but all the rest should be standard....
[...]
> I watched a bit of the LPC discussions around this (from Marek I think)
> but sincerely most of those problems had one (not necessarily simple)
> solution: fix your firmwares AND/OR apply quirks in the meantime...
So let's forward to the future, where the firmware is fixed, is fully
compliant with the SCMI spec, and all IDs are stable, so no quirks are
needed.
Where do we specify the SCMI IDs to use? Unless when using the
remapping driver proposed in this patch series, they must end up in the
DTB. Existing upstream users put them either in the SoC-specific .dtsi,
or in board-specific .dts.
The SCMI server is supposed to expose to an agent (e.g. Linux) a
sequential and contiguous list of IDs that represent only resources that
the agent is allowed to use.
- We cannot put the SCMI IDs in the SoC-specific .dtsi, as that
describes all hardware in the SoC, which is typically much more than
Linux can or even wants to use when running on a specific board.
- You would think we could put the SCMI IDs in the board-specific
.dts. However, that would limit actual use cases later, which do
not necessarily depend on the board solely.
- E.g. when moving control of the CAN-FD controller from Linux to
the Realtime OS, the CAN-FD node must be disabled in the DTB (by
overriding status to "reserved", or by just deleting the CAN-FD
node, both of which can be done by the boot loader). However,
with SCMI, the IDs corresponding to CAN-FD resources must be
removed from the ID space, causing a full renumbering. Who is
supposed to update the IDs in the DTB?
- E.g. when partitioning a single Linux system in multiple VMs,
and distributing hardware across these VMs, all VMs need
different DTBs, each describing a subset of the hardware. With
SCMI, each VM needs different SCMI ID spaces, causing not a
simple partitioning of the devices in the DTB, but also a
renumbering of all IDs.
Hence there are no stable SCMI IDs in DT, by design!
And what do we describe in the SoC-specific .dtsi? E.g. U-Boot IPL
still needs real hardware description.
What is the stance on this from the DT maintainers?
Thanks a lot for your answers!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH v6 03/28] media: v4l2-common: add missing 1 and 2 byte RGB formats to v4l2_format_info
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Add all missing one and two byte RGB formats to v4l2_format_info. This
allows drivers to more consistently use v4l2_format_info, as it now
covers all currently defined RGB formats.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/v4l2-core/v4l2-common.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index f6cb7e14f2236..b55ab72958eaa 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -246,8 +246,29 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{
static const struct v4l2_format_info formats[] = {
/* RGB formats (1 or 2 bytes per pixel) */
+ { .format = V4L2_PIX_FMT_RGB332, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XRGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBX444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XBGR444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRX444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XRGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBX555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XBGR555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRX555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XRGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
/* RGB formats (3 or 4 bytes per pixel) */
--
2.54.0
^ permalink raw reply related
* [PATCH v4 2/3] arm64: dts: ti: Add k3-am62l3-beaglebadge
From: Judith Mendez @ 2026-05-15 15:35 UTC (permalink / raw)
To: Judith Mendez, Nishanth Menon, Vignesh Raghavendra
Cc: Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-kernel, devicetree, linux-kernel, Andrew Davis,
Bryan Brattlof, Jason Kridner, Robert Nelson
In-Reply-To: <20260515153541.294698-1-jm@ti.com>
BeagleBoard.org BeagleBadge is a compact, affordable open source
hardware single board computer based on the Texas Instruments AM62L3
SoC designed for IoT and embedded applications with low power
consumption. Expansion is provided over open standards based headers
including QWIIC and GPIO interfaces.
https://github.com/beagleboard/BeagleBadge
Co-developed-by: Andrew Davis <afd@ti.com>
Signed-off-by: Andrew Davis <afd@ti.com>
Signed-off-by: Judith Mendez <jm@ti.com>
---
Changelog since v3:
- Add missing newline in commit message
- Drop beagleboard URL
- Drop uneeded header files
- Add boothph flags in wkup_i2c0 & PMC nodes
---
arch/arm64/boot/dts/ti/Makefile | 1 +
.../boot/dts/ti/k3-am62l3-beaglebadge.dts | 700 ++++++++++++++++++
2 files changed, 701 insertions(+)
create mode 100644 arch/arm64/boot/dts/ti/k3-am62l3-beaglebadge.dts
diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 5269c9619b65c..4e377ca011cd8 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -41,6 +41,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62d2-evm.dtb
# Boards with AM62Lx SoCs
dtb-$(CONFIG_ARCH_K3) += k3-am62l3-evm.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am62l3-beaglebadge.dtb
# Boards with AM62Px SoC
dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb
diff --git a/arch/arm64/boot/dts/ti/k3-am62l3-beaglebadge.dts b/arch/arm64/boot/dts/ti/k3-am62l3-beaglebadge.dts
new file mode 100644
index 0000000000000..30fc9c83b1f44
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am62l3-beaglebadge.dts
@@ -0,0 +1,700 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * https://www.beagleboard.org/boards/beaglebadge
+ *
+ * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/leds/common.h>
+#include "k3-am62l3.dtsi"
+#include "k3-pinctrl.h"
+
+/ {
+ compatible = "beagle,am62l3-beaglebadge", "ti,am62l3";
+ model = "BeagleBoard.org BeagleBadge";
+
+ chosen {
+ stdout-path = &uart0;
+ };
+
+ aliases {
+ gpio0 = &gpio0;
+ gpio2 = &wkup_gpio0;
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c4 = &wkup_i2c0;
+ mmc1 = &sdhci1;
+ mmc2 = &sdhci2;
+ serial3 = &uart1;
+ usb0 = &usb0;
+ usb1 = &usb1;
+ };
+
+ memory@80000000 {
+ /* 256MB */
+ reg = <0x00000000 0x80000000 0x00000000 0x10000000>;
+ device_type = "memory";
+ bootph-all;
+ };
+
+ thermal-zones {
+ wkup0-thermal {
+ polling-delay-passive = <250>; /* milliSeconds */
+ polling-delay = <500>; /* milliSeconds */
+ thermal-sensors = <&vtm0 0>;
+
+ trips {
+ crit0 {
+ temperature = <125000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+ };
+ };
+
+ gpio_keys: gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+
+ button-select {
+ label = "SELECT";
+ linux,code = <KEY_SELECT>;
+ gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
+ };
+
+ button-back {
+ label = "BACK";
+ linux,code = <KEY_BACK>;
+ gpios = <&gpio0 104 GPIO_ACTIVE_LOW>;
+ };
+
+ button-up {
+ label = "UP";
+ linux,code = <KEY_UP>;
+ gpios = <&gpio0 32 GPIO_ACTIVE_LOW>;
+ };
+
+ button-down {
+ label = "DOWN";
+ linux,code = <KEY_DOWN>;
+ gpios = <&gpio0 42 GPIO_ACTIVE_LOW>;
+ };
+
+ button-left {
+ label = "LEFT";
+ linux,code = <KEY_LEFT>;
+ gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
+ };
+
+ button-right {
+ label = "RIGHT";
+ linux,code = <KEY_RIGHT>;
+ gpios = <&gpio0 95 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ multicolor-led {
+ compatible = "pwm-leds-multicolor";
+
+ multi-led {
+ color = <LED_COLOR_ID_RGB>;
+ max-brightness = <255>;
+
+ led-red {
+ pwms = <&ecap2 0 10000000 0>;
+ color = <LED_COLOR_ID_RED>;
+ };
+
+ led-green {
+ pwms = <&ecap1 0 10000000 0>;
+ color = <LED_COLOR_ID_GREEN>;
+ };
+
+ led-blue {
+ pwms = <&epwm1 1 10000000 0>;
+ color = <LED_COLOR_ID_BLUE>;
+ };
+ };
+ };
+
+ seven-segment-left {
+ compatible = "gpio-7-segment";
+ segment-gpios = <&mcp23s18 0 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 1 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 2 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 3 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 4 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 5 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 6 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 7 GPIO_ACTIVE_LOW>;
+ };
+
+ seven-segment-right {
+ compatible = "gpio-7-segment";
+ segment-gpios = <&mcp23s18 8 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 9 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 10 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 11 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 12 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 13 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 14 GPIO_ACTIVE_LOW>,
+ <&mcp23s18 15 GPIO_ACTIVE_LOW>;
+ };
+
+ pwm-beeper {
+ compatible = "pwm-beeper";
+ pwms = <&epwm0 1 1000000 0>;
+ amp-supply = <&sensor_3v3>;
+ };
+
+ vsys_out: regulator-0 {
+ /* output of BQ24070 */
+ compatible = "regulator-fixed";
+ regulator-name = "VSYS_OUT";
+ regulator-min-microvolt = <4400000>;
+ regulator-max-microvolt = <4400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ bootph-all;
+ };
+
+ vcc_3v3_main: regulator-1 {
+ /* output of TPS62A06 */
+ compatible = "regulator-fixed";
+ regulator-name = "VCC_3V3_MAIN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vsys_out>;
+ regulator-always-on;
+ regulator-boot-on;
+ bootph-all;
+ };
+
+ vdd_3v3: regulator-2 {
+ /* output of TPS22965 */
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_3v3_main>;
+ regulator-always-on;
+ regulator-boot-on;
+ bootph-all;
+ };
+
+ vdd_3v3_sd: regulator-3 {
+ /* TPS22918DBVR */
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_3V3_SD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vdd_3v3>;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vdd_3v3_sd_ena_pins_default>;
+ bootph-all;
+ };
+
+ sensor_3v3: regulator-4 {
+ /* TPS22918DBVR */
+ compatible = "regulator-fixed";
+ regulator-name = "Sensor_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vdd_3v3>;
+ regulator-boot-on;
+ regulator-always-on;
+ enable-active-high;
+ gpio = <&wkup_gpio0 1 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sensor_3v3_ena_pins_default>;
+ bootph-all;
+ };
+
+ wlan_en: regulator-5 {
+ compatible = "regulator-fixed";
+ regulator-name = "wlan_en";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ gpios = <&gpio0 51 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_en_pins_default>;
+ };
+};
+
+&pmx0 {
+ uart0_pins_default: uart0-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01b8, PIN_OUTPUT, 0) /* (C13) UART0_TXD */
+ AM62LX_IOPAD(0x01b4, PIN_INPUT, 0) /* (D13) UART0_RXD */
+ >;
+ bootph-all;
+ };
+
+ uart0_pins_wakeup: uart0-wakeup-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01b8, PIN_OUTPUT, 0) /* (C13) UART0_TXD */
+ AM62LX_IOPAD(0x01b4, PIN_INPUT | PIN_WKUP_EN, 0) /* (D13) UART0_RXD */
+ >;
+ bootph-all;
+ };
+
+ uart1_pins_default: uart1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x019c, PIN_OUTPUT, 2) /* (A12) MCASP0_ACLKR.UART1_TXD */
+ AM62LX_IOPAD(0x0198, PIN_INPUT, 2) /* (C11) MCASP0_AFSR.UART1_RXD */
+ AM62LX_IOPAD(0x0180, PIN_INPUT, 2) /* (A8) MCASP0_AXR3.UART1_CTSn */
+ AM62LX_IOPAD(0x0184, PIN_OUTPUT, 2) /* (B10) MCASP0_AXR2.UART1_RTSn */
+ >;
+ bootph-all;
+ };
+
+ usr_button_pins_default: usr-button-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00a4, PIN_INPUT, 7) /* (H18) GPMC0_AD11.GPIO0_26 */
+ AM62LX_IOPAD(0x01e4, PIN_INPUT, 7) /* (D16) EXT_REFCLK1.GPIO0_104 */
+ AM62LX_IOPAD(0x00c0, PIN_INPUT, 7) /* (N19) GPMC0_ADVn_ALE.GPIO0_32 */
+ AM62LX_IOPAD(0x00e8, PIN_INPUT, 7) /* (L19) GPMC0_CSn1.GPIO0_42 */
+ AM62LX_IOPAD(0x00b8, PIN_INPUT, 7) /* (L21) GPMC0_CLK.GPIO0_31 */
+ AM62LX_IOPAD(0x01c0, PIN_INPUT, 7) /* (B13) UART0_RTSn.GPIO0_95 */
+ >;
+ };
+
+ i2c0_pins_default: i2c0-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01cc, PIN_INPUT_PULLUP, 0) /* (B7) I2C0_SCL */
+ AM62LX_IOPAD(0x01d0, PIN_INPUT_PULLUP, 0) /* (A7) I2C0_SDA */
+ >;
+ bootph-all;
+ };
+
+ i2c1_pins_default: i2c1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01d4, PIN_INPUT_PULLUP, 0) /* (D7) I2C1_SCL */
+ AM62LX_IOPAD(0x01d8, PIN_INPUT_PULLUP, 0) /* (A6) I2C1_SDA */
+ >;
+ bootph-all;
+ };
+
+ i2c2_qwiic_pins_default: i2c2-qwiic-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01dc, PIN_INPUT_PULLUP, 0) /* (B8) I2C2_SCL */
+ AM62LX_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D8) I2C2_SDA */
+ >;
+ bootph-all;
+ };
+
+ vdd_3v3_sd_ena_pins_default: vdd-3v3-sd-ena-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x07c, PIN_OUTPUT, 7) /* (L23) GPMC0_AD1.GPIO0_16 */
+ >;
+ bootph-all;
+ };
+
+ sensor_3v3_ena_pins_default: sensor-3v3-ena-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x004, PIN_OUTPUT, 7) /* (AA23) WKUP_UART0_TXD.WKUP_GPIO0_1 */
+ >;
+ };
+
+ mmc1_pins_default: mmc1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0230, PIN_INPUT, 0) /* (Y3) MMC1_CMD */
+ AM62LX_IOPAD(0x0228, PIN_OUTPUT, 0) /* (Y2) MMC1_CLK */
+ AM62LX_IOPAD(0x0224, PIN_INPUT, 0) /* (AA1) MMC1_DAT0 */
+ AM62LX_IOPAD(0x0220, PIN_INPUT, 0) /* (Y4) MMC1_DAT1 */
+ AM62LX_IOPAD(0x021c, PIN_INPUT, 0) /* (AA2) MMC1_DAT2 */
+ AM62LX_IOPAD(0x0218, PIN_INPUT, 0) /* (AB2) MMC1_DAT3 */
+ AM62LX_IOPAD(0x0234, PIN_INPUT, 7) /* (B6) MMC1_SDCD.GPIO0_122 */
+ >;
+ bootph-all;
+ };
+
+ mmc2_pins_default: mmc2-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x010c, PIN_INPUT, 0) /* (U23) MMC2_CMD */
+ AM62LX_IOPAD(0x0104, PIN_OUTPUT, 0) /* (R23) MMC2_CLK */
+ AM62LX_IOPAD(0x0108, PIN_INPUT, 0) /* () MMC2_CLKLB */
+ AM62LX_IOPAD(0x0100, PIN_INPUT, 0) /* (U22) MMC2_DAT0 */
+ AM62LX_IOPAD(0x00fc, PIN_INPUT, 0) /* (T22) MMC2_DAT1 */
+ AM62LX_IOPAD(0x00f8, PIN_INPUT, 0) /* (T23) MMC2_DAT2 */
+ AM62LX_IOPAD(0x00f4, PIN_INPUT, 0) /* (R22) MMC2_DAT3 */
+ >;
+ };
+
+ wlan_en_pins_default: wlan-en-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0110, PIN_OUTPUT, 7) /* (T20) MMC2_SDCD.GPIO0_51 */
+ >;
+ };
+
+ usb1_pins_default: usb1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0248, PIN_INPUT | PIN_DS_PULLUD_ENABLE |
+ PIN_DS_PULL_UP, 0) /* (A5) USB1_DRVVBUS */
+ >;
+ bootph-all;
+ };
+
+ pwm_beeper_pins_default: pwm-beeper-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00b0, PIN_OUTPUT, 4) /* (F22) GPMC0_AD14.EHRPWM0_B */
+ >;
+ };
+
+ pmic_irq_pins_default: pmic-irq-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x01e8, PIN_INPUT, 0) /* (C8) EXTINTn */
+ >;
+ bootph-all;
+ };
+
+ wkup_i2c0_pins_default: wkup-i2c0-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0010, PIN_INPUT_PULLUP, 0) /* (AB22) WKUP_I2C0_SCL */
+ AM62LX_IOPAD(0x0014, PIN_INPUT_PULLUP, 0) /* (AA22) WKUP_I2C0_SDA */
+ >;
+ bootph-all;
+ };
+
+ rgb_led_ecap2_pins_default: rgb-led-ecap2-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0190, PIN_OUTPUT, 2) /* (A11) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */
+ >;
+ };
+
+ rgb_led_ecap1_pins_default: rgb-led-ecap1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0188, PIN_OUTPUT, 2) /* (A9) MCASP0_AXR1.ECAP1_IN_APWM_OUT */
+ >;
+ };
+
+ rgb_led_epwm1_pins_default: rgb-led-epwm1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x018c, PIN_OUTPUT, 5) /* (B9) MCASP0_AXR0.EHRPWM1_B */
+ >;
+ };
+
+ spi1_pins_default: spi1-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x008c, PIN_OUTPUT, 4) /* (H22) GPMC0_AD5.SPI1_CLK */
+ AM62LX_IOPAD(0x0088, PIN_OUTPUT, 4) /* (K23) GPMC0_AD4.SPI1_CS0 */
+ AM62LX_IOPAD(0x0080, PIN_INPUT, 4) /* (K22) GPMC0_AD2.SPI1_D0 */
+ AM62LX_IOPAD(0x0084, PIN_OUTPUT, 4) /* (J23) GPMC0_AD3.SPI1_D1 */
+ >;
+ bootph-all;
+ };
+
+ spi3_pins_default: spi3-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00d0, PIN_OUTPUT, 5) /* (P22) GPMC0_BE1n.SPI3_CLK */
+ AM62LX_IOPAD(0x00cc, PIN_OUTPUT, 5) /* (P23) GPMC0_BE0n_CLE.SPI3_CS0 */
+ AM62LX_IOPAD(0x00d4, PIN_INPUT, 5) /* (N23) GPMC0_WAIT0.SPI3_D0 */
+ AM62LX_IOPAD(0x00d8, PIN_OUTPUT, 5) /* (N22) GPMC0_WAIT1.SPI3_D1 */
+ >;
+ };
+
+ mcp23s18_reset_pins_default: mcp23s18-reset-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00a0, PIN_OUTPUT, 7) /* (H21) GPMC0_AD10.GPIO0_25 */
+ >;
+ };
+
+ epwm2_pins_default: epwm2-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00c4, PIN_OUTPUT, 4) /* (N20) GPMC0_OEn_REn.EHRPWM2_A */
+ >;
+ };
+
+ lora_control_pins_default: lora-control-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x00c8, PIN_OUTPUT, 7) /* (M19) GPMC0_WEn.GPIO0_34 */
+ AM62LX_IOPAD(0x00e4, PIN_OUTPUT, 7) /* (L20) GPMC0_CSn0.GPIO0_41 */
+ AM62LX_IOPAD(0x01a4, PIN_INPUT, 7) /* (D11) SPI0_CS1.GPIO0_88 */
+ AM62LX_IOPAD(0x01bc, PIN_INPUT, 7) /* (B14) UART0_CTSn.GPIO0_94 */
+ >;
+ };
+
+ gpio0_pins_default: gpio0-default-pins {
+ pinctrl-single,pins = <
+ AM62LX_IOPAD(0x0078, PIN_OUTPUT, 7) /* (L22) GPMC0_AD0.GPIO0_15 */
+ AM62LX_IOPAD(0x00e0, PIN_INPUT, 7) /* (M21) GPMC0_DIR.GPIO0_40 */
+ AM62LX_IOPAD(0x00ec, PIN_OUTPUT, 7) /* (M23) GPMC0_CSn2.GPIO0_43 */
+ AM62LX_IOPAD(0x00f0, PIN_INPUT, 7) /* (M22) GPMC0_CSn3.GPIO0_44 */
+ AM62LX_IOPAD(0x0194, PIN_OUTPUT, 7) /* (B11) MCASP0_AFSX.GPIO0_84 */
+ >;
+ };
+};
+
+&uart0 {
+ wakeup-source;
+ pinctrl-0 = <&uart0_pins_default>;
+ pinctrl-1 = <&uart0_pins_wakeup>;
+ pinctrl-names = "default", "wakeup";
+ bootph-all;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_default>;
+ bootph-all;
+ status = "okay";
+
+ /* T&H Sensor */
+ th-sensor@44 {
+ compatible = "sensirion,sht4x";
+ reg = <0x44>;
+ };
+
+ /* EEPROM */
+ eeprom@50 {
+ /* FT24C32A-ELRT */
+ compatible = "atmel,24c32";
+ reg = <0x50>;
+ };
+
+ /* Fuel Gauge */
+ fuel-gauge@55 {
+ compatible = "ti,bq27541";
+ reg = <0x55>;
+ };
+
+ /* IMU Sensor */
+ accelerometer@6a {
+ compatible = "st,lsm6ds3tr-c";
+ reg = <0x6a>;
+ vdd-supply = <&vcc_3v3_main>;
+ vddio-supply = <&vcc_3v3_main>;
+ };
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_qwiic_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&wkup_i2c0 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wkup_i2c0_pins_default>;
+ bootph-all;
+ status = "okay";
+
+ tps65214: pmic@30 {
+ compatible = "ti,tps65214";
+ reg = <0x30>;
+ interrupt-parent = <&gic500>;
+ interrupts = <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
+ buck1-supply = <&vcc_3v3_main>;
+ buck2-supply = <&vcc_3v3_main>;
+ buck3-supply = <&vcc_3v3_main>;
+ ldo1-supply = <&vcc_3v3_main>;
+ ldo2-supply = <&vcc_3v3_main>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_irq_pins_default>;
+ ti,power-button;
+ bootph-all;
+
+ regulators {
+ buck1_reg: buck1 {
+ regulator-name = "VDD_CORE";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <750000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: buck2 {
+ regulator-name = "VDD_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: buck3 {
+ regulator-name = "VDD_LPDDR4";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo1_reg: ldo1 {
+ regulator-name = "VDDA_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo2_reg: ldo2 {
+ regulator-name = "PMIC_VDD_RTC";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <750000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
+};
+
+&gpio0 {
+ gpio-line-names ="","","","","","","","","","", /* 0-9 */
+ "","","","","","BOOST_5V_ENA","VDD_3V3_SD_ENA","","","", /* 10-19 */
+ "","","","","","MCP23S18_RESET","BTN_SELECT","","","", /* 20-29 */
+ "","BTN_LEFT","BTN_UP","","LORA_RESET","","","","","", /* 30-39 */
+ "FUEL_GAUGE_BATLOW","LORA_RFSW","BTN_DOWN","USB_HUB_RST","MIKROBUS_INT","","","","","", /* 40-49 */
+ "","WLAN_EN","","","","","","","","", /* 50-59 */
+ "","","","","","","","","","", /* 60-69 */
+ "","","","","","","","","","", /* 70-79 */
+ "","","","","MIKROBUS_RST","","","","LORA_BUSY","", /* 80-89 */
+ "","","","","LORA_DIO","BTN_RIGHT","","","","", /* 90-99 */
+ "","","","","BTN_BACK","","","","","", /* 100-109 */
+ "","","","","","","","","","", /* 110-119 */
+ "","","SD_CD","","",""; /* 120-125 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio0_pins_default>, <&usr_button_pins_default>, <&lora_control_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&wkup_gpio0 {
+ gpio-line-names ="","SENSOR_3V3_ENA","","","","","",""; /* 0-7 */
+ bootph-all;
+ status = "okay";
+};
+
+&sdhci1 {
+ /* SD/MMC */
+ vmmc-supply = <&vdd_3v3_sd>;
+ disable-wp;
+ cd-gpios = <&gpio0 122 GPIO_ACTIVE_LOW>;
+ cd-debounce-delay-ms = <100>;
+ ti,fails-without-test-cd;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&sdhci2 {
+ vmmc-supply = <&wlan_en>;
+ bus-width = <4>;
+ non-removable;
+ cap-power-off-card;
+ keep-power-in-suspend;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_default>;
+ ti,driver-strength-ohm = <50>;
+ ti,fails-without-test-cd;
+ status = "okay";
+};
+
+&epwm0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_beeper_pins_default>;
+ status = "okay";
+};
+
+&epwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgb_led_epwm1_pins_default>;
+ status = "okay";
+};
+
+&epwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&epwm2_pins_default>;
+ status = "okay";
+};
+
+&ecap1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgb_led_ecap1_pins_default>;
+ status = "okay";
+};
+
+&ecap2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgb_led_ecap2_pins_default>;
+ status = "okay";
+};
+
+&usbss0 {
+ ti,vbus-divider;
+ status = "okay";
+};
+
+&usb0 {
+ usb-role-switch;
+ bootph-all;
+ status = "okay";
+};
+
+&usbss1 {
+ ti,vbus-divider;
+ bootph-all;
+ status = "okay";
+};
+
+&usb1 {
+ dr_mode = "host";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins_default>;
+ bootph-all;
+ status = "okay";
+};
+
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins_default>;
+ status = "okay";
+
+ mcp23s18: gpio@0 {
+ compatible = "microchip,mcp23s18";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ reset-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcp23s18_reset_pins_default>;
+ microchip,spi-present-mask = /bits/ 8 <0x01>;
+ };
+};
+
+&spi3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi3_pins_default>;
+ status = "okay";
+};
--
2.54.0
^ permalink raw reply related
* [PATCH v4 1/3] dt-bindings: arm: ti: Add am62l3-beaglebadge
From: Judith Mendez @ 2026-05-15 15:35 UTC (permalink / raw)
To: Judith Mendez, Nishanth Menon, Vignesh Raghavendra
Cc: Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-kernel, devicetree, linux-kernel, Andrew Davis,
Bryan Brattlof, Jason Kridner, Robert Nelson
In-Reply-To: <20260515153541.294698-1-jm@ti.com>
This board is based on ti,am62l3.
https://github.com/beagleboard/BeagleBadge
Signed-off-by: Judith Mendez <jm@ti.com>
---
Changelog since v3:
- Add missing newline in commit message
- Drop beagleboard url
---
Documentation/devicetree/bindings/arm/ti/k3.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml
index 2a6a9441c23de..d9cd3fb712fdd 100644
--- a/Documentation/devicetree/bindings/arm/ti/k3.yaml
+++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml
@@ -40,6 +40,7 @@ properties:
- description: K3 AM62L3 SoC and Boards
items:
- enum:
+ - beagle,am62l3-beaglebadge
- ti,am62l3-evm
- const: ti,am62l3
--
2.54.0
^ permalink raw reply related
* [PATCH v4 3/3] arm64: defconfig: Enable drivers for BeagleBadge
From: Judith Mendez @ 2026-05-15 15:35 UTC (permalink / raw)
To: Judith Mendez, Nishanth Menon, Vignesh Raghavendra
Cc: Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-kernel, devicetree, linux-kernel, Andrew Davis,
Bryan Brattlof, Jason Kridner, Robert Nelson
In-Reply-To: <20260515153541.294698-1-jm@ti.com>
Enable drivers used on BeagleBadge[1]:
- LED PWM Multicolor driver as a module
- MCP SPI IO Expander driver as a module
- Seven Segment display GPIO driver as module
- Temperature Sensor driver as a module
[1] https://github.com/beagleboard/BeagleBadge
Signed-off-by: Judith Mendez <jm@ti.com>
---
Changelog since v3:
- Add missing newline in commit message
---
arch/arm64/configs/defconfig | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d905a0777f939..5cfb7f6f2ae78 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -634,6 +634,7 @@ CONFIG_PINCTRL_BRCMSTB=y
CONFIG_PINCTRL_BCM2712=y
CONFIG_PINCTRL_DA9062=m
CONFIG_PINCTRL_MAX77620=y
+CONFIG_PINCTRL_MCP23S08=m
CONFIG_PINCTRL_RK805=m
CONFIG_PINCTRL_SINGLE=y
CONFIG_PINCTRL_SX150X=m
@@ -766,6 +767,7 @@ CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_PWM_FAN=m
CONFIG_SENSORS_RASPBERRYPI_HWMON=m
CONFIG_SENSORS_SL28CPLD=m
+CONFIG_SENSORS_SHT4x=m
CONFIG_SENSORS_AMC6821=m
CONFIG_SENSORS_INA2XX=m
CONFIG_SENSORS_INA3221=m
@@ -955,6 +957,8 @@ CONFIG_VIDEO_IMX412=m
CONFIG_VIDEO_OV5640=m
CONFIG_VIDEO_OV5645=m
CONFIG_VIDEO_S5KJN1=m
+CONFIG_AUXDISPLAY=y
+CONFIG_SEG_LED_GPIO=m
CONFIG_DRM=m
CONFIG_DRM_I2C_NXP_TDA998X=m
CONFIG_DRM_HDLCD=m
@@ -1332,6 +1336,7 @@ CONFIG_LEDS_GPIO=y
CONFIG_LEDS_PWM=y
CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_QCOM_FLASH=m
+CONFIG_LEDS_PWM_MULTICOLOR=m
CONFIG_LEDS_QCOM_LPG=m
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_DISK=y
--
2.54.0
^ permalink raw reply related
* [PATCH v4 0/3] arm64: dts/bindings: Add support for BeagleBadge
From: Judith Mendez @ 2026-05-15 15:35 UTC (permalink / raw)
To: Judith Mendez, Nishanth Menon, Vignesh Raghavendra
Cc: Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-kernel, devicetree, linux-kernel, Andrew Davis,
Bryan Brattlof, Jason Kridner, Robert Nelson
Hi,
BeagleBoard.org BeagleBadge[1] is a compact, affordable open source
hardware [2] single board computer based on the Texas Instruments AM62L3
SoC designed for IoT and embedded applications. Add base support for
the same.
SD boot:
Link: https://gist.github.com/jmenti/8818fa277597de927dd2b42ab1d2552f
This patch series adds:
- Device tree bindings update for am62l3-badge
- Device tree source for BeagleBadge board
- Defconfig: drivers for BeagleBadge
Changelog since v3:
- Fix newline in commit messages
- Drop vendor URLs
DTS:
- Add bootph flags in wakup i2c & PMIC nodes for completeness
- Drop unneeded header files
v3
Link: https://lore.kernel.org/all/20260513233447.2713737-1-jm@ti.com/
V2
Link: https://lore.kernel.org/all/20260508230341.1891450-1-jm@ti.com/
V1
Link: https://lore.kernel.org/all/20260501233148.4180391-1-jm@ti.com/
Patch series depends on:
Link: https://lore.kernel.org/all/20260513231154.2703292-1-jm@ti.com/
[1] https://www.beagleboard.org/boards/beaglebadge
[2] https://github.com/beagleboard/BeagleBadge/blob/main/design/BeagleBadge_RevA_V0.7_SCH_251107.pdf
Judith Mendez (3):
dt-bindings: arm: ti: Add am62l3-beaglebadge
arm64: dts: ti: Add k3-am62l3-beaglebadge
arm64: defconfig: Enable drivers for BeagleBadge
.../devicetree/bindings/arm/ti/k3.yaml | 1 +
arch/arm64/boot/dts/ti/Makefile | 1 +
.../boot/dts/ti/k3-am62l3-beaglebadge.dts | 700 ++++++++++++++++++
arch/arm64/configs/defconfig | 5 +
4 files changed, 707 insertions(+)
create mode 100644 arch/arm64/boot/dts/ti/k3-am62l3-beaglebadge.dts
--
2.54.0
^ permalink raw reply
* [PATCH v6 27/28] media: rockchip: rga: add rga3 support
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Add support for the RGA3 unit contained in the RK3588.
Only a basic feature set consisting of scaling and color conversion is
implemented. Currently unimplemented features include:
- Advanced formats like 10bit YUV, FBCE mode and Tile8x8 mode
- Background color (V4L2_CID_BG_COLOR)
- Configurable alpha value (V4L2_CID_ALPHA_COMPONENT)
- Image flipping (V4L2_CID_HFLIP and V4L2_CID_VFLIP)
- Image rotation (V4L2_CID_ROTATE)
- Image cropping/composing (VIDIOC_S_SELECTION)
- Only very basic output cropping for 1088 -> 1080 cases is implemented
The register address defines were copied from the
vendor Rockchip kernel sources and slightly adjusted to not start at 0
again for the cmd registers.
During testing it has been noted that the scaling of the hardware is
slightly incorrect. A test conversion of 128x128 RGBA to 256x256 RGBA
causes a slightly larger scaling. The scaling is suddle, as it seems
that the image is scaled to a 2px larger version and then cropped to
it's final size. Trying to use the RGA2 scaling factor calculation
didn't work. As the calculation matches the vendor kernel driver, no
further research has been utilized to check if there may be some kind of
better scaling factor calculation.
Furthermore comparing the RGA3 conversion with the GStreamer
videoconvertscale element, the chroma-site is different. A quick testing
didn't reveal a chroma-site that creates the same image with the
GStreamer Element. Also when converting from YUV to RGB the RGB values
differ by 1 or 2. This doesn't seem to be a colorspace conversion issue
but rather a slightly different precision on the calculation.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v6:
- Fixed other_format variable in rga3_adjust_and_map_format being
assigned the wrong way around (ctx->out is capture, not output)
Flagged by Sashiko:
https://sashiko.dev/#/patchset/20260428-spu-rga3-v5-0-eb7f5d019d86%40pengutronix.de?part=28
Changes in v5:
- Fixed cmdbuf size to not be a quarter of the actual size
---
drivers/media/platform/rockchip/rga/Makefile | 2 +-
drivers/media/platform/rockchip/rga/rga.c | 4 +
drivers/media/platform/rockchip/rga/rga.h | 1 +
drivers/media/platform/rockchip/rga/rga3-hw.c | 507 ++++++++++++++++++++++++++
drivers/media/platform/rockchip/rga/rga3-hw.h | 192 ++++++++++
5 files changed, 705 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
index 1bbecdc3d8df2..7326a548f3dc7 100644
--- a/drivers/media/platform/rockchip/rga/Makefile
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+rockchip-rga-objs := rga.o rga-hw.o rga3-hw.o rga-buf.o
obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0152b8ef2da2f..b3cb6bf8eb863 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -913,6 +913,10 @@ static const struct of_device_id rockchip_rga_match[] = {
.compatible = "rockchip,rk3399-rga",
.data = &rga2_hw,
},
+ {
+ .compatible = "rockchip,rk3588-rga3",
+ .data = &rga3_hw,
+ },
{},
};
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index feaf40acd4ee4..bd431534d0d39 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -169,5 +169,6 @@ static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
}
extern const struct rga_hw rga2_hw;
+extern const struct rga_hw rga3_hw;
#endif
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
new file mode 100644
index 0000000000000..ca1c268303dd4
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025-2026 Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/printk.h>
+
+#include <media/v4l2-common.h>
+
+#include "rga3-hw.h"
+#include "rga.h"
+
+static unsigned int rga3_get_scaling(unsigned int src, unsigned int dst)
+{
+ /*
+ * RGA3 scaling factor calculation as described in chapter 5.4.7 Resize
+ * of the TRM Part 2. The resulting scaling factor is a 16-bit value
+ * and therefore normalized with 2^16.
+ *
+ * While the TRM also mentions (dst-1)/(src-1) for the up-scaling case,
+ * it didn't work as the value always exceeds 16 bit. Flipping the
+ * factors results in a correct up-scaling. This is possible as the
+ * RGA3 has the RGA3_WIN_SCALE_XXX_UP bit to determine if it does
+ * an up or downscale.
+ *
+ * The scaling factor can potentially cause a slightly larger scaling
+ * (e.g. 1/2px larger scale and then cropped to the destination size).
+ * This can be seen when scaling 128x128px RGBA to 256x256px RGBA.
+ * The RGA2 scaling factor calculation (without the various +/-1
+ * doesn't work for the RGA3. It's assumed that this is an hardware
+ * accuracy limitation, as the vendor kernel driver uses the same
+ * scaling factor calculation.
+ *
+ * With a scaling factor of 1.0 the calculation technically also
+ * overflows 16 bit. This isn't relevant, as in this case the
+ * RGA3_WIN_SCALE_XXX_BYPASS bit completely skips the scaling operation.
+ */
+ if (dst > src) {
+ if (((src - 1) << 16) % (dst - 1) == 0)
+ return ((src - 1) << 16) / (dst - 1) - 1;
+ else
+ return ((src - 1) << 16) / (dst - 1);
+ } else {
+ return ((dst - 1) << 16) / (src - 1) + 1;
+ }
+}
+
+/*
+ * Check if the given format can be captured, as the RGA3 doesn't support all
+ * input formats also on it's output.
+ */
+static bool rga3_can_capture(const struct rga3_fmt *fmt)
+{
+ return fmt->hw_format <= RGA3_COLOR_FMT_LAST_OUTPUT;
+}
+
+/*
+ * Map the transformations to the RGA3 command buffer.
+ * Currently this is just the scaling settings and a fixed alpha value.
+ */
+static void rga3_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int src_h, src_w, dst_h, dst_w;
+ unsigned int reg;
+ u16 hor_scl_fac, ver_scl_fac;
+ const struct rga3_fmt *in = ctx->in.fmt;
+
+ /* Support basic input cropping to support 1088px inputs */
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+ dst_h = ctx->out.pix.height;
+ dst_w = ctx->out.pix.width;
+
+ reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_SCALE_HOR_UP, dst_w > src_w)
+ | FIELD_PREP(RGA3_WIN_SCALE_HOR_BYPASS, dst_w == src_w)
+ | FIELD_PREP(RGA3_WIN_SCALE_VER_UP, dst_h > src_h)
+ | FIELD_PREP(RGA3_WIN_SCALE_VER_BYPASS, dst_h == src_h);
+
+ hor_scl_fac = rga3_get_scaling(src_w, dst_w);
+ ver_scl_fac = rga3_get_scaling(src_h, dst_h);
+ reg = RGA3_WIN0_SCL_FAC - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_SCALE_HOR_FAC, hor_scl_fac)
+ | FIELD_PREP(RGA3_SCALE_VER_FAC, ver_scl_fac);
+
+ if (v4l2_format_info(in->fourcc)->has_alpha) {
+ /* copy alpha from input */
+ reg = RGA3_OVLP_TOP_ALPHA - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+ | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+ reg = RGA3_OVLP_BOT_ALPHA - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_ALPHA_SELECT_MODE, 1)
+ | FIELD_PREP(RGA3_ALPHA_BLEND_MODE, 1);
+ } else {
+ /* just use a 255 alpha value */
+ reg = RGA3_OVLP_TOP_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+ | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+ reg = RGA3_OVLP_BOT_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_OVLP_GLOBAL_ALPHA, 0xff)
+ | FIELD_PREP(RGA3_OVLP_COLOR_MODE, 1);
+ }
+}
+
+static void rga3_cmd_set_win0_addr(struct rga_ctx *ctx,
+ const struct rga_addrs *addrs)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int reg;
+
+ reg = RGA3_WIN0_Y_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->y_addr;
+ reg = RGA3_WIN0_U_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->u_addr;
+}
+
+static void rga3_cmd_set_wr_addr(struct rga_ctx *ctx,
+ const struct rga_addrs *addrs)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ unsigned int reg;
+
+ reg = RGA3_WR_Y_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->y_addr;
+ reg = RGA3_WR_U_BASE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = addrs->u_addr;
+}
+
+/* Map the input pixel format to win0 of the comamnd buffer. */
+static void rga3_cmd_set_win0_format(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ const struct rga3_fmt *in = ctx->in.fmt;
+ const struct rga3_fmt *out = ctx->out.fmt;
+ const struct v4l2_format_info *in_fmt, *out_fmt;
+ unsigned int act_h, act_w, src_h, src_w;
+ bool r2y, y2r;
+ u8 rd_format;
+ const struct v4l2_pix_format_mplane *csc_pix;
+ u8 csc_mode;
+ unsigned int reg;
+
+ act_h = ctx->in.pix.height;
+ act_w = ctx->in.pix.width;
+ /* Support basic input cropping to support 1088px inputs */
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+
+ in_fmt = v4l2_format_info(in->fourcc);
+ out_fmt = v4l2_format_info(out->fourcc);
+ r2y = v4l2_is_format_rgb(in_fmt) && v4l2_is_format_yuv(out_fmt);
+ y2r = v4l2_is_format_yuv(in_fmt) && v4l2_is_format_rgb(out_fmt);
+
+ /* The Hardware only supports formats with 1/2 planes */
+ if (in_fmt->comp_planes == 2)
+ rd_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+ else
+ rd_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+ /* set pixel format and CSC */
+ csc_pix = r2y ? &ctx->out.pix : &ctx->in.pix;
+ switch (csc_pix->ycbcr_enc) {
+ case V4L2_YCBCR_ENC_BT2020:
+ csc_mode = RGA3_WIN_CSC_MODE_BT2020_L;
+ break;
+ case V4L2_YCBCR_ENC_709:
+ csc_mode = RGA3_WIN_CSC_MODE_BT709_L;
+ break;
+ default: /* should be fixed to BT601 in adjust_and_map_format */
+ if (csc_pix->quantization == V4L2_QUANTIZATION_LIM_RANGE)
+ csc_mode = RGA3_WIN_CSC_MODE_BT601_L;
+ else
+ csc_mode = RGA3_WIN_CSC_MODE_BT601_F;
+ break;
+ }
+
+ reg = RGA3_WIN0_RD_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] |= FIELD_PREP(RGA3_WIN_ENABLE, 1)
+ | FIELD_PREP(RGA3_WIN_PIC_FORMAT, in->hw_format)
+ | FIELD_PREP(RGA3_WIN_YC_SWAP, in->yc_swap)
+ | FIELD_PREP(RGA3_WIN_RBUV_SWAP, in->rbuv_swap)
+ | FIELD_PREP(RGA3_WIN_RD_FORMAT, rd_format)
+ | FIELD_PREP(RGA3_WIN_R2Y, r2y)
+ | FIELD_PREP(RGA3_WIN_Y2R, y2r)
+ | FIELD_PREP(RGA3_WIN_CSC_MODE, csc_mode);
+
+ /* set stride */
+ reg = RGA3_WIN0_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* stride needs to be in words */
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+ reg = RGA3_WIN0_UV_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* The Hardware only supports formats with 1/2 planes */
+ if (ctx->in.pix.num_planes == 2)
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[1].bytesperline >> 2;
+ else
+ cmd[reg >> 2] = ctx->in.pix.plane_fmt[0].bytesperline >> 2;
+
+ /* set size */
+ reg = RGA3_WIN0_ACT_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, act_w)
+ | FIELD_PREP(RGA3_HEIGHT, act_h);
+ reg = RGA3_WIN0_SRC_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, src_w)
+ | FIELD_PREP(RGA3_HEIGHT, src_h);
+}
+
+/* Map the output pixel format to the command buffer */
+static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
+{
+ u32 *cmd = ctx->cmdbuf_virt;
+ const struct rga3_fmt *out = ctx->out.fmt;
+ const struct v4l2_format_info *out_fmt;
+ unsigned int dst_h, dst_w;
+ u8 wr_format;
+ unsigned int reg;
+
+ dst_h = ctx->out.pix.height;
+ dst_w = ctx->out.pix.width;
+
+ out_fmt = v4l2_format_info(out->fourcc);
+
+ /* The Hardware only supports formats with 1/2 planes */
+ if (out_fmt->comp_planes == 2)
+ wr_format = RGA3_RDWR_FORMAT_SEMI_PLANAR;
+ else
+ wr_format = RGA3_RDWR_FORMAT_INTERLEAVED;
+
+ /* set pixel format */
+ reg = RGA3_WR_CTRL - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WR_PIC_FORMAT, out->hw_format)
+ | FIELD_PREP(RGA3_WR_YC_SWAP, out->yc_swap)
+ | FIELD_PREP(RGA3_WR_RBUV_SWAP, out->rbuv_swap)
+ | FIELD_PREP(RGA3_WR_FORMAT, wr_format)
+ /* Use the max value to avoid limiting the write speed */
+ | FIELD_PREP(RGA3_WR_SW_OUTSTANDING_MAX, 63);
+
+ /* set stride */
+ reg = RGA3_WR_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* stride needs to be in words */
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+ reg = RGA3_WR_PL_VIR_STRIDE - RGA3_FIRST_CMD_REG;
+ /* The Hardware only supports formats with 1/2 planes */
+ if (ctx->out.pix.num_planes == 2)
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[1].bytesperline >> 2;
+ else
+ cmd[reg >> 2] = ctx->out.pix.plane_fmt[0].bytesperline >> 2;
+
+ /* Set size.
+ * As two inputs are not supported, we don't use win1.
+ * Therefore only set the size for win0.
+ */
+ reg = RGA3_WIN0_DST_SIZE - RGA3_FIRST_CMD_REG;
+ cmd[reg >> 2] = FIELD_PREP(RGA3_WIDTH, dst_w)
+ | FIELD_PREP(RGA3_HEIGHT, dst_h);
+}
+
+static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+ memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE);
+
+ rga3_cmd_set_win0_format(ctx);
+ rga3_cmd_set_trans_info(ctx);
+ rga3_cmd_set_wr_format(ctx);
+}
+
+static void rga3_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+{
+ struct rga_ctx *ctx = rga->curr;
+
+ rga3_cmd_set_win0_addr(ctx, &src->dma_addrs);
+ rga3_cmd_set_wr_addr(ctx, &dst->dma_addrs);
+
+ rga_write(rga, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
+
+ /* sync CMD buf for RGA */
+ dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+ /* set to master mode and start the conversion */
+ rga_write(rga, RGA3_SYS_CTRL,
+ FIELD_PREP(RGA3_CMD_MODE, RGA3_CMD_MODE_MASTER));
+ rga_write(rga, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
+ rga_write(rga, RGA3_CMD_CTRL,
+ FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
+}
+
+static bool rga3_handle_irq(struct rockchip_rga *rga)
+{
+ u32 intr;
+
+ intr = rga_read(rga, RGA3_INT_RAW);
+ /* clear all interrupts */
+ rga_write(rga, RGA3_INT_CLR, intr);
+
+ return FIELD_GET(RGA3_INT_FRM_DONE, intr);
+}
+
+static void rga3_get_version(struct rockchip_rga *rga)
+{
+ u32 version = rga_read(rga, RGA3_VERSION_NUM);
+
+ rga->version.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version);
+ rga->version.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version);
+}
+
+static struct rga3_fmt rga3_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .hw_format = RGA3_COLOR_FMT_BGR888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .hw_format = RGA3_COLOR_FMT_BGR888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBA32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBX32,
+ .hw_format = RGA3_COLOR_FMT_BGRA8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .hw_format = RGA3_COLOR_FMT_BGR565,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .hw_format = RGA3_COLOR_FMT_YUV420,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .yc_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .yc_swap = 1,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .hw_format = RGA3_COLOR_FMT_YUV422,
+ .rbuv_swap = 1,
+ },
+ /* Input only formats last to keep rga3_enum_format simple */
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRA32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XRGB32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ .rbuv_swap = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRX32,
+ .hw_format = RGA3_COLOR_FMT_ABGR8888,
+ },
+};
+
+static int rga3_enum_format(struct v4l2_fmtdesc *f)
+{
+ struct rga3_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(rga3_formats))
+ return -EINVAL;
+
+ fmt = &rga3_formats[f->index];
+ if (V4L2_TYPE_IS_CAPTURE(f->type) && !rga3_can_capture(fmt))
+ return -EINVAL;
+
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static void *rga3_adjust_and_map_format(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output)
+{
+ unsigned int i;
+ const struct v4l2_format_info *format_info;
+ const struct v4l2_pix_format_mplane *other_format;
+ const struct v4l2_format_info *other_format_info;
+
+ if (!format)
+ return &rga3_formats[0];
+
+ format_info = v4l2_format_info(format->pixelformat);
+ other_format = is_output ? &ctx->out.pix : &ctx->in.pix;
+ other_format_info = v4l2_format_info(other_format->pixelformat);
+
+ if ((v4l2_is_format_rgb(format_info) &&
+ v4l2_is_format_yuv(other_format_info)) ||
+ (v4l2_is_format_yuv(format_info) &&
+ v4l2_is_format_rgb(other_format_info))) {
+ /*
+ * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions
+ * Additionally BT709 and BT2020 only support limited range YUV.
+ */
+ switch (format->ycbcr_enc) {
+ case V4L2_YCBCR_ENC_601:
+ /* supports full and limited range */
+ break;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_BT2020:
+ format->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ default:
+ format->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rga3_formats); i++) {
+ if (!is_output && !rga3_can_capture(&rga3_formats[i]))
+ continue;
+
+ if (rga3_formats[i].fourcc == format->pixelformat)
+ return &rga3_formats[i];
+ }
+
+ format->pixelformat = rga3_formats[0].fourcc;
+ return &rga3_formats[0];
+}
+
+const struct rga_hw rga3_hw = {
+ .card_type = "rga3",
+ .has_internal_iommu = false,
+ .cmdbuf_size = RGA3_CMDBUF_SIZE,
+ .min_width = RGA3_MIN_WIDTH,
+ .min_height = RGA3_MIN_HEIGHT,
+ /* use output size, as it's a bit smaller than the input size */
+ .max_width = RGA3_MAX_OUTPUT_WIDTH,
+ .max_height = RGA3_MAX_OUTPUT_HEIGHT,
+ .max_scaling_factor = RGA3_MAX_SCALING_FACTOR,
+ .stride_alignment = 16,
+ .features = 0,
+
+ .setup_cmdbuf = rga3_hw_setup_cmdbuf,
+ .start = rga3_hw_start,
+ .handle_irq = rga3_handle_irq,
+ .get_version = rga3_get_version,
+ .enum_format = rga3_enum_format,
+ .adjust_and_map_format = rga3_adjust_and_map_format,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.h b/drivers/media/platform/rockchip/rga/rga3-hw.h
new file mode 100644
index 0000000000000..85fd8ae257ecd
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) Pengutronix e.K.
+ * Author: Sven Püschel <s.pueschel@pengutronix.de>
+ */
+#ifndef __RGA3_HW_H__
+#define __RGA3_HW_H__
+
+#include <linux/bits.h>
+#include <linux/types.h>
+
+#define RGA3_CMDBUF_SIZE 0xb8
+
+#define RGA3_MIN_WIDTH 128
+#define RGA3_MIN_HEIGHT 128
+#define RGA3_MAX_INPUT_WIDTH (8192 - 16)
+#define RGA3_MAX_INPUT_HEIGHT (8192 - 16)
+#define RGA3_MAX_OUTPUT_WIDTH (8192 - 64)
+#define RGA3_MAX_OUTPUT_HEIGHT (8192 - 64)
+#define RGA3_MAX_SCALING_FACTOR 8
+#define RGA3_RESET_TIMEOUT 1000
+
+/* Registers address */
+/* sys reg */
+#define RGA3_SYS_CTRL 0x000
+#define RGA3_CMD_CTRL 0x004
+#define RGA3_CMD_ADDR 0x008
+#define RGA3_MI_GROUP_CTRL 0x00c
+#define RGA3_ARQOS_CTRL 0x010
+#define RGA3_VERSION_NUM 0x018
+#define RGA3_VERSION_TIM 0x01c
+#define RGA3_INT_EN 0x020
+#define RGA3_INT_RAW 0x024
+#define RGA3_INT_MSK 0x028
+#define RGA3_INT_CLR 0x02c
+#define RGA3_RO_SRST 0x030
+#define RGA3_STATUS0 0x034
+#define RGA3_SCAN_CNT 0x038
+#define RGA3_CMD_STATE 0x040
+
+/* cmd reg */
+#define RGA3_WIN0_RD_CTRL 0x100
+#define RGA3_FIRST_CMD_REG RGA3_WIN0_RD_CTRL
+#define RGA3_WIN0_Y_BASE 0x110
+#define RGA3_WIN0_U_BASE 0x114
+#define RGA3_WIN0_V_BASE 0x118
+#define RGA3_WIN0_VIR_STRIDE 0x11c
+#define RGA3_WIN0_FBC_OFF 0x120
+#define RGA3_WIN0_SRC_SIZE 0x124
+#define RGA3_WIN0_ACT_OFF 0x128
+#define RGA3_WIN0_ACT_SIZE 0x12c
+#define RGA3_WIN0_DST_SIZE 0x130
+#define RGA3_WIN0_SCL_FAC 0x134
+#define RGA3_WIN0_UV_VIR_STRIDE 0x138
+#define RGA3_WIN1_RD_CTRL 0x140
+#define RGA3_WIN1_Y_BASE 0x150
+#define RGA3_WIN1_U_BASE 0x154
+#define RGA3_WIN1_V_BASE 0x158
+#define RGA3_WIN1_VIR_STRIDE 0x15c
+#define RGA3_WIN1_FBC_OFF 0x160
+#define RGA3_WIN1_SRC_SIZE 0x164
+#define RGA3_WIN1_ACT_OFF 0x168
+#define RGA3_WIN1_ACT_SIZE 0x16c
+#define RGA3_WIN1_DST_SIZE 0x170
+#define RGA3_WIN1_SCL_FAC 0x174
+#define RGA3_WIN1_UV_VIR_STRIDE 0x178
+#define RGA3_OVLP_CTRL 0x180
+#define RGA3_OVLP_OFF 0x184
+#define RGA3_OVLP_TOP_KEY_MIN 0x188
+#define RGA3_OVLP_TOP_KEY_MAX 0x18c
+#define RGA3_OVLP_TOP_CTRL 0x190
+#define RGA3_OVLP_BOT_CTRL 0x194
+#define RGA3_OVLP_TOP_ALPHA 0x198
+#define RGA3_OVLP_BOT_ALPHA 0x19c
+#define RGA3_WR_CTRL 0x1a0
+#define RGA3_WR_FBCE_CTRL 0x1a4
+#define RGA3_WR_VIR_STRIDE 0x1a8
+#define RGA3_WR_PL_VIR_STRIDE 0x1ac
+#define RGA3_WR_Y_BASE 0x1b0
+#define RGA3_WR_U_BASE 0x1b4
+#define RGA3_WR_V_BASE 0x1b8
+
+/* Registers value */
+#define RGA3_COLOR_FMT_YUV420 0x0
+#define RGA3_COLOR_FMT_YUV422 0x1
+#define RGA3_COLOR_FMT_YUV420_10B 0x2
+#define RGA3_COLOR_FMT_YUV422_10B 0x3
+/*
+ * Use memory ordering names
+ * instead of the datasheet naming RGB formats in big endian order
+ */
+#define RGA3_COLOR_FMT_BGR565 0x4
+#define RGA3_COLOR_FMT_BGR888 0x5
+#define RGA3_COLOR_FMT_FIRST_HAS_ALPHA RGA3_COLOR_FMT_BGRA8888
+#define RGA3_COLOR_FMT_BGRA8888 0x6
+#define RGA3_COLOR_FMT_LAST_OUTPUT RGA3_COLOR_FMT_BGRA8888
+/* the following are only supported as inputs */
+#define RGA3_COLOR_FMT_ABGR8888 0x7
+/*
+ * the following seem to be unnecessary,
+ * as they can be achieved with RB swaps
+ */
+#define RGA3_COLOR_FMT_RGBA8888 0x8
+#define RGA3_COLOR_FMT_ARGB8888 0x9
+
+#define RGA3_RDWR_FORMAT_SEMI_PLANAR 0x1
+#define RGA3_RDWR_FORMAT_INTERLEAVED 0x2
+
+#define RGA3_CMD_MODE_MASTER 0x1
+
+#define RGA3_WIN_CSC_MODE_BT601_L 0x0
+#define RGA3_WIN_CSC_MODE_BT709_L 0x1
+#define RGA3_WIN_CSC_MODE_BT601_F 0x2
+#define RGA3_WIN_CSC_MODE_BT2020_L 0x3
+
+/* RGA masks */
+/* SYS_CTRL */
+#define RGA3_CCLK_SRESET BIT(4)
+#define RGA3_ACLK_SRESET BIT(3)
+#define RGA3_CMD_MODE BIT(1)
+
+/* CMD_CTRL */
+#define RGA3_CMD_LINE_START_PULSE BIT(0)
+
+/* VERSION_NUM */
+#define RGA3_VERSION_NUM_MAJOR GENMASK(31, 28)
+#define RGA3_VERSION_NUM_MINOR GENMASK(27, 20)
+
+/* INT_* */
+#define RGA3_INT_FRM_DONE BIT(0)
+#define RGA3_INT_DMA_READ_BUS_ERR BIT(2)
+#define RGA3_INT_WIN0_FBC_DEC_ERR BIT(5)
+#define RGA3_INT_WIN0_HOR_ERR BIT(6)
+#define RGA3_INT_WIN0_VER_ERR BIT(7)
+#define RGA3_INT_WR_VER_ERR BIT(13)
+#define RGA3_INT_WR_HOR_ERR BIT(14)
+#define RGA3_INT_WR_BUS_ERR BIT(15)
+#define RGA3_INT_WIN0_IN_FIFO_WR_ERR BIT(16)
+#define RGA3_INT_WIN0_IN_FIFO_RD_ERR BIT(17)
+#define RGA3_INT_WIN0_HOR_FIFO_WR_ERR BIT(18)
+#define RGA3_INT_WIN0_HOR_FIFO_RD_ERR BIT(19)
+#define RGA3_INT_WIN0_VER_FIFO_WR_ERR BIT(20)
+#define RGA3_INT_WIN0_VER_FIFO_RD_ERR BIT(21)
+
+/* RO_SRST */
+#define RGA3_RO_SRST_DONE GENMASK(5, 0)
+
+/* *_SIZE */
+#define RGA3_HEIGHT GENMASK(28, 16)
+#define RGA3_WIDTH GENMASK(12, 0)
+
+/* SCL_FAC */
+#define RGA3_SCALE_VER_FAC GENMASK(31, 16)
+#define RGA3_SCALE_HOR_FAC GENMASK(15, 0)
+
+/* WINx_CTRL */
+#define RGA3_WIN_CSC_MODE GENMASK(27, 26)
+#define RGA3_WIN_R2Y BIT(25)
+#define RGA3_WIN_Y2R BIT(24)
+#define RGA3_WIN_SCALE_VER_UP BIT(23)
+#define RGA3_WIN_SCALE_VER_BYPASS BIT(22)
+#define RGA3_WIN_SCALE_HOR_UP BIT(21)
+#define RGA3_WIN_SCALE_HOR_BYPASS BIT(20)
+#define RGA3_WIN_YC_SWAP BIT(13)
+#define RGA3_WIN_RBUV_SWAP BIT(12)
+#define RGA3_WIN_RD_FORMAT GENMASK(9, 8)
+#define RGA3_WIN_PIC_FORMAT GENMASK(7, 4)
+#define RGA3_WIN_ENABLE BIT(0)
+
+/* COLOR_CTRL */
+#define RGA3_OVLP_GLOBAL_ALPHA GENMASK(23, 16)
+#define RGA3_OVLP_COLOR_MODE BIT(0)
+
+/* ALPHA_CTRL */
+#define RGA3_ALPHA_SELECT_MODE BIT(4)
+#define RGA3_ALPHA_BLEND_MODE GENMASK(3, 2)
+
+/* WR_CTRL */
+#define RGA3_WR_YC_SWAP BIT(20)
+#define RGA3_WR_SW_OUTSTANDING_MAX GENMASK(18, 13)
+#define RGA3_WR_RBUV_SWAP BIT(12)
+#define RGA3_WR_FORMAT GENMASK(9, 8)
+#define RGA3_WR_PIC_FORMAT GENMASK(7, 4)
+
+struct rga3_fmt {
+ u32 fourcc;
+ u8 hw_format;
+ bool rbuv_swap;
+ bool yc_swap;
+};
+
+#endif
--
2.54.0
^ permalink raw reply related
* [PATCH v6 24/28] media: rockchip: rga: move rga_fmt to rga-hw.h
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Move rga_fmt to rga-hw in preparation of the RGA3 addition, as the struct
contains many RGA2 specific values. They are used to write the correct
register values quickly based on the chosen format. Therefore the
pointer to the rga_fmt struct is kept but changed to an opaque void
pointer outside of the rga-hw.h.
To enumerate and set the correct formats, two helper functions need to
be exposed in the rga_hw struct:
enum_format just get's the vidioc_enum_fmt format and it's return value
is also returned from vidioc_enum_fmt. This is a simple pass-through,
as the implementation is very simple.
adjust_and_map_format is a simple abstraction around the previous
rga_find_format. But unlike rga_find_format, it always returns a valid
format. Therefore the passed format value is also a pointer to update
it in case the values are not supported by the hardware.
Due to the RGA3 supporting different formats on the capture and output
side, an additional parameter is_capture has been added to support
this use-case. The additional ctx parameter is also added to allow the
RGA3 to limit the colorimetry only if an RGB<->YCrCb transformation
happens.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v6:
- adjusted v4l2_fill_pixfmt_mp_aligned argument, which previously was
incorrectly done when the function was first introduced
---
drivers/media/platform/rockchip/rga/rga-buf.c | 2 +-
drivers/media/platform/rockchip/rga/rga-hw.c | 49 +++++++++++++++++++++------
drivers/media/platform/rockchip/rga/rga-hw.h | 8 +++++
drivers/media/platform/rockchip/rga/rga.c | 41 ++++++++--------------
drivers/media/platform/rockchip/rga/rga.h | 14 +++-----
5 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 092c2bdf6b672..c0ea6003336bf 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -162,7 +162,7 @@ static int rga_buf_prepare(struct vb2_buffer *vb)
}
/* Fill the remaining planes */
- info = v4l2_format_info(f->fmt->fourcc);
+ info = v4l2_format_info(f->pix.pixelformat);
for (i = info->mem_planes; i < info->comp_planes; i++)
dma_addrs[i] = dma_addrs[0] + get_plane_offset(f, info, i);
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index fac3975e2d0cd..616ea1bc11311 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -171,6 +171,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
u32 in_stride, out_stride;
+ struct rga_fmt *in_fmt = ctx->in.fmt;
+ struct rga_fmt *out_fmt = ctx->out.fmt;
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
@@ -186,18 +188,18 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
- src_info.data.format = ctx->in.fmt->hw_format;
- src_info.data.swap = ctx->in.fmt->color_swap;
- dst_info.data.format = ctx->out.fmt->hw_format;
- dst_info.data.swap = ctx->out.fmt->color_swap;
+ src_info.data.format = in_fmt->hw_format;
+ src_info.data.swap = in_fmt->color_swap;
+ dst_info.data.format = out_fmt->hw_format;
+ dst_info.data.swap = out_fmt->color_swap;
/*
* CSC mode must only be set when the colorspace families differ between
* input and output. It must remain unset (zeroed) if both are the same.
*/
- if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) &&
- RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) {
+ if (RGA_COLOR_FMT_IS_YUV(in_fmt->hw_format) &&
+ RGA_COLOR_FMT_IS_RGB(out_fmt->hw_format)) {
switch (ctx->in.pix.colorspace) {
case V4L2_COLORSPACE_REC709:
src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -208,8 +210,8 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
}
}
- if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) &&
- RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) {
+ if (RGA_COLOR_FMT_IS_RGB(in_fmt->hw_format) &&
+ RGA_COLOR_FMT_IS_YUV(out_fmt->hw_format)) {
switch (ctx->out.pix.colorspace) {
case V4L2_COLORSPACE_REC709:
dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
@@ -563,11 +565,36 @@ static struct rga_fmt formats[] = {
},
};
+static void *rga_adjust_and_map_format(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output)
+{
+ unsigned int i;
+
+ if (!format)
+ return &formats[0];
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].fourcc == format->pixelformat)
+ return &formats[i];
+ }
+
+ format->pixelformat = formats[0].fourcc;
+ return &formats[0];
+}
+
+static int rga_enum_format(struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ f->pixelformat = formats[f->index].fourcc;
+ return 0;
+}
+
const struct rga_hw rga2_hw = {
.card_type = "rga2",
.has_internal_iommu = true,
- .formats = formats,
- .num_formats = ARRAY_SIZE(formats),
.cmdbuf_size = RGA_CMDBUF_SIZE,
.min_width = MIN_WIDTH,
.max_width = MAX_WIDTH,
@@ -580,4 +607,6 @@ const struct rga_hw rga2_hw = {
.start = rga_hw_start,
.handle_irq = rga_handle_irq,
.get_version = rga_get_version,
+ .adjust_and_map_format = rga_adjust_and_map_format,
+ .enum_format = rga_enum_format,
};
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index 805ec23e5e3f4..14ffa5ebd453b 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -6,6 +6,8 @@
#ifndef __RGA_HW_H__
#define __RGA_HW_H__
+#include <linux/types.h>
+
#define RGA_CMDBUF_SIZE 0x80
/* Hardware limits */
@@ -431,4 +433,10 @@ union rga_pat_con {
} data;
};
+struct rga_fmt {
+ u32 fourcc;
+ u8 color_swap;
+ u8 hw_format;
+};
+
#endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index e52d0577b236c..1878b4e26360b 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -232,17 +232,6 @@ int rga_check_scaling(const struct rga_hw *hw, const struct v4l2_rect *crop_in,
return 0;
}
-static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
-{
- unsigned int i;
-
- for (i = 0; i < rga->hw->num_formats; i++) {
- if (rga->hw->formats[i].fourcc == pixelformat)
- return &rga->hw->formats[i];
- }
- return NULL;
-}
-
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
@@ -264,7 +253,6 @@ static int rga_open(struct file *file)
.crop.top = 0,
.crop.width = def_width,
.crop.height = def_height,
- .fmt = &rga->hw->formats[0],
};
ctx = kzalloc_obj(*ctx);
@@ -286,9 +274,12 @@ static int rga_open(struct file *file)
ctx->in = def_frame;
ctx->out = def_frame;
- v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.fmt->fourcc,
+ ctx->in.fmt = rga->hw->adjust_and_map_format(ctx, &ctx->in.pix, true);
+ v4l2_fill_pixfmt_mp_aligned(&ctx->in.pix, ctx->in.pix.pixelformat,
def_width, def_height, rga->hw->stride_alignment);
- v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.fmt->fourcc,
+ ctx->out.fmt =
+ rga->hw->adjust_and_map_format(ctx, &ctx->out.pix, false);
+ v4l2_fill_pixfmt_mp_aligned(&ctx->out.pix, ctx->out.pix.pixelformat,
def_width, def_height, rga->hw->stride_alignment);
if (mutex_lock_interruptible(&rga->mutex)) {
@@ -370,13 +361,11 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{
struct rockchip_rga *rga = video_drvdata(file);
- struct rga_fmt *fmt;
-
- if (f->index >= rga->hw->num_formats)
- return -EINVAL;
+ int ret;
- fmt = &rga->hw->formats[f->index];
- f->pixelformat = fmt->fourcc;
+ ret = rga->hw->enum_format(f);
+ if (ret != 0)
+ return ret;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -411,7 +400,6 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = file_to_rga_ctx(file);
const struct rga_hw *hw = ctx->rga->hw;
- struct rga_fmt *fmt;
struct v4l2_frmsize_stepwise frmsize = {
.min_width = hw->min_width,
.max_width = hw->max_width,
@@ -442,12 +430,10 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt->xfer_func = frm->pix.xfer_func;
}
- fmt = rga_fmt_find(ctx->rga, pix_fmt->pixelformat);
- if (!fmt)
- fmt = &hw->formats[0];
+ hw->adjust_and_map_format(ctx, pix_fmt, V4L2_TYPE_IS_OUTPUT(f->type));
v4l2_apply_frmsize_constraints(&pix_fmt->width, &pix_fmt->height, &frmsize);
- v4l2_fill_pixfmt_mp_aligned(pix_fmt, fmt->fourcc,
+ v4l2_fill_pixfmt_mp_aligned(pix_fmt, pix_fmt->pixelformat,
pix_fmt->width, pix_fmt->height, hw->stride_alignment);
pix_fmt->field = V4L2_FIELD_NONE;
@@ -478,7 +464,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
frm = rga_get_frame(ctx, f->type);
if (IS_ERR(frm))
return PTR_ERR(frm);
- frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
+ frm->fmt = rga->hw->adjust_and_map_format(ctx, pix_fmt,
+ V4L2_TYPE_IS_OUTPUT(f->type));
/*
* Copy colorimetry from output to capture as required by the
@@ -503,7 +490,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
v4l2_dbg(debug, 1, &rga->v4l2_dev,
"[%s] fmt - %p4cc %dx%d (stride %d)\n",
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
- &frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
+ &pix_fmt->pixelformat, pix_fmt->width, pix_fmt->height,
pix_fmt->plane_fmt[0].bytesperline);
for (i = 0; i < pix_fmt->num_planes; i++) {
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 227ab6c0532c2..effe364a86b02 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -17,18 +17,12 @@
#define DEFAULT_WIDTH 100
#define DEFAULT_HEIGHT 100
-struct rga_fmt {
- u32 fourcc;
- u8 color_swap;
- u8 hw_format;
-};
-
struct rga_frame {
/* Crop */
struct v4l2_rect crop;
/* Image format */
- struct rga_fmt *fmt;
+ void *fmt;
struct v4l2_pix_format_mplane pix;
};
@@ -146,8 +140,6 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
struct rga_hw {
const char *card_type;
bool has_internal_iommu;
- struct rga_fmt *formats;
- u32 num_formats;
size_t cmdbuf_size;
u32 min_width, min_height;
u32 max_width, max_height;
@@ -159,6 +151,10 @@ struct rga_hw {
struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
bool (*handle_irq)(struct rockchip_rga *rga);
void (*get_version)(struct rockchip_rga *rga);
+ void *(*adjust_and_map_format)(struct rga_ctx *ctx,
+ struct v4l2_pix_format_mplane *format,
+ bool is_output);
+ int (*enum_format)(struct v4l2_fmtdesc *f);
};
static inline bool rga_has_internal_iommu(const struct rockchip_rga *rga)
--
2.54.0
^ permalink raw reply related
* [PATCH v6 28/28] arm64: dts: rockchip: add rga3 dt nodes
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Add devicetree nodes for the RGA3 (Raster Graphics Acceleration 3)
peripheral in the RK3588.
The existing rga node refers to the RGA2-Enhanced peripheral. The RK3588
contains one RGA2-Enhanced core and two RGA3 cores. Both feature a similar
functionality of scaling, cropping and rotating of up to two input
images into one output image. Key differences of the RGA3 are:
- supports 10bit YUV output formats
- supports 8x8 tiles and FBCD as inputs and outputs
- supports BT2020 color space conversion
- max output resolution of (8192-64)x(8192-64)
- MMU can map up to 32G DDR RAM
- fully planar formats (3 planes) are not supported
- max scale up/down factor of 8 (RGA2 allows up to 16)
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v6:
- reordered before the rga node to fix the sorting order.
Flagged by sashiko.dev:
https://sashiko.dev/#/patchset/20260325-spu-rga3-v4-0-e90ec1c61354%40pengutronix.de?part=27
---
arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 44 +++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 4fb8888c281c8..a4f44af512375 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1262,6 +1262,50 @@ vpu121_mmu: iommu@fdb50800 {
#iommu-cells = <0>;
};
+ rga3_core0: rga@fdb60000 {
+ compatible = "rockchip,rk3588-rga3";
+ reg = <0x0 0xfdb60000 0x0 0x200>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>, <&cru CLK_RGA3_0_CORE>;
+ clock-names = "aclk", "hclk", "sclk";
+ resets = <&cru SRST_RGA3_0_CORE>, <&cru SRST_A_RGA3_0>, <&cru SRST_H_RGA3_0>;
+ reset-names = "core", "axi", "ahb";
+ power-domains = <&power RK3588_PD_RGA30>;
+ iommus = <&rga3_0_mmu>;
+ };
+
+ rga3_0_mmu: iommu@fdb60f00 {
+ compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+ reg = <0x0 0xfdb60f00 0x0 0x100>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru ACLK_RGA3_0>, <&cru HCLK_RGA3_0>;
+ clock-names = "aclk", "iface";
+ #iommu-cells = <0>;
+ power-domains = <&power RK3588_PD_RGA30>;
+ };
+
+ rga3_core1: rga@fdb70000 {
+ compatible = "rockchip,rk3588-rga3";
+ reg = <0x0 0xfdb70000 0x0 0x200>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>, <&cru CLK_RGA3_1_CORE>;
+ clock-names = "aclk", "hclk", "sclk";
+ resets = <&cru SRST_RGA3_1_CORE>, <&cru SRST_A_RGA3_1>, <&cru SRST_H_RGA3_1>;
+ reset-names = "core", "axi", "ahb";
+ power-domains = <&power RK3588_PD_RGA31>;
+ iommus = <&rga3_1_mmu>;
+ };
+
+ rga3_1_mmu: iommu@fdb70f00 {
+ compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
+ reg = <0x0 0xfdb70f00 0x0 0x100>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru ACLK_RGA3_1>, <&cru HCLK_RGA3_1>;
+ clock-names = "aclk", "iface";
+ #iommu-cells = <0>;
+ power-domains = <&power RK3588_PD_RGA31>;
+ };
+
rga: rga@fdb80000 {
compatible = "rockchip,rk3588-rga", "rockchip,rk3288-rga";
reg = <0x0 0xfdb80000 0x0 0x180>;
--
2.54.0
^ permalink raw reply related
* [PATCH v6 23/28] media: rockchip: rga: remove stride from rga_frame
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Remove the stride variable from rga_frame. Despite the comment it
didn't involve any calculation and is just a copy of the
plane_fmt[0].bytesperline value. Therefore avoid this struct member
and use the bytesperline value directly in the places where it is
required.
Also drop the dependency on the depth format member, which was only
used to calculate the stride of the default format. This is already done
by the v4l2_fill_pixfmt_mp_aligned helper and used as stride in try_fmt.
Therefore using it's value also for the default format stride is just
more consistent.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga-hw.c | 36 ++++++++++------------------
drivers/media/platform/rockchip/rga/rga.c | 5 +---
drivers/media/platform/rockchip/rga/rga.h | 4 ----
3 files changed, 13 insertions(+), 32 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 73584706a47e2..fac3975e2d0cd 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -44,7 +44,7 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
struct rga_addrs *lt, *lb, *rt, *rb;
const struct v4l2_format_info *format_info;
unsigned int x_div = 0,
- y_div = 0, uv_stride = 0, pixel_width = 0;
+ y_div = 0, y_stride = 0, uv_stride = 0, pixel_width = 0;
lt = &corner_addrs.left_top;
lb = &corner_addrs.left_bottom;
@@ -61,14 +61,15 @@ rga_get_corner_addrs(struct rga_frame *frm, struct rga_addrs *addrs,
else
x_div = 1;
y_div = format_info->vdiv;
- uv_stride = frm->stride / x_div;
- pixel_width = frm->stride / frm->pix.width;
+ y_stride = frm->pix.plane_fmt[0].bytesperline;
+ uv_stride = y_stride / x_div;
+ pixel_width = y_stride / frm->pix.width;
- lt->y_addr = addrs->y_addr + y * frm->stride + x * pixel_width;
+ lt->y_addr = addrs->y_addr + y * y_stride + x * pixel_width;
lt->u_addr = addrs->u_addr + (y / y_div) * uv_stride + x / x_div;
lt->v_addr = addrs->v_addr + (y / y_div) * uv_stride + x / x_div;
- lb->y_addr = lt->y_addr + (h - 1) * frm->stride;
+ lb->y_addr = lt->y_addr + (h - 1) * y_stride;
lb->u_addr = lt->u_addr + (h / y_div - 1) * uv_stride;
lb->v_addr = lt->v_addr + (h / y_div - 1) * uv_stride;
@@ -169,6 +170,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
union rga_src_act_info src_act_info;
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
+ u32 in_stride, out_stride;
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
@@ -291,13 +293,15 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
* Calculate the framebuffer virtual strides and active size,
* note that the step of vir_stride / vir_width is 4 byte words
*/
- src_vir_info.data.vir_stride = ctx->in.stride >> 2;
- src_vir_info.data.vir_width = ctx->in.stride >> 2;
+ in_stride = ctx->in.pix.plane_fmt[0].bytesperline;
+ src_vir_info.data.vir_stride = in_stride >> 2;
+ src_vir_info.data.vir_width = in_stride >> 2;
src_act_info.data.act_height = src_h - 1;
src_act_info.data.act_width = src_w - 1;
- dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+ out_stride = ctx->out.pix.plane_fmt[0].bytesperline;
+ dst_vir_info.data.vir_stride = out_stride >> 2;
dst_act_info.data.act_height = dst_h - 1;
dst_act_info.data.act_width = dst_w - 1;
@@ -481,97 +485,81 @@ static struct rga_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_ARGB32,
.color_swap = RGA_COLOR_ALPHA_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR8888,
- .depth = 32,
},
{
.fourcc = V4L2_PIX_FMT_ABGR32,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR8888,
- .depth = 32,
},
{
.fourcc = V4L2_PIX_FMT_XBGR32,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_XBGR8888,
- .depth = 32,
},
{
.fourcc = V4L2_PIX_FMT_RGB24,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_RGB888,
- .depth = 24,
},
{
.fourcc = V4L2_PIX_FMT_BGR24,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_RGB888,
- .depth = 24,
},
{
.fourcc = V4L2_PIX_FMT_ARGB444,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR4444,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_ARGB555,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR1555,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_RGB565,
.color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_BGR565,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_NV21,
.color_swap = RGA_COLOR_UV_SWAP,
.hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
},
{
.fourcc = V4L2_PIX_FMT_NV61,
.color_swap = RGA_COLOR_UV_SWAP,
.hw_format = RGA_COLOR_FMT_YUV422SP,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_NV12,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
},
{
.fourcc = V4L2_PIX_FMT_NV12M,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
},
{
.fourcc = V4L2_PIX_FMT_NV16,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV422SP,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_YUV420,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV420P,
- .depth = 12,
},
{
.fourcc = V4L2_PIX_FMT_YUV422P,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV422P,
- .depth = 16,
},
{
.fourcc = V4L2_PIX_FMT_YVU420,
.color_swap = RGA_COLOR_UV_SWAP,
.hw_format = RGA_COLOR_FMT_YUV420P,
- .depth = 12,
},
};
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index e44e81814b7cb..e52d0577b236c 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -267,8 +267,6 @@ static int rga_open(struct file *file)
.fmt = &rga->hw->formats[0],
};
- def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
-
ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
@@ -481,7 +479,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
if (IS_ERR(frm))
return PTR_ERR(frm);
frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
- frm->stride = pix_fmt->plane_fmt[0].bytesperline;
/*
* Copy colorimetry from output to capture as required by the
@@ -507,7 +504,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
"[%s] fmt - %p4cc %dx%d (stride %d)\n",
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
&frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
- frm->stride);
+ pix_fmt->plane_fmt[0].bytesperline);
for (i = 0; i < pix_fmt->num_planes; i++) {
v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index d47c6821ce2c9..227ab6c0532c2 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -19,7 +19,6 @@
struct rga_fmt {
u32 fourcc;
- int depth;
u8 color_swap;
u8 hw_format;
};
@@ -31,9 +30,6 @@ struct rga_frame {
/* Image format */
struct rga_fmt *fmt;
struct v4l2_pix_format_mplane pix;
-
- /* Variables that can calculated once and reused */
- u32 stride;
};
struct rga_dma_desc {
--
2.54.0
^ permalink raw reply related
* [PATCH v6 25/28] media: rockchip: rga: add feature flags
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
In preparation to the RGA3 addition add feature flags, which can limit
the exposed feature set of the video device, like rotating or selection
support. This is necessary as the RGA3 doesn't initially implement the
full feature set currently exposed by the driver.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v6:
- Dropped selection feature, as the RGA3 also has basic support for the
seleciton API. Flagged by Sashiko
https://sashiko.dev/#/patchset/20260428-spu-rga3-v5-0-eb7f5d019d86%40pengutronix.de?part=28
---
drivers/media/platform/rockchip/rga/rga-hw.c | 3 +++
drivers/media/platform/rockchip/rga/rga.c | 20 ++++++++++++--------
drivers/media/platform/rockchip/rga/rga.h | 6 ++++++
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 616ea1bc11311..be1bc8ddbd03b 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -602,6 +602,9 @@ const struct rga_hw rga2_hw = {
.max_height = MAX_HEIGHT,
.max_scaling_factor = MAX_SCALING_FACTOR,
.stride_alignment = 4,
+ .features = RGA_FEATURE_FLIP
+ | RGA_FEATURE_ROTATE
+ | RGA_FEATURE_BG_COLOR,
.setup_cmdbuf = rga_hw_setup_cmdbuf,
.start = rga_hw_start,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 1878b4e26360b..8d60e94da32d8 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -177,17 +177,21 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
- v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (rga->hw->features & RGA_FEATURE_FLIP) {
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ }
- v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
- V4L2_CID_ROTATE, 0, 270, 90, 0);
+ if (rga->hw->features & RGA_FEATURE_ROTATE)
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+ V4L2_CID_ROTATE, 0, 270, 90, 0);
- v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
- V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+ if (rga->hw->features & RGA_FEATURE_BG_COLOR)
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+ V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
if (ctx->ctrl_handler.error) {
int err = ctx->ctrl_handler.error;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index effe364a86b02..feaf40acd4ee4 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -6,6 +6,7 @@
#ifndef __RGA_H__
#define __RGA_H__
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <media/videobuf2-v4l2.h>
@@ -137,6 +138,10 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
rga_write(rga, reg, temp);
};
+#define RGA_FEATURE_FLIP BIT(0)
+#define RGA_FEATURE_ROTATE BIT(1)
+#define RGA_FEATURE_BG_COLOR BIT(2)
+
struct rga_hw {
const char *card_type;
bool has_internal_iommu;
@@ -145,6 +150,7 @@ struct rga_hw {
u32 max_width, max_height;
u8 max_scaling_factor;
u8 stride_alignment;
+ u8 features;
void (*setup_cmdbuf)(struct rga_ctx *ctx);
void (*start)(struct rockchip_rga *rga,
--
2.54.0
^ permalink raw reply related
* [PATCH v6 26/28] media: rockchip: rga: disable multi-core support
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Disable multi-core support in preparation of the RGA3 addition. The
RK3588 SoC features two equal RGA3 cores. This allows scheduling of the
work between both cores, which is not yet implemented. Until it is
implemented avoid exposing both cores as independent video devices to
prevent an ABI breakage when multi-core support is added.
This patch is copied from the Hantro driver patch to disable multi core
support by Sebastian Reichel. See
commit ccdeb8d57f7f ("media: hantro: Disable multicore support")
Link: https://lore.kernel.org/all/20240618183816.77597-4-sebastian.reichel@collabora.com/
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga.c | 47 +++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 8d60e94da32d8..0152b8ef2da2f 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -711,6 +711,49 @@ static int rga_parse_dt(struct rockchip_rga *rga)
return 0;
}
+/*
+ * Some SoCs, like RK3588 have multiple identical RGA3 cores, but the
+ * kernel is currently missing support for multi-core handling. Exposing
+ * separate devices for each core to userspace is bad, since that does
+ * not allow scheduling tasks properly (and creates ABI). With this workaround
+ * the driver will only probe for the first core and early exit for the other
+ * cores. Once the driver gains multi-core support, the same technique
+ * for detecting the main core can be used to cluster all cores together.
+ */
+static int rga_disable_multicore(struct device *dev)
+{
+ struct device_node *node = NULL;
+ const char *compatible;
+ bool is_main_core;
+ int ret;
+
+ /* Intentionally ignores the fallback strings */
+ ret = of_property_read_string(dev->of_node, "compatible", &compatible);
+ if (ret)
+ return ret;
+
+ /* The first compatible and available node found is considered the main core */
+ do {
+ node = of_find_compatible_node(node, NULL, compatible);
+ if (of_device_is_available(node))
+ break;
+ } while (node);
+
+ if (!node)
+ return -EINVAL;
+
+ is_main_core = (dev->of_node == node);
+
+ of_node_put(node);
+
+ if (!is_main_core) {
+ dev_info(dev, "missing multi-core support, ignoring this instance\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int rga_probe(struct platform_device *pdev)
{
struct rockchip_rga *rga;
@@ -721,6 +764,10 @@ static int rga_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENODEV;
+ ret = rga_disable_multicore(&pdev->dev);
+ if (ret)
+ return ret;
+
rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
if (!rga)
return -ENOMEM;
--
2.54.0
^ permalink raw reply related
* [PATCH v6 22/28] media: rockchip: rga: remove size from rga_frame
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
The size member is only used for the mmu page table mapping.
Therefore avoid storing the value and instead only calculate it
in place. This also avoids the calculation entirely when an external
iommu is used.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga-buf.c | 6 +++++-
drivers/media/platform/rockchip/rga/rga.c | 8 ++------
drivers/media/platform/rockchip/rga/rga.h | 1 -
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index cd6904d5fe5a6..092c2bdf6b672 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -79,6 +79,8 @@ static int rga_buf_init(struct vb2_buffer *vb)
struct rockchip_rga *rga = ctx->rga;
struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
size_t n_desc = 0;
+ u32 size = 0;
+ u8 i;
if (IS_ERR(f))
return PTR_ERR(f);
@@ -86,7 +88,9 @@ static int rga_buf_init(struct vb2_buffer *vb)
if (!rga_has_internal_iommu(rga))
return 0;
- n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+ for (i = 0; i < f->pix.num_planes; i++)
+ size += f->pix.plane_fmt[i].sizeimage;
+ n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
rbuf->n_desc = n_desc;
rbuf->dma_desc = dma_alloc_coherent(rga->dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index cda3cecb1ce8c..e44e81814b7cb 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -268,7 +268,6 @@ static int rga_open(struct file *file)
};
def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
- def_frame.size = def_frame.stride * def_height;
ctx = kzalloc_obj(*ctx);
if (!ctx)
@@ -481,9 +480,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
frm = rga_get_frame(ctx, f->type);
if (IS_ERR(frm))
return PTR_ERR(frm);
- frm->size = 0;
- for (i = 0; i < pix_fmt->num_planes; i++)
- frm->size += pix_fmt->plane_fmt[i].sizeimage;
frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
frm->stride = pix_fmt->plane_fmt[0].bytesperline;
@@ -508,10 +504,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
ctx->cmdbuf_dirty = true;
v4l2_dbg(debug, 1, &rga->v4l2_dev,
- "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
+ "[%s] fmt - %p4cc %dx%d (stride %d)\n",
V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
&frm->fmt->fourcc, pix_fmt->width, pix_fmt->height,
- frm->stride, frm->size);
+ frm->stride);
for (i = 0; i < pix_fmt->num_planes; i++) {
v4l2_dbg(debug, 1, &rga->v4l2_dev,
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index b180df5c48370..d47c6821ce2c9 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -34,7 +34,6 @@ struct rga_frame {
/* Variables that can calculated once and reused */
u32 stride;
- u32 size;
};
struct rga_dma_desc {
--
2.54.0
^ permalink raw reply related
* [PATCH v6 16/28] media: rockchip: rga: reuse cmdbuf contents
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Reuse the command buffer contents instead of completely writing it
for every frame. Therefore we only need to replace the source and
destination addresses for each frame. This reduces the amount of CPU
and memory operations done in each frame. A new cmdbuf_dirty flag notes
if the cmdbuf has to be rewritten on the next frame.
The initial idea of initializing the cmdbuf on streamon broke the
ability to update controls while streaming (e.g. mirroring).
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
Changes in v6:
- Reworked the commit to not setup the cmdbuf on streamon but rather
re-initialize it on the next frame when something changed.
- Sasahiko flagged the cmdbuf setup at streamon:
https://sashiko.dev/#/patchset/20260428-spu-rga3-v5-0-eb7f5d019d86%40pengutronix.de?part=17
- Dropped Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
due to the reworked patch and commit message contents
Changes in v5:
- Don't set the flipping and rotation values at streamon and preventing
the userspace from chainging them at runtime
---
drivers/media/platform/rockchip/rga/rga-hw.c | 13 +++++++++----
drivers/media/platform/rockchip/rga/rga.c | 11 +++++++++--
drivers/media/platform/rockchip/rga/rga.h | 2 ++
3 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index dac3cb6aa17d3..567d39e58d33f 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -417,8 +417,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
{
struct rockchip_rga *rga = ctx->rga;
- memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE);
-
rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
/*
* Due to hardware bug,
@@ -427,11 +425,9 @@ static void rga_cmd_set(struct rga_ctx *ctx,
rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
- rga_cmd_set_mode(ctx);
rga_cmd_set_src_info(ctx, &src->offset);
rga_cmd_set_dst_info(ctx, &dst->offset);
- rga_cmd_set_trans_info(ctx);
rga_write(rga, RGA_CMD_BASE, ctx->cmdbuf_phy);
@@ -440,6 +436,14 @@ static void rga_cmd_set(struct rga_ctx *ctx,
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
+static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
+{
+ memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE);
+
+ rga_cmd_set_mode(ctx);
+ rga_cmd_set_trans_info(ctx);
+}
+
static void rga_hw_start(struct rockchip_rga *rga,
struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
@@ -582,6 +586,7 @@ const struct rga_hw rga2_hw = {
.max_height = MAX_HEIGHT,
.stride_alignment = 4,
+ .setup_cmdbuf = rga_hw_setup_cmdbuf,
.start = rga_hw_start,
.handle_irq = rga_handle_irq,
.get_version = rga_get_version,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index d080cb672740b..394b14b9469df 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -38,6 +38,11 @@ static void device_run(void *prv)
unsigned long flags;
spin_lock_irqsave(&rga->ctrl_lock, flags);
+ if (ctx->cmdbuf_dirty) {
+ ctx->cmdbuf_dirty = false;
+ rga->hw->setup_cmdbuf(ctx);
+ }
+ spin_unlock_irqrestore(&rga->ctrl_lock, flags);
rga->curr = ctx;
@@ -47,8 +52,6 @@ static void device_run(void *prv)
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
-
- spin_unlock_irqrestore(&rga->ctrl_lock, flags);
}
static irqreturn_t rga_isr(int irq, void *prv)
@@ -141,6 +144,7 @@ static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
ctx->fill_color = ctrl->val;
break;
}
+ ctx->cmdbuf_dirty = true;
spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
return 0;
}
@@ -228,6 +232,7 @@ static int rga_open(struct file *file)
ret = -ENOMEM;
goto rel_ctx;
}
+ ctx->cmdbuf_dirty = true;
ctx->rga = rga;
/* Set default formats */
@@ -448,6 +453,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
frm->crop.height = pix_fmt->height;
frm->pix = *pix_fmt;
+ ctx->cmdbuf_dirty = true;
v4l2_dbg(debug, 1, &rga->v4l2_dev,
"[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
@@ -564,6 +570,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
}
f->crop = s->r;
+ ctx->cmdbuf_dirty = true;
return ret;
}
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 38518146910a6..5360f092fecf0 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -55,6 +55,7 @@ struct rga_ctx {
void *cmdbuf_virt;
dma_addr_t cmdbuf_phy;
+ bool cmdbuf_dirty;
int osequence;
int csequence;
@@ -152,6 +153,7 @@ struct rga_hw {
u32 max_width, max_height;
u8 stride_alignment;
+ void (*setup_cmdbuf)(struct rga_ctx *ctx);
void (*start)(struct rockchip_rga *rga,
struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
bool (*handle_irq)(struct rockchip_rga *rga);
--
2.54.0
^ permalink raw reply related
* [PATCH v6 11/28] media: rockchip: rga: move hw specific parts to a dedicated struct
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
In preparation for the RGA3 unit, move RGA2 specific parts from rga.c
to rga-hw.c and create a struct to reference the RGA2 specific functions
and formats. This also allows to remove the rga-hw.h reference from the
include list of the rga driver.
Also document the command finish interrupt with a dedicated define.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga-hw.c | 166 ++++++++++++++++++++-
drivers/media/platform/rockchip/rga/rga-hw.h | 5 +-
drivers/media/platform/rockchip/rga/rga.c | 211 +++++----------------------
drivers/media/platform/rockchip/rga/rga.h | 23 ++-
4 files changed, 227 insertions(+), 178 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index ec6c17504ca15..40498796507e0 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -437,8 +437,8 @@ static void rga_cmd_set(struct rga_ctx *ctx,
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
-void rga_hw_start(struct rockchip_rga *rga,
- struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
+static void rga_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
struct rga_ctx *ctx = rga->curr;
@@ -452,3 +452,165 @@ void rga_hw_start(struct rockchip_rga *rga,
rga_write(rga, RGA_CMD_CTRL, 0x1);
}
+
+static bool rga_handle_irq(struct rockchip_rga *rga)
+{
+ int intr;
+
+ intr = rga_read(rga, RGA_INT) & 0xf;
+
+ rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+ return intr & RGA_INT_COMMAND_FINISHED;
+}
+
+static void rga_get_version(struct rockchip_rga *rga)
+{
+ rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+ rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+}
+
+static struct rga_fmt formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .color_swap = RGA_COLOR_ALPHA_SWAP,
+ .hw_format = RGA_COLOR_FMT_ABGR8888,
+ .depth = 32,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_ABGR8888,
+ .depth = 32,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_XBGR8888,
+ .depth = 32,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_RGB888,
+ .depth = 24,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_RGB888,
+ .depth = 24,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB444,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_ABGR4444,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_ABGR1555,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .color_swap = RGA_COLOR_RB_SWAP,
+ .hw_format = RGA_COLOR_FMT_BGR565,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .color_swap = RGA_COLOR_UV_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420SP,
+ .depth = 12,
+ .y_div = 2,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .color_swap = RGA_COLOR_UV_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV422SP,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420SP,
+ .depth = 12,
+ .y_div = 2,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420SP,
+ .depth = 12,
+ .y_div = 2,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV422SP,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420P,
+ .depth = 12,
+ .y_div = 2,
+ .x_div = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV422P,
+ .depth = 16,
+ .y_div = 1,
+ .x_div = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .color_swap = RGA_COLOR_UV_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420P,
+ .depth = 12,
+ .y_div = 2,
+ .x_div = 2,
+ },
+};
+
+const struct rga_hw rga2_hw = {
+ .formats = formats,
+ .num_formats = ARRAY_SIZE(formats),
+ .cmdbuf_size = RGA_CMDBUF_SIZE,
+ .min_width = MIN_WIDTH,
+ .max_width = MAX_WIDTH,
+ .min_height = MIN_HEIGHT,
+ .max_height = MAX_HEIGHT,
+
+ .start = rga_hw_start,
+ .handle_irq = rga_handle_irq,
+ .get_version = rga_get_version,
+};
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
index 2b8537a5fd0d7..c2e34be751939 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -15,9 +15,6 @@
#define MIN_WIDTH 34
#define MIN_HEIGHT 34
-#define DEFAULT_WIDTH 100
-#define DEFAULT_HEIGHT 100
-
#define RGA_TIMEOUT 500
/* Registers address */
@@ -178,6 +175,8 @@
#define RGA_ALPHA_COLOR_NORMAL 0
#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
+#define RGA_INT_COMMAND_FINISHED 4
+
/* Registers union */
union rga_mode_ctrl {
unsigned int val;
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 8c34f73d69764..f599c992829dd 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -25,7 +25,6 @@
#include <media/videobuf2-dma-sg.h>
#include <media/videobuf2-v4l2.h>
-#include "rga-hw.h"
#include "rga.h"
static int debug;
@@ -47,7 +46,7 @@ static void device_run(void *prv)
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
- rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
+ rga->hw->start(rga, vb_to_rga(src), vb_to_rga(dst));
spin_unlock_irqrestore(&rga->ctrl_lock, flags);
}
@@ -55,13 +54,8 @@ static void device_run(void *prv)
static irqreturn_t rga_isr(int irq, void *prv)
{
struct rockchip_rga *rga = prv;
- int intr;
- intr = rga_read(rga, RGA_INT) & 0xf;
-
- rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
-
- if (intr & 0x04) {
+ if (rga->hw->handle_irq(rga)) {
struct vb2_v4l2_buffer *src, *dst;
struct rga_ctx *ctx = rga->curr;
@@ -184,158 +178,17 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
return 0;
}
-static struct rga_fmt formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_ARGB32,
- .color_swap = RGA_COLOR_ALPHA_SWAP,
- .hw_format = RGA_COLOR_FMT_ABGR8888,
- .depth = 32,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_ABGR32,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_ABGR8888,
- .depth = 32,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_XBGR32,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_XBGR8888,
- .depth = 32,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_RGB24,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_RGB888,
- .depth = 24,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_BGR24,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_RGB888,
- .depth = 24,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB444,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_ABGR4444,
- .depth = 16,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB555,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_ABGR1555,
- .depth = 16,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_RGB565,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_BGR565,
- .depth = 16,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV21,
- .color_swap = RGA_COLOR_UV_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
- .y_div = 2,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV61,
- .color_swap = RGA_COLOR_UV_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV422SP,
- .depth = 16,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV12,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
- .y_div = 2,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV12M,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV420SP,
- .depth = 12,
- .y_div = 2,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV16,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV422SP,
- .depth = 16,
- .y_div = 1,
- .x_div = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV420,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV420P,
- .depth = 12,
- .y_div = 2,
- .x_div = 2,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .color_swap = RGA_COLOR_NONE_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV422P,
- .depth = 16,
- .y_div = 1,
- .x_div = 2,
- },
- {
- .fourcc = V4L2_PIX_FMT_YVU420,
- .color_swap = RGA_COLOR_UV_SWAP,
- .hw_format = RGA_COLOR_FMT_YUV420P,
- .depth = 12,
- .y_div = 2,
- .x_div = 2,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-static struct rga_fmt *rga_fmt_find(u32 pixelformat)
+static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
{
unsigned int i;
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].fourcc == pixelformat)
- return &formats[i];
+ for (i = 0; i < rga->hw->num_formats; i++) {
+ if (rga->hw->formats[i].fourcc == pixelformat)
+ return &rga->hw->formats[i];
}
return NULL;
}
-static struct rga_frame def_frame = {
- .crop.left = 0,
- .crop.top = 0,
- .crop.width = DEFAULT_WIDTH,
- .crop.height = DEFAULT_HEIGHT,
- .fmt = &formats[0],
-};
-
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
@@ -350,6 +203,18 @@ static int rga_open(struct file *file)
struct rockchip_rga *rga = video_drvdata(file);
struct rga_ctx *ctx = NULL;
int ret = 0;
+ u32 def_width = clamp(DEFAULT_WIDTH, rga->hw->min_width, rga->hw->max_width);
+ u32 def_height = clamp(DEFAULT_HEIGHT, rga->hw->min_height, rga->hw->max_height);
+ struct rga_frame def_frame = {
+ .crop.left = 0,
+ .crop.top = 0,
+ .crop.width = def_width,
+ .crop.height = def_height,
+ .fmt = &rga->hw->formats[0],
+ };
+
+ def_frame.stride = (def_width * def_frame.fmt->depth) >> 3;
+ def_frame.size = def_frame.stride * def_height;
ctx = kzalloc_obj(*ctx);
if (!ctx)
@@ -360,9 +225,9 @@ static int rga_open(struct file *file)
ctx->out = def_frame;
v4l2_fill_pixfmt_mp(&ctx->in.pix,
- ctx->in.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ ctx->in.fmt->fourcc, def_width, def_height);
v4l2_fill_pixfmt_mp(&ctx->out.pix,
- ctx->out.fmt->fourcc, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ ctx->out.fmt->fourcc, def_width, def_height);
if (mutex_lock_interruptible(&rga->mutex)) {
kfree(ctx);
@@ -429,12 +294,13 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{
+ struct rockchip_rga *rga = video_drvdata(file);
struct rga_fmt *fmt;
- if (f->index >= NUM_FORMATS)
+ if (f->index >= rga->hw->num_formats)
return -EINVAL;
- fmt = &formats[f->index];
+ fmt = &rga->hw->formats[f->index];
f->pixelformat = fmt->fourcc;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
@@ -469,6 +335,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = file_to_rga_ctx(file);
+ const struct rga_hw *hw = ctx->rga->hw;
struct rga_fmt *fmt;
if (V4L2_TYPE_IS_CAPTURE(f->type)) {
@@ -487,14 +354,14 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt->xfer_func = frm->pix.xfer_func;
}
- fmt = rga_fmt_find(pix_fmt->pixelformat);
+ fmt = rga_fmt_find(ctx->rga, pix_fmt->pixelformat);
if (!fmt)
- fmt = &formats[0];
+ fmt = &hw->formats[0];
pix_fmt->width = clamp(pix_fmt->width,
- (u32)MIN_WIDTH, (u32)MAX_WIDTH);
+ hw->min_width, hw->max_width);
pix_fmt->height = clamp(pix_fmt->height,
- (u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
+ hw->min_height, hw->max_height);
v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
pix_fmt->field = V4L2_FIELD_NONE;
@@ -529,7 +396,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
frm->size = 0;
for (i = 0; i < pix_fmt->num_planes; i++)
frm->size += pix_fmt->plane_fmt[i].sizeimage;
- frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
+ frm->fmt = rga_fmt_find(rga, pix_fmt->pixelformat);
frm->stride = pix_fmt->plane_fmt[0].bytesperline;
/*
@@ -660,7 +527,7 @@ static int vidioc_s_selection(struct file *file, void *priv,
if (s->r.left + s->r.width > f->pix.width ||
s->r.top + s->r.height > f->pix.height ||
- s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+ s->r.width < rga->hw->min_width || s->r.height < rga->hw->min_height) {
v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
return -EINVAL;
}
@@ -770,6 +637,10 @@ static int rga_probe(struct platform_device *pdev)
if (!rga)
return -ENOMEM;
+ rga->hw = of_device_get_match_data(&pdev->dev);
+ if (!rga->hw)
+ return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
+
rga->dev = &pdev->dev;
spin_lock_init(&rga->ctrl_lock);
mutex_init(&rga->mutex);
@@ -833,8 +704,7 @@ static int rga_probe(struct platform_device *pdev)
if (ret < 0)
goto rel_m2m;
- rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
- rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+ rga->hw->get_version(rga);
v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
rga->version.major, rga->version.minor);
@@ -842,7 +712,7 @@ static int rga_probe(struct platform_device *pdev)
pm_runtime_put(rga->dev);
/* Create CMD buffer */
- rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+ rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
&rga->cmdbuf_phy, GFP_KERNEL,
DMA_ATTR_WRITE_COMBINE);
if (!rga->cmdbuf_virt) {
@@ -850,9 +720,6 @@ static int rga_probe(struct platform_device *pdev)
goto rel_m2m;
}
- def_frame.stride = (DEFAULT_WIDTH * def_frame.fmt->depth) >> 3;
- def_frame.size = def_frame.stride * DEFAULT_HEIGHT;
-
ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
if (ret) {
v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
@@ -865,7 +732,7 @@ static int rga_probe(struct platform_device *pdev)
return 0;
free_dma:
- dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+ dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
rel_m2m:
v4l2_m2m_release(rga->m2m_dev);
@@ -883,7 +750,7 @@ static void rga_remove(struct platform_device *pdev)
{
struct rockchip_rga *rga = platform_get_drvdata(pdev);
- dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
+ dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
v4l2_info(&rga->v4l2_dev, "Removing\n");
@@ -919,9 +786,11 @@ static const struct dev_pm_ops rga_pm = {
static const struct of_device_id rockchip_rga_match[] = {
{
.compatible = "rockchip,rk3288-rga",
+ .data = &rga2_hw,
},
{
.compatible = "rockchip,rk3399-rga",
+ .data = &rga2_hw,
},
{},
};
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index c4a3905a48f0d..640e510285341 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -14,6 +14,9 @@
#define RGA_NAME "rockchip-rga"
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
struct rga_fmt {
u32 fourcc;
int depth;
@@ -68,6 +71,8 @@ static inline struct rga_ctx *file_to_rga_ctx(struct file *filp)
return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh);
}
+struct rga_hw;
+
struct rockchip_rga {
struct v4l2_device v4l2_dev;
struct v4l2_m2m_dev *m2m_dev;
@@ -88,6 +93,8 @@ struct rockchip_rga {
struct rga_ctx *curr;
dma_addr_t cmdbuf_phy;
void *cmdbuf_virt;
+
+ const struct rga_hw *hw;
};
struct rga_addr_offset {
@@ -138,7 +145,19 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
rga_write(rga, reg, temp);
};
-void rga_hw_start(struct rockchip_rga *rga,
- struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+struct rga_hw {
+ struct rga_fmt *formats;
+ u32 num_formats;
+ size_t cmdbuf_size;
+ u32 min_width, min_height;
+ u32 max_width, max_height;
+
+ void (*start)(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
+ bool (*handle_irq)(struct rockchip_rga *rga);
+ void (*get_version)(struct rockchip_rga *rga);
+};
+
+extern const struct rga_hw rga2_hw;
#endif
--
2.54.0
^ permalink raw reply related
* [PATCH v6 18/28] media: rockchip: rga: use card type to specify rga type
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
In preparation of the RGA3 support add a filed to the rga_hw struct
to specify the desired card type value. This allows the user to
differentiate the RGA2 and RGA3 video device nodes.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/platform/rockchip/rga/rga-hw.c | 1 +
drivers/media/platform/rockchip/rga/rga.c | 4 +++-
drivers/media/platform/rockchip/rga/rga.h | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index f2900812ba76f..43fd023b7571c 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -577,6 +577,7 @@ static struct rga_fmt formats[] = {
};
const struct rga_hw rga2_hw = {
+ .card_type = "rga2",
.formats = formats,
.num_formats = ARRAY_SIZE(formats),
.cmdbuf_size = RGA_CMDBUF_SIZE,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 22954bbae55fc..91775b43ff617 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -354,8 +354,10 @@ static const struct v4l2_file_operations rga_fops = {
static int
vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
{
+ struct rockchip_rga *rga = video_drvdata(file);
+
strscpy(cap->driver, RGA_NAME, sizeof(cap->driver));
- strscpy(cap->card, "rockchip-rga", sizeof(cap->card));
+ strscpy(cap->card, rga->hw->card_type, sizeof(cap->card));
strscpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
return 0;
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index df525c6aea8b6..cee2e75ea89f1 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -149,6 +149,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
};
struct rga_hw {
+ const char *card_type;
struct rga_fmt *formats;
u32 num_formats;
size_t cmdbuf_size;
--
2.54.0
^ permalink raw reply related
* [PATCH v6 04/28] media: v4l2-common: add has_alpha to v4l2_format_info
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Add a has_alpha value to the v4l2_format_info struct to indicate if the
format contains an alpha component. This information can currently not
be queried in a generic way, but might be useful for potential drivers
to properly setup alpha blending to copy or set the alpha value.
The implementation is based on the drm_format_info implementation.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/v4l2-core/v4l2-common.c | 32 ++++++++++++++++----------------
include/media/v4l2-common.h | 2 ++
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index b55ab72958eaa..3cc8b04e1ea63 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -248,26 +248,26 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
/* RGB formats (1 or 2 bytes per pixel) */
{ .format = V4L2_PIX_FMT_RGB332, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XRGB444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_RGBX444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XBGR444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGRA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_BGRX444, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XRGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_RGBX555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XBGR555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGRA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_BGRX555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XRGB555X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@@ -276,24 +276,24 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
{ .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
+ { .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
/* RGB formats (6 or 8 bytes per pixel) */
{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1, .has_alpha = true },
/* HSV formats */
{ .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index f8b1faced79c8..401d8506c24b5 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -520,6 +520,7 @@ enum v4l2_pixel_encoding {
* @vdiv: Vertical chroma subsampling factor
* @block_w: Per-plane macroblock pixel width (optional)
* @block_h: Per-plane macroblock pixel height (optional)
+ * @has_alpha: Does the format embeds an alpha component?
*/
struct v4l2_format_info {
u32 format;
@@ -532,6 +533,7 @@ struct v4l2_format_info {
u8 vdiv;
u8 block_w[4];
u8 block_h[4];
+ bool has_alpha;
};
static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f)
--
2.54.0
^ permalink raw reply related
* [PATCH v6 02/28] media: v4l2-common: sort RGB formats in v4l2_format_info
From: Sven Püschel @ 2026-05-15 15:32 UTC (permalink / raw)
To: Jacob Chen, Ezequiel Garcia, Mauro Carvalho Chehab,
Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Hans Verkuil
Cc: linux-media, linux-rockchip, linux-arm-kernel, linux-kernel,
devicetree, kernel, nicolas, sebastian.reichel, m.tretter,
p.zabel, Sven Püschel, Nicolas Dufresne
In-Reply-To: <20260515-spu-rga3-v6-0-e547152eb9c9@pengutronix.de>
Sort the RGB formats in v4l2_format_info to match the format definitions
in include/uapi/linux/videodev2.h . Also introduce the same sections to
partition the list of formats and align the format info in each section.
The alignment of the 1 or 2 bytes RGB formats contains an additional
space in preparation of adding the missing formats to the list, as for
V4L2_PIX_FMT_ARGB555X an additional space is necessary.
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
---
drivers/media/v4l2-core/v4l2-common.c | 54 +++++++++++++++++++----------------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index bceafc4e92c81..f6cb7e14f2236 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -245,33 +245,39 @@ EXPORT_SYMBOL_GPL(v4l2_s_parm_cap);
const struct v4l2_format_info *v4l2_format_info(u32 format)
{
static const struct v4l2_format_info formats[] = {
- /* RGB formats */
- { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
- { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ /* RGB formats (1 or 2 bytes per pixel) */
+ { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+
+ /* RGB formats (3 or 4 bytes per pixel) */
+ { .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ /* RGB formats (6 or 8 bytes per pixel) */
+ { .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+
+ /* HSV formats */
+ { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+
/* YUV packed formats */
{ .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
--
2.54.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