* Re: [PATCH 3/3] arm64: Sort registers in cpu-feature-registers.rst
From: Catalin Marinas @ 2026-07-02 15:22 UTC (permalink / raw)
To: Mark Brown
Cc: Will Deacon, Jonathan Corbet, Shuah Khan, Peter Maydell,
Joey Gouly, linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20260522-arm64-cpu-ftr-regs-v1-3-19775b40faf0@kernel.org>
On Fri, May 22, 2026 at 06:58:39PM +0100, Mark Brown wrote:
> - ID_AA64PFR0_EL1 - Processor Feature Register 0
> + ID_AA64ISAR1_EL1 - Instruction set attribute register 1
>
> +------------------------------+---------+---------+
> | Name | bits | visible |
> +------------------------------+---------+---------+
> - | DIT | [51-48] | y |
> + | LS64 | [63-60] | y |
> +------------------------------+---------+---------+
> - | MPAM | [43-40] | n |
> + | I8MM | [55-52] | y |
> +------------------------------+---------+---------+
> - | SVE | [35-32] | y |
> + | DGH | [51-48] | y |
> +------------------------------+---------+---------+
> - | GIC | [27-24] | n |
> + | BF16 | [47-44] | y |
> +------------------------------+---------+---------+
> - | AdvSIMD | [23-20] | y |
> + | SB | [39-36] | y |
> +------------------------------+---------+---------+
> - | FP | [19-16] | y |
> + | FRINTTS | [35-32] | y |
> +------------------------------+---------+---------+
> - | EL3 | [15-12] | n |
> + | GPI | [31-28] | y |
> +------------------------------+---------+---------+
> - | EL2 | [11-8] | n |
> + | GPA | [27-24] | y |
> +------------------------------+---------+---------+
> - | EL1 | [7-4] | n |
> + | LRCPC | [23-20] | y |
> +------------------------------+---------+---------+
> - | EL0 | [3-0] | n |
> + | FCMA | [19-16] | y |
> + +------------------------------+---------+---------+
> + | JSCVT | [15-12] | y |
> + +------------------------------+---------+---------+
> + | API | [11-8] | y |
> + +------------------------------+---------+---------+
> + | APA | [7-4] | y |
> + +------------------------------+---------+---------+
> + | DPB | [3-0] | y |
> +------------------------------+---------+---------+
The patch is fine but I just realised that we are really inconsistent
with the non-visible things. We exposed a few hear, I guess in the early
days, and then we stopped, just adding the occasional visible fields.
Shall we drop the 'visible' column altogether and only document the
visible fields here?
--
Catalin
^ permalink raw reply
* Re: [PATCH 2/3] arm64: Document missing bitfields in cpu-feature-registers.rst
From: Catalin Marinas @ 2026-07-02 15:19 UTC (permalink / raw)
To: Mark Brown
Cc: Will Deacon, Jonathan Corbet, Shuah Khan, Peter Maydell,
Joey Gouly, linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20260522-arm64-cpu-ftr-regs-v1-2-19775b40faf0@kernel.org>
On Fri, May 22, 2026 at 06:58:38PM +0100, Mark Brown wrote:
> --- a/Documentation/arch/arm64/cpu-feature-registers.rst
> +++ b/Documentation/arch/arm64/cpu-feature-registers.rst
> @@ -113,6 +113,30 @@ infrastructure:
> 4. List of registers with visible features
> -------------------------------------------
>
> + ID_AA6FPFR0_EL1 - Floating Point feature ID register 0
That's missing a '4' in '64'.
> + ID_AA6SMFR0_EL1 - SME feature ID register 0
Same here.
--
Catalin
^ permalink raw reply
* Re: [PATCH v6 00/20] dma-mapping: Use DMA_ATTR_CC_SHARED through direct, pool and swiotlb paths
From: Jason Gunthorpe @ 2026-07-02 15:19 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Alexey Kardashevskiy, Catalin Marinas, iommu, linux-arm-kernel,
linux-kernel, linux-coco, Robin Murphy, Marek Szyprowski,
Will Deacon, Marc Zyngier, Steven Price, Suzuki K Poulose,
Jiri Pirko, Mostafa Saleh, Petr Tesarik, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <yq5abjcro17x.fsf@kernel.org>
On Wed, Jul 01, 2026 at 08:39:06AM +0530, Aneesh Kumar K.V wrote:
> This is the only code path where we need to special-case host memory
> encryption. For this reason, I have avoided renaming
> io_tlb_mem::cc_shared to io_tlb_mem::unencrypted. I can send a v7 with
> the above and we can review the changes based on that?
I'm OK with this
Jason
^ permalink raw reply
* Re: [PATCH v2] iommu/arm-smmu-v3: Shrink command/event/PRI queues in kdump kernel
From: Jason Gunthorpe @ 2026-07-02 15:17 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: Will Deacon, Robin Murphy, Joerg Roedel, Nicolin Chen,
Kyle McMartin, Breno Leitao, Usama Arif, linux-arm-kernel, iommu,
linux-kernel
In-Reply-To: <20260702112825.781750-1-kas@kernel.org>
On Thu, Jul 02, 2026 at 12:28:25PM +0100, Kiryl Shutsemau (Meta) wrote:
> The command, event and PRI queues are sized from the maxima the hardware
> advertises in IDR1, which can be several megabytes each. On systems with
> many SMMUv3 instances that cost is paid per instance and adds up to tens
> of megabytes of coherent DMA in the capture kernel.
>
> A kdump capture kernel runs from a small crashkernel reservation and only
> has to drive the few devices used to save the dump, so deep queues serve
> no purpose. The queues carry invalidation commands and fault records, not
> DMA data, so dump throughput is unaffected; a shallower queue only bounds
> how many commands may be in flight before a sync, which does not matter for
> the capture kernel's small device count and modest I/O.
>
> Clamp every queue to a single page when is_kdump_kernel() is true. Doing
> it in arm_smmu_init_one_queue() covers the command, event and PRI queues
> in one place. The command queue still holds at least one batch plus a sync
> (256 entries on a 4K-page kernel, well above CMDQ_BATCH_ENTRIES), so
> command batching keeps working.
>
> Suggested-by: Kyle McMartin <jkkm@meta.com>
> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> Reviewed-by: Breno Leitao <leitao@debian.org>
> ---
> v2:
> - Use min() instead of min_t(); both operands are u32 so the cast was
> redundant (Jason Gunthorpe, Breno Leitao).
> - Add Reviewed-by from Breno.
>
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Jason
^ permalink raw reply
* Re: [PATCH v9 0/9] Add support for MT6392 PMIC
From: Lee Jones @ 2026-07-02 15:14 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sen Chu, Sean Wang, Macpaul Lin, Matthias Brugger,
AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
Linus Walleij, Louis-Alexis Eyraud, Val Packett, Julien Massot,
Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>
On Sun, 21 Jun 2026, Luca Leonardo Scorcia wrote:
> The MediaTek MT6392 PMIC is usually found on devices powered by
> the MT8516/MT8167 SoC and is yet another MT6323/MT6397 variant.
The MFD pieces look fine to me.
I'm assuming this will go in via MFD.
Just let me know when you have all of the remaining Acks.
--
Lee Jones
^ permalink raw reply
* Re: [PATCH v4] KVM: arm64: Record whether pKVM stage 2 mapping is cacheable
From: Leonardo Bras @ 2026-07-02 15:13 UTC (permalink / raw)
To: Bradley Morgan
Cc: Leonardo Bras, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Catalin Marinas,
Will Deacon, Quentin Perret, Vincent Donnefort, linux-arm-kernel,
kvmarm, linux-kernel
In-Reply-To: <6495D546-8FC7-4A31-B18C-88F34E1B64BB@grrlz.net>
On Thu, Jul 02, 2026 at 03:52:14PM +0100, Bradley Morgan wrote:
> On July 2, 2026 12:18:58 PM GMT+01:00, Leonardo Bras <leo.bras@arm.com>
> wrote:
> >On Thu, Jul 02, 2026 at 09:59:23AM +0100, Marc Zyngier wrote:
> >> + Vincent, Leo
> >>
> >> On Wed, 01 Jul 2026 20:24:28 +0100,
> >> Bradley Morgan <include@grrlz.net> wrote:
> >> >
> >> > pKVM keeps its own mapping list for stage 2 operations. Its flush path
> >> > uses that list directly, so it lost the PTE attribute check done by
> >the
> >> > generic stage 2 walker.
> >> >
> >> > Record whether a mapping is cacheable and skip cache maintenance for
> >> > mappings that are not cacheable.
> >> >
> >> > Fixes: e912efed485a ("KVM: arm64: Introduce the EL1 pKVM MMU")
> >> > Signed-off-by: Bradley Morgan <include@grrlz.net>
> >> > ---
> >> > Changes since V3:
> >> > - addressed some review :)
> >>
> >> This isn't a change log. If you want to be taken seriously, I'd
> >> suggest you start by following the process. You are otherwise wasting
> >> people's time. Again.
> >
> >Agree... the process has a reason: the changelog here helps the reviewer
> >having an overview of what actually changed between versions, and that
> >makes reviewing much easier, and costs very little to the contributor.
> >
> >Also, the 1 week waiting time is really important, as mentioned before, as
> >it allows more reviewers and maintainers to give feedback: different
> >people, from different companies and lifestyles have different schedules
> >for dev/rev, but in general it happens weekly. So waiting for a week is
> >really recommended, as it tends to avoid people re-reading 2+ versions of
> >the same patchset, and allows revs time to discuss the suggestions in the
> >same thread.
> >
> >(I know the waiting can be really frustating, and that sending a vN+1 fast
> >seems to show that you are interested in it, but it really does not help)
>
> Well, it's fair, let me give you reasoning on why I do quick Rerolls.
>
> So, if I do something wrong, e.g: checkpatch, I don't want to wait a week,
> because I would get grilled for a said checkpatch failure.
>
Fair, but people would not avoid reviewing your new version due to a
checkpath/etc issue. It's common to just report/ignore that and go on with
the code that matters.
Also, checkpath is a good example of what you can run in your code before
sending, so it does not become a respin.
>
> In this case, I was just excited /shrug.
It's okay. Been there as well :)
> >>
> >> You also failed to Cc people who have provided feedback on previous
> >> versions. That's not right.
> >
> >(Bradley: usually you want as many people as possible to review your
> >stuff,
> >so CC'ing previous reviewers is actually good for you)
>
> Vincent not being CCed was dumb of me, no idea how I didn't get him on get
> maintainers.
>
> For you, I didn't want to annoy you with another patch, since maintainers
> tend to be stressed and annoyed. And I didn't wanna add on to the pain.
>
Don't worry on this. Previous reviewers can just ignore the e-mail if
they don't find it interesting anymore.
> >>
> >> >
> >> > arch/arm64/kvm/pkvm.c | 51
> >++++++++++++++++++++++++++++++++++---------
> >> > 1 file changed, 41 insertions(+), 10 deletions(-)
> >> >
> >> > diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> >> > index 053e4f733e4b..6d1cad890c7e 100644
> >> > --- a/arch/arm64/kvm/pkvm.c
> >> > +++ b/arch/arm64/kvm/pkvm.c
> >> > @@ -302,9 +302,32 @@ static u64 __pkvm_mapping_start(struct
> >pkvm_mapping *m)
> >> > return m->gfn * PAGE_SIZE;
> >> > }
> >> >
> >> > +#define PKVM_MAPPING_NR_PAGES_MASK GENMASK_ULL(47, 0)
> >> > +#define PKVM_MAPPING_NC BIT_ULL(48)
> >> > +
> >> > +static u64 pkvm_mapping_nr_pages(struct pkvm_mapping *m)
> >> > +{
> >> > + return m->nr_pages & PKVM_MAPPING_NR_PAGES_MASK;
> >> > +}
> >>
> >> No. You've been pointed to the correct data structure (an anonymous
> >> structure containing bit fields). Please consider taking the review
> >> comments into account.
> >
> >(and if you do not agree with the suggestion, discuss it in the same
> >thread. Although as Marc shows below, it becames much simpler like that)
> >
> >Thanks!
> >Leo
> >
>
> I'll test it. If it's good. I'll do
>
> Suggested-by? Or co-developed by?
I would say none. It's just a change suggestion to your patch, made by a
reviewer.
IIRC 'Suggested-by' is used if someone suggested the idea for the patch,
such as "ah, you should do this thing before", etc. It's both for giving
credit and showing people the idea for that was not yours, for multiple
reasons.
>
> I'll hold the patch on for a week.
>
Good!
If you get too excited, I suggest reading other people's patches. Everybody
makes mistakes, and the solutions / suggestions are really interesting :)
>
> Thanks you lot for taking my bull crap.
>
It's not bad, the process just goes like that for everybody.
It's just slower than people expect :)
We get slightly better over time, but still make mistakes.
(And try our best not to make the same mistakes again :)
Thanks for contributing!
Leo
> >>
> >> This would avoid most of the churn in this patch, and make it easy to
> >> backport. Something like the untested hack below.
> >>
> >> M.
> >>
> >> diff --git a/arch/arm64/include/asm/kvm_pkvm.h
> >b/arch/arm64/include/asm/kvm_pkvm.h
> >> index 74fedd9c5ff02..cdddc9e3a11f5 100644
> >> --- a/arch/arm64/include/asm/kvm_pkvm.h
> >> +++ b/arch/arm64/include/asm/kvm_pkvm.h
> >> @@ -195,7 +195,10 @@ struct pkvm_mapping {
> >> struct rb_node node;
> >> u64 gfn;
> >> u64 pfn;
> >> - u64 nr_pages;
> >> + struct {
> >> + unsigned long nr_pages:48;
> >> + unsigned int nc:1;
> >> + };
> >> u64 __subtree_last; /* Internal member for interval tree */
> >> };
> >>
> >> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> >> index 428723b1b0f5c..5932b93bded58 100644
> >> --- a/arch/arm64/kvm/pkvm.c
> >> +++ b/arch/arm64/kvm/pkvm.c
> >> @@ -369,7 +369,7 @@ static int __pkvm_pgtable_stage2_unshare(struct
> >kvm_pgtable *pgt, u64 start, u64
> >>
> >> for_each_mapping_in_range_safe(pgt, start, end, mapping) {
> >> ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_guest, handle, mapping->gfn,
> >> - mapping->nr_pages);
> >> + (u64)mapping->nr_pages);
> >> if (WARN_ON(ret))
> >> return ret;
> >> pkvm_mapping_remove(mapping, &pgt->pkvm_mappings);
> >> @@ -473,6 +473,7 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt,
> >u64 addr, u64 size,
> >> mapping->gfn = gfn;
> >> mapping->pfn = pfn;
> >> mapping->nr_pages = size / PAGE_SIZE;
> >> + mapping->nc = !!(prot & (KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC));
> >> pkvm_mapping_insert(mapping, &pgt->pkvm_mappings);
> >>
> >> return ret;
> >> @@ -503,7 +504,7 @@ int pkvm_pgtable_stage2_wrprotect(struct kvm_pgtable
> >*pgt, u64 addr, u64 size)
> >> lockdep_assert_held(&kvm->mmu_lock);
> >> for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
> >> ret = kvm_call_hyp_nvhe(__pkvm_host_wrprotect_guest, handle, mapping->gfn,
> >> - mapping->nr_pages);
> >> + (u64)mapping->nr_pages);
> >> if (WARN_ON(ret))
> >> break;
> >> }
> >> @@ -517,10 +518,11 @@ int pkvm_pgtable_stage2_flush(struct kvm_pgtable
> >*pgt, u64 addr, u64 size)
> >> struct pkvm_mapping *mapping;
> >>
> >> lockdep_assert_held(&kvm->mmu_lock);
> >> - for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
> >> - __clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
> >> - PAGE_SIZE * mapping->nr_pages);
> >> -
> >> + for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
> >> + if (!mapping->nc)
> >> + __clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
> >> + PAGE_SIZE * mapping->nr_pages);
> >> + }
> >> return 0;
> >> }
> >>
> >> @@ -537,7 +539,7 @@ bool pkvm_pgtable_stage2_test_clear_young(struct
> >kvm_pgtable *pgt, u64 addr, u64
> >> lockdep_assert_held(&kvm->mmu_lock);
> >> for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
> >> young |= kvm_call_hyp_nvhe(__pkvm_host_test_clear_young_guest, handle, mapping->gfn,
> >> - mapping->nr_pages, mkold);
> >> + (u64)mapping->nr_pages, mkold);
> >>
> >> return young;
> >> }
> >>
> >> --
> >> Without deviation from the norm, progress is not possible.
> >
>
> Thanks!
^ permalink raw reply
* Re: [PATCH] irqchip/gic-v3-its: Reconfigure ITS from software state on resume
From: Thomas Gleixner @ 2026-07-02 15:13 UTC (permalink / raw)
To: Bjoern Doebel, stable, Marc Zyngier, linux-arm-kernel,
linux-kernel, David Woodhouse, Ali Saidi, David Arinzon,
Zeev Zilberman
Cc: Bjoern Doebel
In-Reply-To: <akZPM6SeJiM8th0N@amazon.de>
On Thu, Jul 02 2026 at 11:57, Bjoern Doebel wrote:
> Hi all,
>
> gentle ping on this one.
Marc?
> Since the original posting I've re-validated the fix against current
> mainline:
>
> - It still applies cleanly to v7.2-rc1 (and to v7.1.0).
>
> - I reproduced the original failure on *stock* v7.2-rc1. On EC2
> Graviton instances, hibernation resume fails 100% of the time: the
> ITS comes back reset, MAPD/MAPTI are never replayed, and the ENA
> NIC silently loses its LPIs:
>
> ena 0000:00:05.0: ... didn't receive a MSI-X interrupt (cmd 3)
> ena 0000:00:05.0: Failed to create IO CQ. error: -62
>
> The instance then has no networking after resume.
>
> - With this patch applied, the same kernel survives hibernate/resume
> cleanly: 9/9 cycles with zero failures, across all three Graviton
> generations (Graviton 2/3/4, i.e. Neoverse N1/V1/V2), networking
> fully restored on every resume.
>
> As described in the previous message, this is the fallout from 713335b6ee29
> ("irqchip/gic-v3-its: Implement .msi_teardown() callback"): device
> teardown no longer happens across a suspend/resume that keeps the MSI
> domain, so the ITS is never reprogrammed and drops interrupts after the
> hardware has been reset.
>
> Could you take a look when you get a chance?
>
> Thanks,
> Bjoern
>
>
>
>
> Amazon Web Services Development Center Germany GmbH
> Tamara-Danz-Str. 13
> 10243 Berlin
> Geschaeftsfuehrung: Christof Hellmis, Andreas Stieger
> Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B
> Sitz: Berlin
> Ust-ID: DE 365 538 597
^ permalink raw reply
* [PATCH v8 25/39] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Start with HPD masked, matching RK3588, so the bridge framework controls
when interrupts are armed via hpd_enable().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 3de4b3e6ea85..11ca73ca4caf 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -427,7 +427,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
+ val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v4 5/5] arm64: mpam: Add memory bandwidth usage (MBWU) documentation
From: Ben Horgan @ 2026-07-02 14:58 UTC (permalink / raw)
To: Reinette Chatre
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, rohit.mathew, scott, sdonthineni, tan.shaopeng, xhao,
zengheng4, x86
In-Reply-To: <b2dae9c4-d0b3-4ec2-884a-569020039b5f@intel.com>
Hi Reinette,
On 7/2/26 15:46, Reinette Chatre wrote:
> Hi Ben,
>
> On 7/2/26 2:20 AM, Ben Horgan wrote:
>> On 7/1/26 23:38, Reinette Chatre wrote:
>>> On 5/20/26 2:24 PM, Ben Horgan wrote:
>
> ...
>
>>>> --- a/Documentation/arch/arm64/mpam.rst
>>>> +++ b/Documentation/arch/arm64/mpam.rst
>>>> @@ -65,6 +65,23 @@ The supported features are:
>>>> there is at least one CSU monitor on each MSC that makes up the L3 group.
>>>> Exposing CSU counters from other caches or devices is not supported.
>>>>
>>>> +* Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
>>>> + L3 cache-id to identify where the memory bandwidth is measured. For this
>>>> + reason the platform must have an L3 cache with cache-id's supplied by
>>>> + firmware. (It doesn't need to support MPAM.)
>>>> +
>>>> + Memory bandwidth monitoring makes use of MBWU monitors in each MSC that
>>>> + makes up the L3 group. If the memory bandwidth monitoring is on the memory
>>>> + rather than the L3 then there must be a single global L3 as otherwise it
>>>> + is unknown which L3 the traffic came from.
>>>> +
>>>> + To expose 'mbm_total_bytes', the topology of the group of MSC chosen must
>>>> + match the topology of the L3 cache so that the cache-id's can be
>>>> + repainted. For example: Platforms with Memory bandwidth monitors on
>>>> + CPU-less NUMA nodes cannot expose 'mbm_total_bytes' as these nodes do not
>>>> + have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
>>>> + cannot distinguish local traffic from global traffic.
>>>
>>> Hopefully we can get to a point where memory bandwidth monitoring data from
>>> CPU-less NUMA nodes can be exposed via resctrl. When considering such possible
>>
>> Thank you for your interest here. I hope so too.
>>
>>> future I think it may make this work easier to build on if the documentation
>>> focuses on what the current implementation supports and leave room for
>>> future enhancements by not constraining user space expectation with an absolute
>>> like "CPU-less NUMA nodes cannot expose 'mbm_total_bytes'".
>>
>> The intention was to describe the current limitations but I do see how
>> this can come across as fundamental problems rather than just that we
>> need to do some more work to establish how this can be done and
>> implement it.
>>
>> How about if I add this paragraph at the end?
>>
>> All these restrictions based on L3 cache are due to resctrl, currently,
>> only supporting monitoring at the scope of the L3 scope. It is expected
>
> How about "at L3 scope" instead of "at the scope of the L3 scope"?
Sure, that reads better.
Ben
>
>> that going forward more MBWU monitors can be exposed to the user after
>> support for more monitoring scopes is added to resctrl.
> Looks good to me, thank you.
>
> Reinette
^ permalink raw reply
* [PATCH v8 26/39] drm/rockchip: dw_hdmi_qp: Implement .{enable|disable}_hpd() PHY ops
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Implement .enable_hpd() and .disable_hpd() phy ops for RK3576 and RK3588
SoCs, used by the corresponding bridge callbacks for HPD activation
control.
Consolidate the interrupt clear-and-unmask sequence into enable_hpd()
and the mask-only operation into disable_hpd(), replacing the open-coded
register writes in the interrupt handlers and io_init().
The .setup_hpd() phy op, which was previously called from
dw_hdmi_qp_init_hw(), is no longer needed and its users are removed.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 78 +++++++++++++-------------
1 file changed, 38 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 11ca73ca4caf..c8675f43c687 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -274,7 +274,7 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -289,11 +289,25 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ u32 val;
+
+ if (hdmi->port_id)
+ val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+ else
+ val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
};
static enum drm_connector_status
@@ -308,7 +322,7 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -317,14 +331,22 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+}
+
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
};
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -345,13 +367,12 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -361,15 +382,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -377,16 +394,12 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
if (intr_stat) {
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -396,22 +409,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
-
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- if (hdmi->port_id)
- val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
- else
- val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -424,11 +426,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -453,11 +455,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.54.0
^ permalink raw reply related
* [PATCH v1 2/3] mfd: Initialize spi_device_id arrays using member names
From: Uwe Kleine-König (The Capable Hub) @ 2026-07-02 14:53 UTC (permalink / raw)
To: Lee Jones
Cc: James Ogletree, Fred Treven, Ben Bright, Support Opensource,
Xu Yilun, Tom Rix, Charles Keepax, Richard Fitzgerald,
Maxime Coquelin, Alexandre Torgue, patches, linux-kernel,
linux-sound, linux-stm32, linux-arm-kernel
In-Reply-To: <cover.1783003256.git.u.kleine-koenig@baylibre.com>
While being less compact, using named initializers allows to more easily
see which members of the structs are assigned which value without having
to lookup the declaration of the struct. And it's also more robust
against changes to the struct definition.
The mentioned robustness is relevant for a planned change to struct
spi_device_id that replaces .driver_data by an anonymous union.
Also adapt spacing and usage of commas to the most common style.
This patch doesn't modify the compiled array, only its representation
in source form benefits.
Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
---
drivers/mfd/arizona-spi.c | 12 ++++++------
drivers/mfd/cs40l50-spi.c | 4 ++--
drivers/mfd/da9052-spi.c | 12 ++++++------
drivers/mfd/intel-m10-bmc-spi.c | 6 +++---
drivers/mfd/madera-spi.c | 18 +++++++++---------
drivers/mfd/rsmu_spi.c | 12 ++++++------
drivers/mfd/stmpe-spi.c | 12 ++++++------
drivers/mfd/wm831x-spi.c | 16 ++++++++--------
8 files changed, 46 insertions(+), 46 deletions(-)
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index eaa2b2bc5dd0..04baf5a1c652 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -255,12 +255,12 @@ static void arizona_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id arizona_spi_ids[] = {
- { "wm5102", WM5102 },
- { "wm5110", WM5110 },
- { "wm8280", WM8280 },
- { "wm1831", WM1831 },
- { "cs47l24", CS47L24 },
- { },
+ { .name = "wm5102", .driver_data = WM5102 },
+ { .name = "wm5110", .driver_data = WM5110 },
+ { .name = "wm8280", .driver_data = WM8280 },
+ { .name = "wm1831", .driver_data = WM1831 },
+ { .name = "cs47l24", .driver_data = CS47L24 },
+ { }
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
diff --git a/drivers/mfd/cs40l50-spi.c b/drivers/mfd/cs40l50-spi.c
index 53526b595a0d..a635951ca6b7 100644
--- a/drivers/mfd/cs40l50-spi.c
+++ b/drivers/mfd/cs40l50-spi.c
@@ -40,8 +40,8 @@ static void cs40l50_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id cs40l50_id_spi[] = {
- { "cs40l50" },
- {}
+ { .name = "cs40l50" },
+ { }
};
MODULE_DEVICE_TABLE(spi, cs40l50_id_spi);
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
index be5f2b34e18a..29cf2c17fde1 100644
--- a/drivers/mfd/da9052-spi.c
+++ b/drivers/mfd/da9052-spi.c
@@ -63,12 +63,12 @@ static void da9052_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id da9052_spi_id[] = {
- {"da9052", DA9052},
- {"da9053-aa", DA9053_AA},
- {"da9053-ba", DA9053_BA},
- {"da9053-bb", DA9053_BB},
- {"da9053-bc", DA9053_BC},
- {}
+ { .name = "da9052", .driver_data = DA9052 },
+ { .name = "da9053-aa", .driver_data = DA9053_AA },
+ { .name = "da9053-ba", .driver_data = DA9053_BA },
+ { .name = "da9053-bb", .driver_data = DA9053_BB },
+ { .name = "da9053-bc", .driver_data = DA9053_BC },
+ { }
};
static struct spi_driver da9052_spi_driver = {
diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c
index cfa620f0c70e..94b9c99bb4f8 100644
--- a/drivers/mfd/intel-m10-bmc-spi.c
+++ b/drivers/mfd/intel-m10-bmc-spi.c
@@ -160,9 +160,9 @@ static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
};
static const struct spi_device_id m10bmc_spi_id[] = {
- { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 },
- { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 },
- { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 },
+ { .name = "m10-n3000", .driver_data = (kernel_ulong_t)&m10bmc_spi_n3000 },
+ { .name = "m10-d5005", .driver_data = (kernel_ulong_t)&m10bmc_spi_d5005 },
+ { .name = "m10-n5010", .driver_data = (kernel_ulong_t)&m10bmc_spi_n5010 },
{ }
};
MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c
index ce9e90322c9c..3fffa21ceadc 100644
--- a/drivers/mfd/madera-spi.c
+++ b/drivers/mfd/madera-spi.c
@@ -112,15 +112,15 @@ static void madera_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id madera_spi_ids[] = {
- { "cs47l15", CS47L15 },
- { "cs47l35", CS47L35 },
- { "cs47l85", CS47L85 },
- { "cs47l90", CS47L90 },
- { "cs47l91", CS47L91 },
- { "cs42l92", CS42L92 },
- { "cs47l92", CS47L92 },
- { "cs47l93", CS47L93 },
- { "wm1840", WM1840 },
+ { .name = "cs47l15", .driver_data = CS47L15 },
+ { .name = "cs47l35", .driver_data = CS47L35 },
+ { .name = "cs47l85", .driver_data = CS47L85 },
+ { .name = "cs47l90", .driver_data = CS47L90 },
+ { .name = "cs47l91", .driver_data = CS47L91 },
+ { .name = "cs42l92", .driver_data = CS42L92 },
+ { .name = "cs47l92", .driver_data = CS47L92 },
+ { .name = "cs47l93", .driver_data = CS47L93 },
+ { .name = "wm1840", .driver_data = WM1840 },
{ }
};
MODULE_DEVICE_TABLE(spi, madera_spi_ids);
diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c
index e07f21482439..cdb0f9797ec6 100644
--- a/drivers/mfd/rsmu_spi.c
+++ b/drivers/mfd/rsmu_spi.c
@@ -239,12 +239,12 @@ static void rsmu_spi_remove(struct spi_device *client)
}
static const struct spi_device_id rsmu_spi_id[] = {
- { "8a34000", RSMU_CM },
- { "8a34001", RSMU_CM },
- { "8a34002", RSMU_CM },
- { "82p33810", RSMU_SABRE },
- { "82p33811", RSMU_SABRE },
- {}
+ { .name = "8a34000", .driver_data = RSMU_CM },
+ { .name = "8a34001", .driver_data = RSMU_CM },
+ { .name = "8a34002", .driver_data = RSMU_CM },
+ { .name = "82p33810", .driver_data = RSMU_SABRE },
+ { .name = "82p33811", .driver_data = RSMU_SABRE },
+ { }
};
MODULE_DEVICE_TABLE(spi, rsmu_spi_id);
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
index dea31efface6..22a3da062dee 100644
--- a/drivers/mfd/stmpe-spi.c
+++ b/drivers/mfd/stmpe-spi.c
@@ -121,12 +121,12 @@ static const struct of_device_id stmpe_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, stmpe_spi_of_match);
static const struct spi_device_id stmpe_spi_id[] = {
- { "stmpe610", STMPE610 },
- { "stmpe801", STMPE801 },
- { "stmpe811", STMPE811 },
- { "stmpe1601", STMPE1601 },
- { "stmpe2401", STMPE2401 },
- { "stmpe2403", STMPE2403 },
+ { .name = "stmpe610", .driver_data = STMPE610 },
+ { .name = "stmpe801", .driver_data = STMPE801 },
+ { .name = "stmpe811", .driver_data = STMPE811 },
+ { .name = "stmpe1601", .driver_data = STMPE1601 },
+ { .name = "stmpe2401", .driver_data = STMPE2401 },
+ { .name = "stmpe2403", .driver_data = STMPE2403 },
{ }
};
MODULE_DEVICE_TABLE(spi, stmpe_spi_id);
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 54c87267917b..1e519fd9a9e1 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -77,14 +77,14 @@ static const struct dev_pm_ops wm831x_spi_pm = {
};
static const struct spi_device_id wm831x_spi_ids[] = {
- { "wm8310", WM8310 },
- { "wm8311", WM8311 },
- { "wm8312", WM8312 },
- { "wm8320", WM8320 },
- { "wm8321", WM8321 },
- { "wm8325", WM8325 },
- { "wm8326", WM8326 },
- { },
+ { .name = "wm8310", .driver_data = WM8310 },
+ { .name = "wm8311", .driver_data = WM8311 },
+ { .name = "wm8312", .driver_data = WM8312 },
+ { .name = "wm8320", .driver_data = WM8320 },
+ { .name = "wm8321", .driver_data = WM8321 },
+ { .name = "wm8325", .driver_data = WM8325 },
+ { .name = "wm8326", .driver_data = WM8326 },
+ { }
};
static struct spi_driver wm831x_spi_driver = {
--
2.55.0.11.g153666a7d9bb
^ permalink raw reply related
* [PATCH v1 0/3] mfd: Initialize spi_device_id arrays using member names
From: Uwe Kleine-König (The Capable Hub) @ 2026-07-02 14:53 UTC (permalink / raw)
To: Lee Jones
Cc: Colin Foster, linux-kernel, James Ogletree, Fred Treven,
Ben Bright, Support Opensource, Xu Yilun, Tom Rix, Charles Keepax,
Richard Fitzgerald, Maxime Coquelin, Alexandre Torgue, patches,
linux-sound, linux-stm32, linux-arm-kernel, Orson Zhai,
Baolin Wang, Chunyan Zhang
Hello,
this series targets to use named initializers for spi_device_id arrays.
In general these are better readable for humans and more robust to
changes in the respective struct definition.
This robustness is needed as I want to do
diff --git a/include/linux/device-id/spi.h b/include/linux/device-id/spi.h
index 812e7c3854a7..93d9cd45569a 100644
--- a/include/linux/device-id/spi.h
+++ b/include/linux/device-id/spi.h
@@ -13,7 +13,11 @@ typedef unsigned long kernel_ulong_t;
struct spi_device_id {
char name[SPI_NAME_SIZE];
- kernel_ulong_t driver_data; /* Data private to the driver */
+ union {
+ /* Data private to the driver */
+ kernel_ulong_t driver_data;
+ const void *driver_data_ptr;
+ };
};
#endif /* ifndef LINUX_MOD_DEVICE_ID_SPI_H */
which allows dropping several casts and eases porting CHERI to mainline
Linux. A possible follow-up change is the following example:
diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c
index 94b9c99bb4f8..28a3cc84b778 100644
--- a/drivers/mfd/intel-m10-bmc-spi.c
+++ b/drivers/mfd/intel-m10-bmc-spi.c
@@ -70,7 +70,7 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi)
if (!ddata)
return -ENOMEM;
- info = (struct intel_m10bmc_platform_info *)id->driver_data;
+ info = id->driver_data_ptr;
ddata->dev = dev;
ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
@@ -160,9 +160,9 @@ static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
};
static const struct spi_device_id m10bmc_spi_id[] = {
- { .name = "m10-n3000", .driver_data = (kernel_ulong_t)&m10bmc_spi_n3000 },
- { .name = "m10-d5005", .driver_data = (kernel_ulong_t)&m10bmc_spi_d5005 },
- { .name = "m10-n5010", .driver_data = (kernel_ulong_t)&m10bmc_spi_n5010 },
+ { .name = "m10-n3000", .driver_data_ptr = &m10bmc_spi_n3000 },
+ { .name = "m10-d5005", .driver_data_ptr = &m10bmc_spi_d5005 },
+ { .name = "m10-n5010", .driver_data_ptr = &m10bmc_spi_n5010 },
{ }
};
MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
increasing readability due to less explicit casting. This also yields
tighter type checking as the assignment in the first hunk results in a
warning if info wasn't a pointer to a const type.
If you consider the last patch mostly churn, just drop it.
There are no dependencies between the patches, and they are merge window
material.
Best regards
Uwe
Uwe Kleine-König (The Capable Hub) (3):
mfd: Drop unused assignment of spi_device_id driver data
mfd: Initialize spi_device_id arrays using member names
mfd: Unify style of spi_device_id arrays
drivers/mfd/altera-a10sr.c | 2 +-
drivers/mfd/arizona-spi.c | 12 ++++++------
drivers/mfd/cs40l50-spi.c | 4 ++--
drivers/mfd/da9052-spi.c | 12 ++++++------
drivers/mfd/intel-m10-bmc-spi.c | 6 +++---
drivers/mfd/madera-spi.c | 18 +++++++++---------
drivers/mfd/motorola-cpcap.c | 6 +++---
drivers/mfd/ocelot-spi.c | 2 +-
drivers/mfd/rk8xx-spi.c | 2 +-
drivers/mfd/rsmu_spi.c | 12 ++++++------
drivers/mfd/sprd-sc27xx-spi.c | 2 +-
drivers/mfd/stmpe-spi.c | 12 ++++++------
drivers/mfd/tps65912-spi.c | 2 +-
drivers/mfd/wm831x-spi.c | 16 ++++++++--------
14 files changed, 54 insertions(+), 54 deletions(-)
base-commit: 4f441960e691d37c880d2cc004de06bb5b6bd5e4
--
2.55.0.11.g153666a7d9bb
^ permalink raw reply
* Re: [PATCH v4] KVM: arm64: Record whether pKVM stage 2 mapping is cacheable
From: Bradley Morgan @ 2026-07-02 14:52 UTC (permalink / raw)
To: Leonardo Bras, Marc Zyngier
Cc: Oliver Upton, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Quentin Perret, Vincent Donnefort, linux-arm-kernel, kvmarm,
linux-kernel
In-Reply-To: <akZJIm6mTza7qAuu@LeoBrasDK>
On July 2, 2026 12:18:58 PM GMT+01:00, Leonardo Bras <leo.bras@arm.com>
wrote:
>On Thu, Jul 02, 2026 at 09:59:23AM +0100, Marc Zyngier wrote:
>> + Vincent, Leo
>>
>> On Wed, 01 Jul 2026 20:24:28 +0100,
>> Bradley Morgan <include@grrlz.net> wrote:
>> >
>> > pKVM keeps its own mapping list for stage 2 operations. Its flush path
>> > uses that list directly, so it lost the PTE attribute check done by
>the
>> > generic stage 2 walker.
>> >
>> > Record whether a mapping is cacheable and skip cache maintenance for
>> > mappings that are not cacheable.
>> >
>> > Fixes: e912efed485a ("KVM: arm64: Introduce the EL1 pKVM MMU")
>> > Signed-off-by: Bradley Morgan <include@grrlz.net>
>> > ---
>> > Changes since V3:
>> > - addressed some review :)
>>
>> This isn't a change log. If you want to be taken seriously, I'd
>> suggest you start by following the process. You are otherwise wasting
>> people's time. Again.
>
>Agree... the process has a reason: the changelog here helps the reviewer
>having an overview of what actually changed between versions, and that
>makes reviewing much easier, and costs very little to the contributor.
>
>Also, the 1 week waiting time is really important, as mentioned before, as
>it allows more reviewers and maintainers to give feedback: different
>people, from different companies and lifestyles have different schedules
>for dev/rev, but in general it happens weekly. So waiting for a week is
>really recommended, as it tends to avoid people re-reading 2+ versions of
>the same patchset, and allows revs time to discuss the suggestions in the
>same thread.
>
>(I know the waiting can be really frustating, and that sending a vN+1 fast
>seems to show that you are interested in it, but it really does not help)
Well, it's fair, let me give you reasoning on why I do quick Rerolls.
So, if I do something wrong, e.g: checkpatch, I don't want to wait a week,
because I would get grilled for a said checkpatch failure.
In this case, I was just excited /shrug.
>>
>> You also failed to Cc people who have provided feedback on previous
>> versions. That's not right.
>
>(Bradley: usually you want as many people as possible to review your
>stuff,
>so CC'ing previous reviewers is actually good for you)
Vincent not being CCed was dumb of me, no idea how I didn't get him on get
maintainers.
For you, I didn't want to annoy you with another patch, since maintainers
tend to be stressed and annoyed. And I didn't wanna add on to the pain.
>>
>> >
>> > arch/arm64/kvm/pkvm.c | 51
>++++++++++++++++++++++++++++++++++---------
>> > 1 file changed, 41 insertions(+), 10 deletions(-)
>> >
>> > diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
>> > index 053e4f733e4b..6d1cad890c7e 100644
>> > --- a/arch/arm64/kvm/pkvm.c
>> > +++ b/arch/arm64/kvm/pkvm.c
>> > @@ -302,9 +302,32 @@ static u64 __pkvm_mapping_start(struct
>pkvm_mapping *m)
>> > return m->gfn * PAGE_SIZE;
>> > }
>> >
>> > +#define PKVM_MAPPING_NR_PAGES_MASK GENMASK_ULL(47, 0)
>> > +#define PKVM_MAPPING_NC BIT_ULL(48)
>> > +
>> > +static u64 pkvm_mapping_nr_pages(struct pkvm_mapping *m)
>> > +{
>> > + return m->nr_pages & PKVM_MAPPING_NR_PAGES_MASK;
>> > +}
>>
>> No. You've been pointed to the correct data structure (an anonymous
>> structure containing bit fields). Please consider taking the review
>> comments into account.
>
>(and if you do not agree with the suggestion, discuss it in the same
>thread. Although as Marc shows below, it becames much simpler like that)
>
>Thanks!
>Leo
>
I'll test it. If it's good. I'll do
Suggested-by? Or co-developed by?
I'll hold the patch on for a week.
Thanks you lot for taking my bull crap.
>>
>> This would avoid most of the churn in this patch, and make it easy to
>> backport. Something like the untested hack below.
>>
>> M.
>>
>> diff --git a/arch/arm64/include/asm/kvm_pkvm.h
>b/arch/arm64/include/asm/kvm_pkvm.h
>> index 74fedd9c5ff02..cdddc9e3a11f5 100644
>> --- a/arch/arm64/include/asm/kvm_pkvm.h
>> +++ b/arch/arm64/include/asm/kvm_pkvm.h
>> @@ -195,7 +195,10 @@ struct pkvm_mapping {
>> struct rb_node node;
>> u64 gfn;
>> u64 pfn;
>> - u64 nr_pages;
>> + struct {
>> + unsigned long nr_pages:48;
>> + unsigned int nc:1;
>> + };
>> u64 __subtree_last; /* Internal member for interval tree */
>> };
>>
>> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
>> index 428723b1b0f5c..5932b93bded58 100644
>> --- a/arch/arm64/kvm/pkvm.c
>> +++ b/arch/arm64/kvm/pkvm.c
>> @@ -369,7 +369,7 @@ static int __pkvm_pgtable_stage2_unshare(struct
>kvm_pgtable *pgt, u64 start, u64
>>
>> for_each_mapping_in_range_safe(pgt, start, end, mapping) {
>> ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_guest, handle, mapping->gfn,
>> - mapping->nr_pages);
>> + (u64)mapping->nr_pages);
>> if (WARN_ON(ret))
>> return ret;
>> pkvm_mapping_remove(mapping, &pgt->pkvm_mappings);
>> @@ -473,6 +473,7 @@ int pkvm_pgtable_stage2_map(struct kvm_pgtable *pgt,
>u64 addr, u64 size,
>> mapping->gfn = gfn;
>> mapping->pfn = pfn;
>> mapping->nr_pages = size / PAGE_SIZE;
>> + mapping->nc = !!(prot & (KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC));
>> pkvm_mapping_insert(mapping, &pgt->pkvm_mappings);
>>
>> return ret;
>> @@ -503,7 +504,7 @@ int pkvm_pgtable_stage2_wrprotect(struct kvm_pgtable
>*pgt, u64 addr, u64 size)
>> lockdep_assert_held(&kvm->mmu_lock);
>> for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
>> ret = kvm_call_hyp_nvhe(__pkvm_host_wrprotect_guest, handle, mapping->gfn,
>> - mapping->nr_pages);
>> + (u64)mapping->nr_pages);
>> if (WARN_ON(ret))
>> break;
>> }
>> @@ -517,10 +518,11 @@ int pkvm_pgtable_stage2_flush(struct kvm_pgtable
>*pgt, u64 addr, u64 size)
>> struct pkvm_mapping *mapping;
>>
>> lockdep_assert_held(&kvm->mmu_lock);
>> - for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
>> - __clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
>> - PAGE_SIZE * mapping->nr_pages);
>> -
>> + for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
>> + if (!mapping->nc)
>> + __clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
>> + PAGE_SIZE * mapping->nr_pages);
>> + }
>> return 0;
>> }
>>
>> @@ -537,7 +539,7 @@ bool pkvm_pgtable_stage2_test_clear_young(struct
>kvm_pgtable *pgt, u64 addr, u64
>> lockdep_assert_held(&kvm->mmu_lock);
>> for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
>> young |= kvm_call_hyp_nvhe(__pkvm_host_test_clear_young_guest, handle, mapping->gfn,
>> - mapping->nr_pages, mkold);
>> + (u64)mapping->nr_pages, mkold);
>>
>> return young;
>> }
>>
>> --
>> Without deviation from the norm, progress is not possible.
>
Thanks!
^ permalink raw reply
* Re: [PATCH v6 03/20] dma-direct: use DMA_ATTR_CC_SHARED in alloc/free paths
From: Jason Gunthorpe @ 2026-07-02 14:47 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: Aneesh Kumar K.V (Arm), iommu, linux-arm-kernel, linux-kernel,
linux-coco, Robin Murphy, Marek Szyprowski, Will Deacon,
Marc Zyngier, Steven Price, Suzuki K Poulose, Catalin Marinas,
Jiri Pirko, Mostafa Saleh, Petr Tesarik, Dan Williams, Xu Yilun,
linuxppc-dev, linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86, Jiri Pirko,
Michael Kelley, Cheloha, Scott
In-Reply-To: <98800d21-18f6-44d6-9ba0-da9b77567d85@amd.com>
On Thu, Jul 02, 2026 at 10:25:16AM +1000, Alexey Kardashevskiy wrote:
> > > not externally available so I'll have to trick the DMA layer into
> > > using SWIOTLB (which is still all shared, right?) as I specifically
> > > want to skip page conversions. Setting low DMA mask won't guarantee
> > > that the DMA layer won't allocate a page outside of SWIOTLB and
> > > convert it. Manually do
> >
> > Why so particular?
>
> aahhh I missed "pre-". I need a way to get pre-shared pages for my
> sev-guest activities.
It sounds to me like you don't, what you are worried about is
optimizing the dma_alloc_coherent flow to avoid fragmentation and all
CC architetures require this optimization.
So I'm strongly against you trying to open code something in your
driver. Use the DMA API as-is. Propose general DMA API improvements to
reduce the fragmentation problem. It is a real problem.
Jason
^ permalink raw reply
* [PATCH v8 36/39] drm/tests: edid: Add 4K@60Hz EDID with 600MHz TMDS
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Add a new test EDID advertising the following capabilities:
Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
Max BPC: 16
Max TMDS clock: 600 MHz
This is needed to exercise the new HDMI infrastructure that decides
whether scrambling needs to be enabled for a given display mode and
to validate that high-rate modes are properly rejected/accepted
depending on the source/sink scrambling capability.
The EDID is derived from test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz
with the following changes:
- Upgraded the first DTD from 3840x2160@30 (297 MHz) to 3840x2160@60
(594 MHz). The H/V totals (4400x2250) and porches already match the
HDMI 2.0 4K@60Hz standard timing, so only the pixel clock had to be
bumped.
- Widened Display Range Limits descriptor to cover the new timing, i.e.
24-140 kHz H, max dotclock 600 MHz.
- Updated CTA-861 Video Data Block to advertise VIC 97 (4K@60Hz) instead
of VIC 95 (4k30).
- Bumped HF-VSDB Max TMDS Character Rate to 600 MHz, keeping
SCDC_Present set so that the sink advertises scrambling support.
- Cleared HDMI VSDB Max TMDS clock byte, as required by HDMI 2.0 when
the HF-VSDB declares a Max TMDS Character Rate above 340 MHz.
- Provided a Video Capability Data Block advertising selectable RGB and
YCC quantization range plus underscan for IT/CE formats; also set the
'IT Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Aligned base block image size with the DTD (160x90 cm) and replaced
the bogus 'Week of Manufacture = 0xff' with the Model Year code, both
fixing inherited EDID conformity warnings.
- Dropped the empty YCbCr 4:2:0 Video Data Block inherited from the
parent EDID, which is flagged as a failure by edid-decode v1.33.0
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.c | 129 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/tests/drm_kunit_edid.h | 1 +
2 files changed, 130 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index c807ae0d9faa..673a0ea8c2ae 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -990,6 +990,135 @@ const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+/*
+ * Max resolution: 3840x2160@60Hz with RGB, YUV444, YUV422, YUV420
+ * Max BPC: 16 for all modes
+ * Max TMDS clock: 600 MHz
+ *
+ * edid-decode (hex):
+ *
+ * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
+ * 00 23 01 03 80 a0 5a 78 0f ee 91 a3 54 4c 99 26
+ * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
+ * 01 01 01 01 01 01 08 e8 00 30 f2 70 5a 80 b0 58
+ * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
+ * 55 18 8c 3c 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 a9
+ *
+ * 02 03 28 b1 41 61 6c 03 0c 00 10 00 78 00 20 00
+ * 00 01 03 6d d8 5d c4 01 78 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54
+ *
+ * ----------------
+ *
+ * Block 0, Base EDID:
+ * EDID Structure Version & Revision: 1.3
+ * Vendor & Product Identification:
+ * Manufacturer: LNX
+ * Model: 52
+ * Made in: 2025
+ * Basic Display Parameters & Features:
+ * Digital display
+ * Maximum image size: 160 cm x 90 cm
+ * Gamma: 2.20
+ * RGB color display
+ * Default (sRGB) color space is primary color space
+ * First detailed timing is the preferred timing
+ * Supports GTF timings within operating range
+ * Color Characteristics:
+ * Red : 0.6396, 0.3300
+ * Green: 0.2998, 0.5996
+ * Blue : 0.1503, 0.0595
+ * White: 0.3125, 0.3291
+ * Established Timings I & II:
+ * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
+ * Standard Timings: none
+ * Detailed Timing Descriptors:
+ * DTD 1: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz (1600 mm x 900 mm)
+ * Hfront 176 Hsync 88 Hback 296 Hpol P
+ * Vfront 8 Vsync 10 Vback 72 Vpol P
+ * Display Product Name: 'Test EDID'
+ * Display Range Limits:
+ * Monitor ranges (GTF): 24-85 Hz V, 24-140 kHz H, max dotclock 600 MHz
+ * Dummy Descriptor:
+ * Extension blocks: 1
+ * Checksum: 0xa9
+ *
+ * ----------------
+ *
+ * Block 1, CTA-861 Extension Block:
+ * Revision: 3
+ * Underscans IT Video Formats by default
+ * Supports YCbCr 4:4:4
+ * Supports YCbCr 4:2:2
+ * Native detailed modes: 1
+ * Video Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
+ * Source physical address: 1.0.0.0
+ * DC_48bit
+ * DC_36bit
+ * DC_30bit
+ * DC_Y444
+ * Maximum TMDS clock: 0 MHz
+ * Extended HDMI video details:
+ * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
+ * Version: 1
+ * Maximum TMDS Character Rate: 600 MHz
+ * SCDC Present
+ * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
+ * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
+ * YCbCr 4:2:0 Capability Map Data Block:
+ * VIC 97: 3840x2160 60.000000 Hz 16:9 135.000 kHz 594.000000 MHz
+ * Checksum: 0x54 Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * EDID conformity: PASS
+ */
+const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0xa0, 0x5a, 0x78,
+ 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
+ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8, 0x00, 0x30, 0xf2, 0x70,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
+ 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
+ 0x55, 0x18, 0x8c, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa9, 0x02, 0x03, 0x28, 0xb1,
+ 0x41, 0x61, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x78, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x54,
+};
+EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_DESCRIPTION("EDID Definitions for KUnit tests");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 28b4df93a555..fb5b0295e35e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -12,5 +12,6 @@ extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[256];
extern const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[256];
extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[256];
+extern const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[256];
#endif // DRM_KUNIT_EDID_H_
--
2.54.0
^ permalink raw reply related
* [PATCH v8 38/39] drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
The test EDID added by commit 58fe1d78605e ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with YUV420 only") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
EDID:
Base EDID: Some timings are out of range of the Monitor Ranges:
Maximum Clock: 297.000 MHz (Monitor: 170.000 MHz)
CTA-861: Multiple native progressive timings are defined.
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Capability Map Data Block: Empty Capability Map.
YCbCr 4:2:0 Video Data Block: YCbCr 4:2:0-only VIC 95 is also a regular VIC.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
CTA-861: The maximum HDMI TMDS clock is 200000 kHz, but one or more video timings go up to 297000 kHz.
Address them while preserving the advertised maximum resolutions, BPC
and TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 200 MHz as
Max TMDS Clock.
- VIC 95 (3840x2160@30Hz) was reported as YUV420-only but was listed in
both the regular Video Data Block and the YCbCr 4:2:0 Video Data
Block. Drop it from the regular VDB (so it stays advertised in the
4:2:0 VDB only) and remove the now unnecessary empty YCbCr 4:2:0
Capability Map Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
- Bump the Display Range Limits max pixel clock from 170 MHz to 300 MHz
so it covers the 297 MHz pixel rate of VIC 95.
- Drop the 'native' flag from VIC 16 in the Video Data Block so it is no
longer flagged as a second native progressive timing alongside the
preferred DTD.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.c | 65 +++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 673a0ea8c2ae..4dff28fff796 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -766,22 +766,22 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c
* 45 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
- * 55 18 5e 11 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 bb
+ * 55 18 5e 1e 00 0a 20 20 20 20 20 20 00 00 00 10
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ad
*
- * 02 03 29 31 42 90 5f 6c 03 0c 00 10 00 78 28 20
- * 00 00 01 03 6d d8 5d c4 01 28 80 07 00 00 00 00
- * 00 00 e3 0f 00 00 e2 0e 5f 00 00 00 00 00 00 00
+ * 02 03 27 b1 41 10 6c 03 0c 00 10 00 78 28 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e2 0e 5f 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ca
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9a
*
* ----------------
*
@@ -790,7 +790,7 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -813,21 +813,21 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
* Vfront 4 Vsync 5 Vback 36 Vpol P
* Display Product Name: 'Test EDID'
* Display Range Limits:
- * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 170 MHz
+ * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 300 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xbb
+ * Checksum: 0xad
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
* Video Data Block:
- * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (native)
- * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
+ * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz
* Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
* Source physical address: 1.0.0.0
* DC_48bit
@@ -838,40 +838,57 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 200 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
- * YCbCr 4:2:0 Capability Map Data Block:
- * Empty Capability Map
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Video Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * Checksum: 0xca
+ * Checksum: 0x9a Unused space in Extension Block: 88 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38,
0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
- 0x55, 0x18, 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x55, 0x18, 0x5e, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbb, 0x02, 0x03, 0x29, 0x31,
- 0x42, 0x90, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20,
- 0x00, 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x28, 0x80, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x00, 0x00, 0xe2, 0x0e,
- 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xad, 0x02, 0x03, 0x27, 0xb1,
+ 0x41, 0x10, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe2, 0x0e, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xca
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x9a,
};
EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
--
2.54.0
^ permalink raw reply related
* [PATCH v8 37/39] drm/tests: hdmi_state_helper: Cover source-side scrambling decision
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Add two atomic-check cases that initialise an HDMI 2.0 connector via
drm_connector_hdmi_caps (so the core infers scrambler_supported and the
600 MHz TMDS limit) and assert that conn_state->hdmi.scrambler_needed
stays clear for a 1080p@60 CEA mode (~148.5 MHz TMDS) and is set for the
4K@60 RGB preferred mode (~594 MHz TMDS), straddling the 340 MHz
threshold.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 160 +++++++++++++++++++++
1 file changed, 160 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index b8ae5fad2794..7cd6bd422b0b 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -20,6 +20,8 @@
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
+#include <linux/hdmi.h>
+
#include "../drm_crtc_internal.h"
#include <kunit/test.h>
@@ -194,6 +196,29 @@ static const struct drm_connector_hdmi_funcs accept_connector_hdmi_funcs = {
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs scrambler_connector_hdmi_funcs = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -2265,6 +2290,139 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+/*
+ * Test that on an HDMI connector with source+sink scrambling support, driving
+ * a sub-340 MHz CEA mode, we end up with scrambler_needed cleared.
+ */
+static void drm_test_check_scrambler_needed_low_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *low_rate_mode;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ low_rate_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+ KUNIT_ASSERT_NOT_NULL(test, low_rate_mode);
+
+ rate = drm_hdmi_compute_mode_clock(low_rate_mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_LT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ low_rate_mode, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_LE(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that on an HDMI connector with source+sink scrambling support, driving
+ * the 4K@60 RGB preferred mode (~594 MHz TMDS, above the 340 MHz threshold),
+ * we end up with scrambler_needed set.
+ */
+static void drm_test_check_scrambler_needed_high_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ unsigned long long rate;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &scrambler_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+ info = &conn->display_info;
+ KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+ KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+ KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+ preferred, &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+ KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+ KUNIT_EXPECT_TRUE(test, conn_state->hdmi.scrambler_needed);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
struct color_format_test_param {
enum drm_connector_color_format fmt;
enum drm_output_color_format expected;
@@ -2505,6 +2663,8 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+ KUNIT_CASE(drm_test_check_scrambler_needed_low_rate),
+ KUNIT_CASE(drm_test_check_scrambler_needed_high_rate),
KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format,
check_hdmi_color_format_gen_params),
KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only,
--
2.54.0
^ permalink raw reply related
* [PATCH v8 39/39] drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
The test EDID added by commit 54a5f1c4d5f8 ("drm/tests: hdmi: Provide
EDID supporting 4K@30Hz with RGB/YUV") fails 'edid-decode --check'
(v1.33.0) with the following issues:
Warnings:
Block 1, CTA-861 Extension Block:
IT Video Formats are overscanned by default, but normally this should be underscanned.
YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
(which requires an RGB timings pixel rate >= 590 MHz).
Failures:
Block 0, Base EDID:
Vendor & Product Identification: EDID 1.3 does not support week 0xff.
Detailed Timing Descriptor #1: Mismatch of image size 1600x900 mm vs display size 960x540 mm.
Block 1, CTA-861 Extension Block:
Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
YCbCr 4:2:0 Video Data Block: This Data Block is empty.
Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
EDID:
Base EDID: The DTD max image size is 1600x900mm, which is larger than the display size 960.0x540.0mm.
Address them while preserving the advertised maximum resolution, BPC and
TMDS clock used by the existing KUnit tests:
- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
year field becomes a regular Year of Manufacture.
- Align the DTD image size with the Basic Display Parameters maximum
image size (96 cm x 54 cm).
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
above 340 MHz is supported. The HDMI VSDB still advertises 340 MHz as
Max TMDS Clock.
- Drop the empty YCbCr 4:2:0 Video Data Block. VIC 95 (3840x2160@30Hz)
remains advertised as YUV420-capable via the YCbCr 4:2:0 Capability
Map Data Block, which references the corresponding entry in the
regular Video Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
quantization range plus underscan for IT/CE formats; also set the 'IT
Video Formats Underscanned' bit in the CTA-861 extension header to
match.
The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_kunit_edid.c | 57 ++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.c b/drivers/gpu/drm/tests/drm_kunit_edid.c
index 4dff28fff796..a6c5e8d6077a 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.c
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.c
@@ -900,22 +900,22 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
* edid-decode (hex):
*
* 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
* 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
* 01 01 01 01 01 01 04 74 00 30 f2 70 5a 80 b0 58
- * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 8a 00 c0 1c 32 00 00 1e 00 00 00 fc 00 54 65 73
* 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
* 55 18 5e 22 00 0a 20 20 20 20 20 20 00 00 00 10
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ce
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 e6
*
- * 02 03 27 31 41 5f 6c 03 0c 00 10 00 78 44 20 00
- * 00 01 03 6d d8 5d c4 01 44 80 07 00 00 00 00 00
- * 00 e3 0f 01 00 e1 0e 00 00 00 00 00 00 00 00 00
+ * 02 03 28 b1 41 5f 6c 03 0c 00 10 00 78 44 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8a
*
* ----------------
*
@@ -924,7 +924,7 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
* Vendor & Product Identification:
* Manufacturer: LNX
* Model: 52
- * Model year: 2025
+ * Made in: 2025
* Basic Display Parameters & Features:
* Digital display
* Maximum image size: 96 cm x 54 cm
@@ -942,7 +942,7 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
* DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
* Standard Timings: none
* Detailed Timing Descriptors:
- * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (1600 mm x 900 mm)
+ * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (960 mm x 540 mm)
* Hfront 176 Hsync 88 Hback 296 Hpol P
* Vfront 8 Vsync 10 Vback 72 Vpol P
* Display Product Name: 'Test EDID'
@@ -950,12 +950,13 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
* Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 340 MHz
* Dummy Descriptor:
* Extension blocks: 1
- * Checksum: 0xce
+ * Checksum: 0xe6
*
* ----------------
*
* Block 1, CTA-861 Extension Block:
* Revision: 3
+ * Underscans IT Video Formats by default
* Supports YCbCr 4:4:4
* Supports YCbCr 4:2:2
* Native detailed modes: 1
@@ -971,31 +972,49 @@ EXPORT_SYMBOL(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
* Extended HDMI video details:
* Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
* Version: 1
- * Maximum TMDS Character Rate: 340 MHz
* SCDC Present
* Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
* Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ * VRRmin: 0 Hz
+ * VRRmax: 0 Hz
+ * Video Capability Data Block:
+ * YCbCr quantization: Selectable (via AVI YQ)
+ * RGB quantization: Selectable (via AVI Q)
+ * PT scan behavior: No Data
+ * IT scan behavior: Always Underscanned
+ * CE scan behavior: Always Underscanned
* YCbCr 4:2:0 Capability Map Data Block:
* VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
- * YCbCr 4:2:0 Video Data Block:
- * Checksum: 0x84
+ * Checksum: 0x8a Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ * YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ * (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
*/
const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70,
- 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+ 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e,
0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
0x55, 0x18, 0x5e, 0x22, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0x02, 0x03, 0x27, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe6, 0x02, 0x03, 0x28, 0xb1,
0x41, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00,
- 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x44, 0x80, 0x07, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x01, 0x00, 0xe1, 0x0e, 0x00,
+ 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1003,7 +1022,7 @@ const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x84
+ 0x00, 0x00, 0x00, 0x8a,
};
EXPORT_SYMBOL(test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v4 5/5] arm64: mpam: Add memory bandwidth usage (MBWU) documentation
From: Reinette Chatre @ 2026-07-02 14:46 UTC (permalink / raw)
To: Ben Horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jic23, kobak, lcherian,
linux-arm-kernel, linux-kernel, peternewman, punit.agrawal,
quic_jiles, rohit.mathew, scott, sdonthineni, tan.shaopeng, xhao,
zengheng4, x86
In-Reply-To: <0ebb1365-9883-4974-9e8f-05c2eaa01fb1@arm.com>
Hi Ben,
On 7/2/26 2:20 AM, Ben Horgan wrote:
> On 7/1/26 23:38, Reinette Chatre wrote:
>> On 5/20/26 2:24 PM, Ben Horgan wrote:
...
>>> --- a/Documentation/arch/arm64/mpam.rst
>>> +++ b/Documentation/arch/arm64/mpam.rst
>>> @@ -65,6 +65,23 @@ The supported features are:
>>> there is at least one CSU monitor on each MSC that makes up the L3 group.
>>> Exposing CSU counters from other caches or devices is not supported.
>>>
>>> +* Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
>>> + L3 cache-id to identify where the memory bandwidth is measured. For this
>>> + reason the platform must have an L3 cache with cache-id's supplied by
>>> + firmware. (It doesn't need to support MPAM.)
>>> +
>>> + Memory bandwidth monitoring makes use of MBWU monitors in each MSC that
>>> + makes up the L3 group. If the memory bandwidth monitoring is on the memory
>>> + rather than the L3 then there must be a single global L3 as otherwise it
>>> + is unknown which L3 the traffic came from.
>>> +
>>> + To expose 'mbm_total_bytes', the topology of the group of MSC chosen must
>>> + match the topology of the L3 cache so that the cache-id's can be
>>> + repainted. For example: Platforms with Memory bandwidth monitors on
>>> + CPU-less NUMA nodes cannot expose 'mbm_total_bytes' as these nodes do not
>>> + have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
>>> + cannot distinguish local traffic from global traffic.
>>
>> Hopefully we can get to a point where memory bandwidth monitoring data from
>> CPU-less NUMA nodes can be exposed via resctrl. When considering such possible
>
> Thank you for your interest here. I hope so too.
>
>> future I think it may make this work easier to build on if the documentation
>> focuses on what the current implementation supports and leave room for
>> future enhancements by not constraining user space expectation with an absolute
>> like "CPU-less NUMA nodes cannot expose 'mbm_total_bytes'".
>
> The intention was to describe the current limitations but I do see how
> this can come across as fundamental problems rather than just that we
> need to do some more work to establish how this can be done and
> implement it.
>
> How about if I add this paragraph at the end?
>
> All these restrictions based on L3 cache are due to resctrl, currently,
> only supporting monitoring at the scope of the L3 scope. It is expected
How about "at L3 scope" instead of "at the scope of the L3 scope"?
> that going forward more MBWU monitors can be exposed to the user after
> support for more monitoring scopes is added to resctrl.
Looks good to me, thank you.
Reinette
^ permalink raw reply
* [PATCH v8 34/39] drm/tests: hdmi_state_helper: Use drmm_connector_hdmi_init_with_caps()
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Convert the internal __connector_hdmi_init() helper to take a
drm_connector_hdmi_caps struct rather than separate formats and max_bpc
parameters, and add a
drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs() macro that
exposes the full caps struct to tests.
This lets new tests exercise capability fields beyond formats and
max_bpc, notably supported_hdmi_ver and max_tmds_char_rate, without
further changes to the helper signature.
The legacy drm_kunit_helper_connector_hdmi_init_with_edid_funcs() macro
is kept as a thin wrapper so the bulk of the test suite is unaffected.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 35 ++++++++++++++--------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 353a261d42da..6a7dd2de002a 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -231,8 +231,7 @@ static const struct drm_encoder_helper_funcs test_encoder_helper_funcs = {
static
struct drm_atomic_helper_connector_hdmi_priv *
__connector_hdmi_init(struct kunit *test,
- unsigned int formats,
- unsigned int max_bpc,
+ const struct drm_connector_hdmi_caps *caps,
const struct drm_connector_hdmi_funcs *hdmi_funcs,
const void *edid_data, size_t edid_len)
{
@@ -273,16 +272,16 @@ __connector_hdmi_init(struct kunit *test,
enc->possible_crtcs = drm_crtc_mask(priv->crtc);
conn = &priv->connector;
- conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ conn->ycbcr_420_allowed = !!(caps->supported_formats &
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
- ret = drmm_connector_hdmi_init(drm, conn,
- "Vendor", "Product",
- &dummy_connector_funcs,
- hdmi_funcs,
- DRM_MODE_CONNECTOR_HDMIA,
- NULL,
- formats,
- max_bpc);
+ ret = drmm_connector_hdmi_init_with_caps(drm, conn,
+ "Vendor", "Product",
+ &dummy_connector_funcs,
+ hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ NULL,
+ caps);
KUNIT_ASSERT_EQ(test, ret, 0);
drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
@@ -298,8 +297,18 @@ __connector_hdmi_init(struct kunit *test,
return priv;
}
-#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, max_bpc, funcs, edid) \
- __connector_hdmi_init(test, formats, max_bpc, funcs, edid, ARRAY_SIZE(edid))
+#define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, \
+ bpc_max, funcs, edid) \
+({ \
+ struct drm_connector_hdmi_caps __caps = { \
+ .supported_formats = (formats), \
+ .max_bpc = (bpc_max), \
+ }; \
+ __connector_hdmi_init(test, &__caps, funcs, edid, ARRAY_SIZE(edid)); \
+})
+
+#define drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test, caps, funcs, edid) \
+ __connector_hdmi_init(test, caps, funcs, edid, ARRAY_SIZE(edid))
static
struct drm_atomic_helper_connector_hdmi_priv *
--
2.54.0
^ permalink raw reply related
* [PATCH v8 31/39] drm/vc4: hdmi: Convert to common SCDC scrambling infrastructure
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Replace driver local scrambling logic with the newly introduced common
HDMI 2.0 scrambling support:
- Advertise source-side scrambling capability by setting supported HDMI
version based on the variant's max_pixel_clock.
- Provide minimal .scrambler_{enable|disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register, while delegating
sink-side SCDC programming and periodic status monitoring to
drm_connector_hdmi_{enable|disable}_scrambling().
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to drm_atomic_helper_connector_hdmi_hotplug()
which internally calls drm_connector_hdmi_sync_scdc() to trigger a
CRTC reset on reconnection.
- Drop the local scrambling_work delayed workqueue and scdc_enabled
flag, now tracked by the common drm_connector_hdmi layer, as well as
the now unused output_{bpc|color_format} driver data members.
No functional change intended.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 276 ++++++++---------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 21 ----
2 files changed, 49 insertions(+), 248 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index e7b0f0f2e350..81e0214f7e95 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -35,7 +35,6 @@
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
-#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
@@ -114,22 +113,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
-{
- struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!display->is_hdmi)
- return false;
-
- if (!display->hdmi.scdc.supported ||
- !display->hdmi.scdc.scrambling.supported)
- return false;
-
- return true;
-}
-
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -263,124 +246,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
-static int vc4_hdmi_reset_link(struct drm_connector *connector,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_device *drm;
- struct vc4_hdmi *vc4_hdmi;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc *crtc;
- bool scrambling_needed;
- u8 config;
- int ret;
-
- if (!connector)
- return 0;
-
- drm = connector->dev;
- ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
- if (ret)
- return ret;
-
- conn_state = connector->state;
- crtc = conn_state->crtc;
- if (!crtc)
- return 0;
-
- ret = drm_modeset_lock(&crtc->mutex, ctx);
- if (ret)
- return ret;
-
- crtc_state = crtc->state;
- if (!crtc_state->active)
- return 0;
-
- vc4_hdmi = connector_to_vc4_hdmi(connector);
- mutex_lock(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- scrambling_needed = drm_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format);
- if (!scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
- drm_err(drm, "Failed to read TMDS config: %d\n", ret);
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- mutex_unlock(&vc4_hdmi->mutex);
-
- /*
- * HDMI 2.0 says that one should not send scrambled data
- * prior to configuring the sink scrambling, and that
- * TMDS clock/data transmission should be suspended when
- * changing the TMDS clock rate in the sink. So let's
- * just do a full modeset here, even though some sinks
- * would be perfectly happy if were to just reconfigure
- * the SCDC settings on the fly.
- */
- return drm_atomic_helper_reset_crtc(crtc, ctx);
-}
-
-static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
- struct drm_modeset_acquire_ctx *ctx,
- enum drm_connector_status status)
-{
- struct drm_connector *connector = &vc4_hdmi->connector;
- int ret;
-
- /*
- * NOTE: This function should really be called with vc4_hdmi->mutex
- * held, but doing so results in reentrancy issues since
- * cec_s_phys_addr() might call .adap_enable, which leads to that
- * funtion being called with our mutex held.
- *
- * A similar situation occurs with vc4_hdmi_reset_link() that
- * will call into our KMS hooks if the scrambling was enabled.
- *
- * Concurrency isn't an issue at the moment since we don't share
- * any state with any of the other frameworks so we can ignore
- * the lock for now.
- */
-
- drm_atomic_helper_connector_hdmi_hotplug(connector, status, NULL);
-
- if (status != connector_status_connected)
- return;
-
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -392,8 +257,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
/*
* NOTE: This function should really take vc4_hdmi->mutex, but
* doing so results in reentrancy issues since
- * vc4_hdmi_handle_hotplug() can call into other functions that
- * would take the mutex while it's held here.
+ * drm_atomic_helper_connector_hdmi_hotplug() can call into other
+ * functions that would take the mutex while it's held here.
*
* Concurrency isn't an issue at the moment since we don't share
* any state with any of the other frameworks so we can ignore
@@ -416,10 +281,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, status, ctx);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
- return status;
+ return ret == -EDEADLK ? ret : status;
}
static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -526,22 +392,28 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
{
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
- unsigned int max_bpc = 8;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
+ .max_bpc = 8,
+ };
int ret;
if (vc4_hdmi->variant->supports_hdr)
- max_bpc = 12;
+ caps.max_bpc = 12;
- ret = drmm_connector_hdmi_init(dev, connector,
- "Broadcom", "Videocore",
- &vc4_hdmi_connector_funcs,
- &vc4_hdmi_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA,
- vc4_hdmi->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- max_bpc);
+ if (vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
+ caps.supported_hdmi_ver = HDMI_VERSION_2_0;
+ else if (vc4_hdmi->variant->max_pixel_clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
+ caps.supported_hdmi_ver = HDMI_VERSION_1_3;
+
+ ret = drmm_connector_hdmi_init_with_caps(dev, connector,
+ "Broadcom", "Videocore",
+ &vc4_hdmi_connector_funcs,
+ &vc4_hdmi_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ vc4_hdmi->ddc, &caps);
if (ret)
return ret;
@@ -553,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+ /*
+ * Since we don't know the state of the controller and its
+ * display (if any), let's assume it's always enabled.
+ * drm_connector_hdmi_disable_scrambling() will thus run at boot,
+ * make sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -778,32 +658,14 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
buffer, len);
}
-#define SCRAMBLING_POLLING_DELAY_MS 1000
-
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!drm_hdmi_mode_needs_scrambling(mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format))
- return;
-
- if (!drm_dev_enter(drm, &idx))
- return;
-
- drm_scdc_set_high_tmds_clock_ratio(connector, true);
- drm_scdc_set_scrambling(connector, true);
+ if (!drm_dev_enter(connector->dev, &idx))
+ return -ENODEV;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
@@ -812,59 +674,26 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
drm_dev_exit(idx);
- vc4_hdmi->scdc_enabled = true;
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
-static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
- struct drm_device *drm = connector->dev;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi->scdc_enabled)
- return;
-
- vc4_hdmi->scdc_enabled = false;
-
- if (delayed_work_pending(&vc4_hdmi->scrambling_work))
- cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
-
- if (!drm_dev_enter(drm, &idx))
- return;
+ if (!drm_dev_enter(connector->dev, &idx))
+ return -ENODEV;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_scdc_set_scrambling(connector, false);
- drm_scdc_set_high_tmds_clock_ratio(connector, false);
-
drm_dev_exit(idx);
-}
-static void vc4_hdmi_scrambling_wq(struct work_struct *work)
-{
- struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
- struct vc4_hdmi,
- scrambling_work);
- struct drm_connector *connector = &vc4_hdmi->connector;
-
- if (drm_scdc_get_scrambling_status(connector))
- return;
-
- drm_scdc_set_high_tmds_clock_ratio(connector, true);
- drm_scdc_set_scrambling(connector, true);
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -909,7 +738,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
}
- vc4_hdmi_disable_scrambling(encoder);
+ drm_connector_hdmi_disable_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1617,6 +1446,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+ struct drm_connector_state *conn_state;
unsigned long flags;
int ret;
int idx;
@@ -1685,7 +1515,9 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
- vc4_hdmi_enable_scrambling(encoder);
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ drm_connector_hdmi_enable_scrambling(connector, conn_state);
drm_dev_exit(idx);
@@ -1702,8 +1534,6 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
- vc4_hdmi->output_bpc = conn_state->hdmi.output_bpc;
- vc4_hdmi->output_format = conn_state->hdmi.output_format;
mutex_unlock(&vc4_hdmi->mutex);
}
@@ -1731,7 +1561,9 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
}
static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
.avi = {
.clear_infoframe = vc4_hdmi_clear_avi_infoframe,
.write_infoframe = vc4_hdmi_write_avi_infoframe,
@@ -3225,7 +3057,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
spin_lock_init(&vc4_hdmi->hw_lock);
- INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base;
@@ -3238,15 +3069,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->pdev = pdev;
vc4_hdmi->variant = variant;
- /*
- * Since we don't know the state of the controller and its
- * display (if any), let's assume it's always enabled.
- * vc4_hdmi_disable_scrambling() will thus run at boot, make
- * sure it's disabled, and avoid any inconsistency.
- */
- if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
- vc4_hdmi->scdc_enabled = true;
-
ret = variant->init_resources(drm, vc4_hdmi);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..0e9797ffad30 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -118,8 +118,6 @@ struct vc4_hdmi {
struct vc4_encoder encoder;
struct drm_connector connector;
- struct delayed_work scrambling_work;
-
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -193,25 +191,6 @@ struct vc4_hdmi {
*/
bool packet_ram_enabled;
- /**
- * @scdc_enabled: Is the HDMI controller currently running with
- * the scrambler on? Protected by @mutex.
- */
- bool scdc_enabled;
-
- /**
- * @output_bpc: Copy of @drm_connector_state.hdmi.output_bpc for
- * use outside of KMS hooks. Protected by @mutex.
- */
- unsigned int output_bpc;
-
- /**
- * @output_format: Copy of
- * @drm_connector_state.hdmi.output_format for use outside of
- * KMS hooks. Protected by @mutex.
- */
- enum drm_output_color_format output_format;
-
/**
* @hdmi_jack: Represents the connection state of the HDMI plug, for
* ALSA jack detection.
--
2.54.0
^ permalink raw reply related
* [PATCH v8 33/39] drm/tests: connector: Add HDMI source-side scrambler coverage
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Add KUnit tests for the HDMI source-side scrambling validation done by
drmm_connector_hdmi_init_with_caps().
Connector initialization derives the scrambler_supported flag from the
driver-provided supported_hdmi_ver capability. If it indicates
source-side scrambling support, both .scrambler_enable and
.scrambler_disable must be provided. Missing either callback is
rejected. If source-side scrambling is not supported, the callbacks are
ignored.
Test the valid and invalid callback combinations for both supported and
unsupported scrambling configurations.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 141 +++++++++++++++++++++++++++++
1 file changed, 141 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index 1fb1d83aec1a..98ccfaa0ee36 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -47,6 +47,41 @@ static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
},
};
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler = {
+ .scrambler_enable = accept_scrambler_enable,
+ .scrambler_disable = accept_scrambler_disable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler_partial = {
+ .scrambler_enable = accept_scrambler_enable,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static const struct drm_connector_funcs dummy_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -1436,6 +1471,108 @@ static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *
KUNIT_EXPECT_LT(test, ret, 0);
}
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support succeeds when the .scrambler_{enable|disable} callbacks
+ * are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_valid(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.scrambler_supported, true);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when the .scrambler_{enable|disable} callbacks
+ * are not provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_no_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when only one of the .scrambler_{enable|disable}
+ * callbacks are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_partial_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler_partial,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support succeeds, even when the .scrambler_{enable|disable}
+ * callbacks are provided, i.e. they are ignored.
+ */
+static void drm_test_connector_hdmi_init_scrambler_ignored_callbacks(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.scrambler_supported, false);
+}
+
static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_valid),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
@@ -1467,6 +1604,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_exceeds),
KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_valid),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_no_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_partial_callbacks),
+ KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_ignored_callbacks),
{ }
};
--
2.54.0
^ permalink raw reply related
* [PATCH v8 35/39] drm/tests: hdmi_state_helper: Add max_tmds_char_rate fallback tests
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Cover the fallback in hdmi_clock_valid() that rejects modes whose TMDS
character rate exceeds connector->hdmi.max_tmds_char_rate when the
driver provides no .tmds_char_rate_valid() callback. Exercise both an
explicit limit set through drm_connector_hdmi_caps and the limit
inferred from caps.supported_hdmi_ver, and confirm that a driver hook
takes precedence over the connector limit.
The connector limit is installed via the new
drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs() helper so it
is in place before mode probing runs.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 120 +++++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 6a7dd2de002a..b8ae5fad2794 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -174,6 +174,26 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static enum drm_mode_status
+accept_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_hdmi_funcs accept_connector_hdmi_funcs = {
+ .tmds_char_rate_valid = accept_connector_tmds_char_rate_valid,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -2771,6 +2791,103 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
}
+/*
+ * Test that a driver-provided .tmds_char_rate_valid() hook takes precedence
+ * over the connector->hdmi.max_tmds_char_rate fallback: the fallback must
+ * not be consulted when the hook is present.
+ */
+static void
+drm_test_check_mode_valid_driver_hook_overrides_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = 100ULL * 1000 * 1000,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &accept_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 148500);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() falls back to
+ * connector->hdmi.max_tmds_char_rate when the driver provides no
+ * .tmds_char_rate_valid() hook, rejecting modes whose computed TMDS character
+ * rate exceeds the connector limit.
+ */
+static void
+drm_test_check_mode_valid_reject_connector_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = 100ULL * 1000 * 1000,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
+}
+
+/*
+ * Test that the max_tmds_char_rate inferred from caps.supported_hdmi_ver
+ * is applied as a mode-filtering limit: with an HDMI 1.3 connector
+ * (340 MHz inferred cap) and no driver hook, modes whose RGB444/8bpc TMDS
+ * rate exceeds 340 MHz must be filtered out even though the sink itself
+ * advertises a higher limit.
+ */
+static void
+drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+ unsigned long long rate;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_EXPECT_LE(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+}
+
/*
* Test that drm_hdmi_connector_mode_valid() will accept modes that require a
* 4:2:0 chroma subsampling, even if said mode would violate maximum clock
@@ -2865,6 +2982,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
KUNIT_CASE(drm_test_check_mode_valid_reject),
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_driver_hook_overrides_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_connector_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate),
KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
--
2.54.0
^ permalink raw reply related
* [PATCH v8 32/39] drm/tests: connector: Add HDMI caps-based init coverage
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Add KUnit tests for drmm_connector_hdmi_init_with_caps() covering NULL
caps rejection, the max_tmds_char_rate inferred from each advertised
HDMI specification version, and the validation of a driver-provided
max_tmds_char_rate against the version-inferred limit: override below,
accept at, reject above, reject when no version is advertised.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/tests/drm_connector_test.c | 189 +++++++++++++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..1fb1d83aec1a 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -1254,6 +1254,188 @@ KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_tests,
drm_connector_hdmi_init_type_desc);
+/*
+ * Test that the registration of an HDMI connector with a NULL caps fails.
+ */
+static void drm_test_connector_hdmi_init_null_caps(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ NULL);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector without an explicit max TMDS
+ * character rate being provided succeeds, and the connector limit is inferred
+ * from the advertised HDMI specification version.
+ */
+struct drm_connector_hdmi_init_max_tmds_rate_inferred_case {
+ const char *desc;
+ enum hdmi_version ver;
+ unsigned long long expected;
+};
+
+static void drm_test_connector_hdmi_init_max_tmds_rate_inferred(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *param =
+ test->param_value;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = param->ver,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ param->expected);
+}
+
+static const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case
+drm_connector_hdmi_init_max_tmds_rate_inferred_tests[] = {
+ { "unknown", HDMI_VERSION_UNKNOWN, 0 },
+ { "1.0", HDMI_VERSION_1_0, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.2", HDMI_VERSION_1_2, HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.3", HDMI_VERSION_1_3, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "1.4", HDMI_VERSION_1_4, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ },
+ { "2.0", HDMI_VERSION_2_0, HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ },
+};
+
+static void drm_connector_hdmi_init_max_tmds_rate_inferred_desc(
+ const struct drm_connector_hdmi_init_max_tmds_rate_inferred_case *t,
+ char *desc)
+{
+ strscpy(desc, t->desc, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_tests,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_desc);
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate strictly below the version-inferred limit succeeds, and
+ * the connector limit is overridden.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_override(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate equal to the version-inferred limit succeeds.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_at_limit(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs_scrambler,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a max TMDS
+ * character rate that exceeds the limit inferred from the advertised HDMI
+ * specification version fails.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_exceeds(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector providing a non-zero max
+ * TMDS character rate without an HDMI specification version fails, as the
+ * version-inferred limit defaults to zero and any positive override would
+ * exceed it.
+ */
+static void drm_test_connector_hdmi_init_max_tmds_rate_no_version(struct kunit *test)
+{
+ struct drm_connector_init_priv *priv = test->priv;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ,
+ };
+ int ret;
+
+ ret = drmm_connector_hdmi_init_with_caps(&priv->drm, &priv->connector,
+ "Vendor", "Product",
+ &dummy_funcs,
+ &dummy_hdmi_funcs,
+ DRM_MODE_CONNECTOR_HDMIA,
+ &priv->ddc,
+ &caps);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
static struct kunit_case drmm_connector_hdmi_init_tests[] = {
KUNIT_CASE(drm_test_connector_hdmi_init_valid),
KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
@@ -1278,6 +1460,13 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
drm_connector_hdmi_init_type_valid_gen_params),
KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
drm_connector_hdmi_init_type_invalid_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_null_caps),
+ KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_max_tmds_rate_inferred,
+ drm_connector_hdmi_init_max_tmds_rate_inferred_gen_params),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_override),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_at_limit),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_exceeds),
+ KUNIT_CASE(drm_test_connector_hdmi_init_max_tmds_rate_no_version),
{ }
};
--
2.54.0
^ permalink raw reply related
* [PATCH v8 29/39] drm/vc4: hdmi: Use common TMDS char rate constants
From: Cristian Ciocaltea @ 2026-07-02 14:46 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Luca Ceresoli,
Sandy Huang, Heiko Stübner, Andy Yan, Daniel Stone,
Dave Stevenson, Maíra Canal, Raspberry Pi Kernel Maintenance
Cc: kernel, dri-devel, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260702-dw-hdmi-qp-scramb-v8-0-d79890d00b6a@collabora.com>
Replace HDMI_14_MAX_TMDS_CLK defined locally with
HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
rate was actually introduced in HDMI 1.3.
Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
magic number.
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index e165f604939b..fbdb0448aa2b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -113,8 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
-
static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
{
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
@@ -137,7 +136,7 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
{
unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
- return clock > HDMI_14_MAX_TMDS_CLK;
+ return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
}
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
@@ -1727,7 +1726,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
/* 4096x2160@60 is not reliable without overclocking core */
@@ -3253,7 +3252,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
* vc4_hdmi_disable_scrambling() will thus run at boot, make
* sure it's disabled, and avoid any inconsistency.
*/
- if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+ if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
vc4_hdmi->scdc_enabled = true;
ret = variant->init_resources(drm, vc4_hdmi);
@@ -3383,7 +3382,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3412,7 +3411,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
+ .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3441,7 +3440,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3468,7 +3467,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
--
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