* Re: [PATCH 2/2] dmaengine: zynqmp_dma: Add per-channel reset support
From: Golla, Nagendra @ 2026-06-15 9:29 UTC (permalink / raw)
To: sashiko-reviews; +Cc: robh, devicetree, vkoul, Frank.Li, dmaengine, conor+dt
In-Reply-To: <20260525113349.68D6E1F00A3D@smtp.kernel.org>
On 5/25/2026 5:03 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The probe error path leaks a runtime PM usage counter reference, permanently breaking runtime PM and leaving hardware clocks enabled.
> - [High] Dropping the spinlock inside `list_for_each_entry_safe` allows concurrent modification of the list, leading to memory corruption.
> - [High] Hardware registers are accessed in the IRQ handler without verifying if the device is active, risking a kernel panic on spurious interrupts.
> --
>
> commit b2d2a678f48614c7188f8d81cbc70143b2bdfc0f
> Author: Golla Nagendra <nagendra.golla@amd.com>
> Subject: dmaengine: zynqmp_dma: Add per-channel reset support
>
> This commit introduces per-channel reset support for Versal Gen 2 and
> Versal Net SoCs. It adds reset handling in the channel probe path using
> device_reset_optional() to trigger a reset pulse during initialization.
> Platforms without per-channel reset are unaffected.
>
>> diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
>> index f6a812e49ddca..51c831760372c 100644
>> --- a/drivers/dma/xilinx/zynqmp_dma.c
>> +++ b/drivers/dma/xilinx/zynqmp_dma.c
> [ ... ]
>> @@ -916,6 +917,11 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
>> if (IS_ERR(chan->regs))
>> return PTR_ERR(chan->regs);
>>
>> + err = device_reset_optional(&pdev->dev);
>> + if (err)
>> + return dev_err_probe(&pdev->dev, err,
>> + "failed to reset channel\n");
>> +
>
> [Severity: High]
> This isn't a bug introduced by this patch, but does this error path leak a
> runtime PM usage counter reference?
>
> In zynqmp_dma_probe(), pm_runtime_resume_and_get() is called to increment
> the runtime PM usage counter and enable the device clocks. If a subsequent
> initialization step fails, such as the newly added device_reset_optional()
> returning -EPROBE_DEFER, the code jumps to the err_disable_pm label:
>
> zynqmp_dma_probe()
> ...
> ret = pm_runtime_resume_and_get(zdev->dev);
> ...
> ret = zynqmp_dma_chan_probe(zdev, pdev);
> if (ret) {
> dev_err_probe(&pdev->dev, ret, "Probing channel failed\n");
> goto err_disable_pm;
> }
> ...
> err_disable_pm:
> if (!pm_runtime_enabled(zdev->dev))
> zynqmp_dma_runtime_suspend(zdev->dev);
> pm_runtime_disable(zdev->dev);
> return ret;
>
> Since the device is still runtime PM enabled, it skips
> zynqmp_dma_runtime_suspend() and fails to drop the usage counter with
> pm_runtime_put_noidle().
>
> Because -EPROBE_DEFER is a normal occurrence during boot, this path can
> be hit multiple times. Will this permanently leave the usage counter above
> zero, preventing the device from ever entering runtime suspend and leaving
> its clocks enabled indefinitely?
>
>> chan->bus_width = ZYNQMP_DMA_BUS_WIDTH_64;
>> chan->dst_burst_len = ZYNQMP_DMA_MAX_DST_BURST_LEN;
>
> [Severity: High]
> This is a pre-existing issue, but does dropping the spinlock inside
> list_for_each_entry_safe() in zynqmp_dma_chan_desc_cleanup() allow concurrent
> modification of the list, leading to memory corruption?
>
> When zynqmp_dma_chan_desc_cleanup() temporarily drops the lock to invoke
> the DMA callback:
>
> zynqmp_dma_chan_desc_cleanup()
> ...
> list_for_each_entry_safe(desc, next, &chan->done_list, node) {
> ...
> if (dmaengine_desc_callback_valid(&cb)) {
> spin_unlock_irqrestore(&chan->lock, irqflags);
> dmaengine_desc_callback_invoke(&cb, NULL);
> spin_lock_irqsave(&chan->lock, irqflags);
> }
>
> A client driver can concurrently invoke dmaengine_terminate_sync(), which
> calls zynqmp_dma_device_terminate_all() and executes
> zynqmp_dma_free_descriptors(). This moves all remaining elements, including
> the prefetched next pointer, from done_list to free_list.
>
> When zynqmp_dma_chan_desc_cleanup() reacquires the lock, won't it continue
> iterating using the corrupted next pointer that now resides in free_list,
> eventually interpreting the list head &chan->free_list as a struct
> zynqmp_dma_desc_sw and resulting in out-of-bounds memory accesses?
>
> [Severity: High]
> This is a pre-existing issue, but are hardware registers accessed in the
> IRQ handler without verifying if the device is active, risking a kernel
> panic on spurious interrupts?
Hi,
Thanks for pointing this out.After reviewing the runtime PM guidelines
and the driver behavior, I believe this is not a strict requirement for
all IRQ handlers. The PM documentation does not mandate that
pm_runtime_get_if_active() must be used before every register access in
an ISR. It is mainly intended for cases where an interrupt can occur
while the device might be runtime-suspended, such as shared IRQ or
spurious interrupt scenarios.
In the case of the zynqmp DMA driver, the interrupt is generated only
when the hardware is active during a transfer, and the driver ensures
the device remains runtime-active while DMA operations are in progress.
Because of this, the ISR is not expected to run when the device is
suspended, and accessing registers directly should be safe.
So, in this context, adding pm_runtime_get_if_active() in the IRQ
handler may not be necessary. That said, please let me know if you see
a scenario where the interrupt could be triggered while the device is
runtime-suspended, and I can revisit accordingly.
Thanks,
Nagendra
>
> The IRQ handler zynqmp_dma_irq_handler() directly reads the ISR and IMR
> hardware registers:
>
> zynqmp_dma_irq_handler()
> ...
> isr = readl(chan->regs + ZYNQMP_DMA_ISR);
> imr = readl(chan->regs + ZYNQMP_DMA_IMR);
>
> According to the Power Management Subsystem guidelines, IRQ handlers must
> use pm_runtime_get_if_active() before accessing hardware registers.
>
> Although this IRQ is not shared, spurious interrupts can still occur. If a
> spurious interrupt fires while the device is in a suspended state with its
> clocks disabled via zynqmp_dma_runtime_suspend(), could this unprotected
> register read lead to a synchronous external abort and crash the kernel?
>
^ permalink raw reply
* Re: [PATCH v5 5/9] block: implement NVMEM provider
From: Loic Poulain @ 2026-06-15 9:28 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Srinivas Kandagatla,
Andrew Lunn, Heiner Kallweit, Russell King, Saravana Kannan
In-Reply-To: <CAMRc=McQkLnz2OS2RREAbcrsp47cL-W3bCduq8LwPBBUcVNyJw@mail.gmail.com>
On Mon, Jun 15, 2026 at 10:53 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Fri, 12 Jun 2026 15:20:57 +0200, Loic Poulain
> <loic.poulain@oss.qualcomm.com> said:
> > From: Daniel Golle <daniel@makrotopia.org>
> >
> > On embedded devices using an eMMC it is common that one or more partitions
> > on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
> > data. Allow referencing the partition in device tree for the kernel and
> > Wi-Fi drivers accessing it via the NVMEM layer.
> >
> > For now, NVMEM is only registered for the whole disk block device, as the
> > OF node is currently only associated to it.
> >
> > Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> > Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
> > block/Kconfig | 9 ++++
> > block/Makefile | 1 +
> > block/blk-nvmem.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++
> > block/blk.h | 8 ++++
> > block/genhd.c | 4 ++
> > include/linux/blk_types.h | 3 ++
> > include/linux/blkdev.h | 1 +
> > 7 files changed, 135 insertions(+)
> >
> > diff --git a/block/Kconfig b/block/Kconfig
> > index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
> > --- a/block/Kconfig
> > +++ b/block/Kconfig
> > @@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
> > by falling back to the kernel crypto API when inline
> > encryption hardware is not present.
> >
> > +config BLK_NVMEM
> > + bool "Block device NVMEM provider"
> > + depends on OF
> > + depends on NVMEM
> > + help
> > + Allow block devices (or partitions) to act as NVMEM providers,
> > + typically used with eMMC to store MAC addresses or Wi-Fi
> > + calibration data on embedded devices.
> > +
> > source "block/partitions/Kconfig"
> >
> > config BLK_PM
> > diff --git a/block/Makefile b/block/Makefile
> > index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
> > --- a/block/Makefile
> > +++ b/block/Makefile
> > @@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
> > blk-crypto-sysfs.o
> > obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
> > obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
> > +obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
> > diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..c005f059d9fe56242ebaef9905673dff902b5686
> > --- /dev/null
> > +++ b/block/blk-nvmem.c
> > @@ -0,0 +1,109 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * block device NVMEM provider
> > + *
> > + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + *
> > + * Useful on devices using a partition on an eMMC for MAC addresses or
> > + * Wi-Fi calibration EEPROM data.
> > + */
> > +
> > +#include <linux/file.h>
> > +#include <linux/nvmem-provider.h>
> > +#include <linux/nvmem-consumer.h>
> > +#include <linux/of.h>
> > +#include <linux/pagemap.h>
> > +#include <linux/property.h>
> > +
> > +#include "blk.h"
> > +
> > +static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)
> > +{
> > + blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES;
> > + dev_t devt = (dev_t)(uintptr_t)priv;
> > + size_t bytes_left = bytes;
> > + loff_t pos = from;
> > + int ret = 0;
> > +
> > + struct file *bdev_file __free(fput) = bdev_file_open_by_dev(devt, mode, priv, NULL);
> > + if (IS_ERR(bdev_file))
> > + return PTR_ERR(bdev_file);
> > +
> > + while (bytes_left) {
> > + pgoff_t f_index = pos >> PAGE_SHIFT;
> > + struct folio *folio;
> > + size_t folio_off;
> > + size_t to_read;
> > +
> > + folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
> > + if (IS_ERR(folio)) {
> > + ret = PTR_ERR(folio);
> > + break;
> > + }
> > +
> > + folio_off = offset_in_folio(folio, pos);
> > + to_read = min(bytes_left, folio_size(folio) - folio_off);
> > + memcpy_from_folio(val, folio, folio_off, to_read);
> > + pos += to_read;
> > + bytes_left -= to_read;
> > + val += to_read;
> > + folio_put(folio);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +void blk_nvmem_add(struct block_device *bdev)
> > +{
> > + struct device *dev = &bdev->bd_device;
> > + struct nvmem_config config = {};
> > +
> > + /* skip devices which do not have a device tree node */
> > + if (!dev_of_node(dev))
> > + return;
> > +
> > + /* skip devices without an nvmem layout defined */
> > + struct device_node *child __free(device_node) =
> > + of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
> > + if (!child)
> > + return;
> > +
> > + /*
> > + * skip block device too large to be represented as NVMEM devices,
> > + * the NVMEM reg_read callback uses an unsigned int offset
> > + */
> > + if (bdev_nr_bytes(bdev) > UINT_MAX) {
> > + dev_warn(dev, "block device too large to be an NVMEM provider\n");
> > + return;
> > + }
> > +
> > + config.id = NVMEM_DEVID_NONE;
> > + config.dev = dev;
> > + config.name = dev_name(dev);
> > + config.owner = THIS_MODULE;
> > + config.priv = (void *)(uintptr_t)dev->devt;
> > + config.reg_read = blk_nvmem_reg_read;
> > + config.size = bdev_nr_bytes(bdev);
> > + config.word_size = 1;
> > + config.stride = 1;
> > + config.read_only = true;
> > + config.root_only = true;
> > + config.ignore_wp = true;
> > + config.of_node = to_of_node(dev->fwnode);
> > +
> > + bdev->bd_nvmem = nvmem_register(&config);
> > + if (IS_ERR(bdev->bd_nvmem)) {
> > + dev_err_probe(dev, PTR_ERR(bdev->bd_nvmem),
> > + "Failed to register NVMEM device\n");
>
> Using dev_err_probe() only makes sense with a return value. Which makes me
> think: we won't retry this after a probe deferral. I think we should return
Yes, so here with the nvmem fixed-layout, there is no way to get a
deferred probe error, but better to be ready to handle this anyway.
> int from this function just for this use-case. Also: if we *do* have
> a layout, shouldn't we treat a failure to register the nvmem provider as
> a an error and propagate it up the stack?
From an API perspective we should indeed return the error. From block
core, Do we want to fail the entire disk addition just because the
'companion' NVMEM provider couldn't be registered, or should we only
abort/return in case of EPROBE_DEFER?
>
> > + bdev->bd_nvmem = NULL;
> > + }
> > +}
> > +
> > +void blk_nvmem_del(struct block_device *bdev)
> > +{
> > + if (bdev->bd_nvmem)
>
> Nvmem core already performs a NULL check.
Ok, thanks!
>
> > + nvmem_unregister(bdev->bd_nvmem);
> > +
> > + bdev->bd_nvmem = NULL;
> > +}
> > diff --git a/block/blk.h b/block/blk.h
> > index ec4674cdf2ead4fd259ff5fc42401f591e684ee9..cd3c7ca723391c40be56f1dd4810e641b7c8a2b3 100644
> > --- a/block/blk.h
> > +++ b/block/blk.h
> > @@ -757,4 +757,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
> > memalloc_noio_restore(memflags);
> > }
> >
> > +#ifdef CONFIG_BLK_NVMEM
> > +void blk_nvmem_add(struct block_device *bdev);
> > +void blk_nvmem_del(struct block_device *bdev);
> > +#else
> > +static inline void blk_nvmem_add(struct block_device *bdev) {}
> > +static inline void blk_nvmem_del(struct block_device *bdev) {}
> > +#endif
> > +
> > #endif /* BLK_INTERNAL_H */
> > diff --git a/block/genhd.c b/block/genhd.c
> > index 7d6854fd28e95ae9134309679a7c6a937f5b7db8..1b2382de6fb30c1e5f60f45c04dc03ed3bf5d5f2 100644
> > --- a/block/genhd.c
> > +++ b/block/genhd.c
> > @@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
> > */
> > dev_set_uevent_suppress(ddev, 0);
> > disk_uevent(disk, KOBJ_ADD);
> > +
> > + blk_nvmem_add(disk->part0);
> > }
> >
> > blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
> > @@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
> >
> > disk_del_events(disk);
> >
> > + blk_nvmem_del(disk->part0);
> > +
> > /*
> > * Prevent new openers by unlinked the bdev inode.
> > */
> > diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> > index 8808ee76e73c09e0ceaac41ba59e86fb0c4efc64..ace6f59b860d0813665b2f62a1c03a1f4be94059 100644
> > --- a/include/linux/blk_types.h
> > +++ b/include/linux/blk_types.h
> > @@ -73,6 +73,9 @@ struct block_device {
> > int bd_writers;
> > #ifdef CONFIG_SECURITY
> > void *bd_security;
> > +#endif
> > +#ifdef CONFIG_BLK_NVMEM
> > + struct nvmem_device *bd_nvmem;
> > #endif
> > /*
> > * keep this out-of-line as it's both big and not needed in the fast
> > diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> > index 890128cdea1ce66863c5baa36f3b336ec4550807..f15d2b5bf9e4fd2368b8a70416a978e22c0d4333 100644
> > --- a/include/linux/blkdev.h
> > +++ b/include/linux/blkdev.h
> > @@ -30,6 +30,7 @@
> >
> > struct module;
> > struct request_queue;
> > +struct nvmem_device;
> > struct elevator_queue;
> > struct blk_trace;
> > struct request;
> >
> > --
> > 2.34.1
> >
> >
>
> I like this approach better than the previous one.
>
> Thanks,
> Bartosz
^ permalink raw reply
* Re: [PATCH v1 1/6] ASoC: qcom: qdsp6: add topology-driven Audio IF support
From: Srinivas Kandagatla @ 2026-06-15 9:28 UTC (permalink / raw)
To: Prasad Kumpatla, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Jaroslav Kysela, Takashi Iwai,
Srinivas Kandagatla
Cc: linux-arm-msm, linux-sound, devicetree, linux-kernel
In-Reply-To: <20260610154517.134570-2-prasad.kumpatla@oss.qualcomm.com>
On 6/10/26 4:45 PM, Prasad Kumpatla wrote:
> Add topology parsing and media-format programming for Audio IF
> source and sink modules.
>
> Add the Audio IF module IDs, the required topology tokens, and a
> dedicated topology loader that stores the parsed interface
> configuration in the AudioReach module state. Also add the Audio IF
> media-format path that sends the interface configuration, hardware
> endpoint media format, and frame-duration parameters for Audio IF
> modules.
>
> This keeps the serial-interface configuration topology-driven while
> still allowing the machine driver to provide runtime slot and media
> format settings. The same Audio IF path can then be reused for TDM,
> PCM, and I2S style backends.
>
> The new UAPI tokens (AR_TKN_U32_MODULE_SYNC_SRC=262 through
> AR_TKN_U32_MODULE_INV_EXT_BIT_CLK=276) are added.
>
> MODULE_ID_AUDIO_IF_SINK (0x0700117C) and MODULE_ID_AUDIO_IF_SOURCE
> (0x0700117D) are introduced in this patch.
>
Which platform is this tested on, also please send a PR to
github.com/linux-msm/audioreach-topology to add thse new tokens.
> Signed-off-by: Prasad Kumpatla <prasad.kumpatla@oss.qualcomm.com>
> ---
> include/uapi/sound/snd_ar_tokens.h | 58 ++++++++++++++++
> sound/soc/qcom/qdsp6/audioreach.c | 97 ++++++++++++++++++++++++++
> sound/soc/qcom/qdsp6/audioreach.h | 62 +++++++++++++++++
> sound/soc/qcom/qdsp6/topology.c | 108 +++++++++++++++++++++++++++++
> 4 files changed, 325 insertions(+)
>
> diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h
> index 6b8102eaa..355a1e629 100644
> --- a/include/uapi/sound/snd_ar_tokens.h
> +++ b/include/uapi/sound/snd_ar_tokens.h
> @@ -168,6 +168,48 @@ enum ar_event_types {
> * LOG_WAIT = 0,
> * LOG_IMMEDIATELY = 1
> *
> + * %AR_TKN_U32_MODULE_SYNC_SRC: Frame sync source
> + * 0 = external, 1 = internal
> + *
> + * %AR_TKN_U32_MODULE_CTRL_DATA_OUT_ENABLE: Enable data-out tri-state control
> + * 0 = disable, 1 = enable
> + *
> + * %AR_TKN_U32_MODULE_SLOT_MASK: Active TDM slot bitmask
> + *
> + * %AR_TKN_U32_MODULE_NSLOTS_PER_FRAME: Number of slots per TDM frame
> + *
> + * %AR_TKN_U32_MODULE_SLOT_WIDTH: Slot width in bits (16 or 32)
> + *
> + * %AR_TKN_U32_MODULE_SYNC_MODE: Frame sync mode
> + * 0 = short pulse, 1 = long pulse
We have 3 possible values, please correct this, also you could add
defines for these values.
> + *
> + * %AR_TKN_U32_MODULE_CTRL_INVERT_SYNC_PULSE: Invert frame sync pulse polarity
> + * 0 = normal, 1 = inverted
> + *
> + * %AR_TKN_U32_MODULE_CTRL_SYNC_DATA_DELAY: Data delay relative to frame sync
> + * 0 = no delay, 1 = one cycle delay
Exactly same here, we have 2 cyle delay too.
> + *
> + * %AR_TKN_U32_MODULE_INTF_MODE: Audio IF interface mode
> + * AUDIO_IF_INTF_MODE_TDM = 0,
> + * AUDIO_IF_INTF_MODE_PCM = 1,
> + * AUDIO_IF_INTF_MODE_I2S = 2
Same here, defines for these.
> + *
> + * %AR_TKN_U32_MODULE_QAIF_TYPE: QAIF hardware port type index
> + *
> + * %AR_TKN_U32_MODULE_ACTIVE_LANE_MASK: Active lane bitmask for multi-lane
> + *
> + * %AR_TKN_U32_MODULE_FRAME_SYNC_RATE: Frame sync rate in Hz
> + *
> + * %AR_TKN_U32_MODULE_BIT_CLK_TYPE: Bit clock type
> + * 0 = internal, 1 = external,
> + * 2 = skip (bypass bit clock enable)
> + *
> + * %AR_TKN_U32_MODULE_INV_INT_BIT_CLK: Invert internal bit clock
> + * 0 = normal, 1 = inverted
> + *
> + * %AR_TKN_U32_MODULE_INV_EXT_BIT_CLK: Invert external bit clock
> + * 0 = normal, 1 = inverted
> + *
> * %AR_TKN_DAI_INDEX: dai index
> *
> */
> @@ -240,6 +282,22 @@ enum ar_event_types {
> #define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260
> #define AR_TKN_U32_MODULE_LOG_MODE 261
>
> +#define AR_TKN_U32_MODULE_SYNC_SRC 262
> +#define AR_TKN_U32_MODULE_CTRL_DATA_OUT_ENABLE 263
> +#define AR_TKN_U32_MODULE_SLOT_MASK 264
> +#define AR_TKN_U32_MODULE_NSLOTS_PER_FRAME 265
> +#define AR_TKN_U32_MODULE_SLOT_WIDTH 266
> +#define AR_TKN_U32_MODULE_SYNC_MODE 267
> +#define AR_TKN_U32_MODULE_CTRL_INVERT_SYNC_PULSE 268
> +#define AR_TKN_U32_MODULE_CTRL_SYNC_DATA_DELAY 269
> +#define AR_TKN_U32_MODULE_INTF_MODE 270
> +#define AR_TKN_U32_MODULE_QAIF_TYPE 271
> +#define AR_TKN_U32_MODULE_ACTIVE_LANE_MASK 272
> +#define AR_TKN_U32_MODULE_FRAME_SYNC_RATE 273
> +#define AR_TKN_U32_MODULE_BIT_CLK_TYPE 274
> +#define AR_TKN_U32_MODULE_INV_INT_BIT_CLK 275
> +#define AR_TKN_U32_MODULE_INV_EXT_BIT_CLK 276
> +
Here you prefix the tokens with U32, however in dirver this values are
validated against U8 and U16, So please fix the prefixes to reflect the
range.
...
>
> default:
> rc = 0;
> diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
> index 62a2fd79b..1dc29ddfd 100644
> --- a/sound/soc/qcom/qdsp6/audioreach.h
> +++ b/sound/soc/qcom/qdsp6/audioreach.h
> @@ -22,6 +22,8 @@ struct q6apm_graph;
> #define MODULE_ID_PLACEHOLDER_DECODER 0x07001009
> #define MODULE_ID_I2S_SINK 0x0700100A
> #define MODULE_ID_I2S_SOURCE 0x0700100B
> +#define MODULE_ID_AUDIO_IF_SINK 0x0700117C
> +#define MODULE_ID_AUDIO_IF_SOURCE 0x0700117D
Please place it in the assending order.
> #define MODULE_ID_SAL 0x07001010
> #define MODULE_ID_MFC 0x07001015
> #define MODULE_ID_DATA_LOGGING 0x0700101A
> @@ -544,6 +546,41 @@ struct param_id_i2s_intf_cfg {
> #define PORT_ID_I2S_OUPUT 1
> #define I2S_STACK_SIZE 2048
>
> +#define PARAM_ID_AUDIO_IF_INTF_CFG 0x08001B11
> +
> +#define AUDIO_IF_INTF_MODE_TDM 0x0
> +#define AUDIO_IF_INTF_MODE_PCM 0x1
> +#define AUDIO_IF_INTF_MODE_I2S 0x2
> +
> +struct param_id_audio_if_intf_cfg {
I know that we have not added documentation for all the structures, but
Am in process of adding them. Can you add kernel doc to these structs.
> + uint16_t qaif_type;
> + uint16_t intf_idx;
> + uint16_t intf_mode;
> + uint16_t ctrl_data_out_enable;
> + uint32_t active_slot_mask;
> + uint16_t nslots_per_frame;
> + uint16_t slot_width;
> + uint32_t active_lane_mask;
> + uint32_t frame_sync_rate;
> + uint16_t frame_sync_src;
> + uint16_t frame_sync_mode;
> + uint16_t invert_frame_sync_pulse;
> + uint16_t frame_sync_data_delay;
> + uint16_t bit_clk_type;
> + uint8_t inv_int_bit_clk;
> + uint8_t inv_ext_bit_clk;
> +} __packed;
> +
> +#define PARAM_ID_HW_EP_FRAME_DURATION 0x08001B2F
> +#define AUDIO_IF_FRAME_DURATION_US 1000
Why is this hardcoded?
> +
> +struct param_id_hw_ep_frame_duration {
> + uint32_t frame_duration_in_us;
> + uint32_t allow_frame_duration_normalization;
> + uint32_t min_normalized_frame_dur_us;
> + uint32_t max_normalized_frame_dur_us;
> +} __packed;
> +
> #define PARAM_ID_DISPLAY_PORT_INTF_CFG 0x08001154
>
> struct param_id_display_port_intf_cfg {
> @@ -877,6 +914,28 @@ struct audioreach_module {
> uint32_t data_format;
> uint32_t hw_interface_type;
>
> + /* Audio IF module (TDM/PCM/I2S) */
> + /*
> + * uint32_t fields first to minimise intra-block padding;
Why do we need this comments does not add a real value here?
> + * 2 bytes of trailing padding remain after inv_ext_bit_clk
> + * before the next uint32_t field (interleave_type).
> + */
> + uint32_t slot_mask;
> + uint32_t active_lane_mask;
> + uint32_t frame_sync_rate;
> + uint16_t qaif_type;
> + uint16_t sync_src;
> + uint16_t ctrl_data_out_enable;
> + uint16_t nslots_per_frame;
> + uint16_t slot_width;
> + uint16_t intf_mode;
> + uint16_t sync_mode;
> + uint16_t ctrl_invert_sync_pulse;
> + uint16_t ctrl_sync_data_delay;
> + uint16_t bit_clk_type;
> + uint8_t inv_int_bit_clk;
> + uint8_t inv_ext_bit_clk;
> +
> /* PCM module specific */
> uint32_t interleave_type;
>
> @@ -907,6 +966,9 @@ struct audioreach_module_config {
> u32 channel_allocation;
> u32 sd_line_mask;
> int fmt;
> + u32 slot_mask;
> + u16 nslots_per_frame;
> + u16 slot_width;
> struct snd_codec codec;
> u8 channel_map[AR_PCM_MAX_NUM_CHANNEL];
> };
> diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
> index 1f69fba6d..2ae7ac3d2 100644
> --- a/sound/soc/qcom/qdsp6/topology.c
> +++ b/sound/soc/qcom/qdsp6/topology.c
> @@ -753,6 +753,108 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
> return 0;
> }
>
> +static int audioreach_widget_audio_if_module_load(struct audioreach_module *mod,
> + const struct snd_soc_tplg_vendor_array *mod_array)
> +{
> + const struct snd_soc_tplg_vendor_value_elem *mod_elem;
> + int tkn_count = 0;
> + u32 val;
> +
> + mod_elem = mod_array->value;
> +
> + while (tkn_count < le32_to_cpu(mod_array->num_elems)) {
> + val = le32_to_cpu(mod_elem->value);
> + switch (le32_to_cpu(mod_elem->token)) {
> + case AR_TKN_U32_MODULE_HW_IF_IDX:
> + if (val > U16_MAX)
> + return -EINVAL;
Plese fix such instances as suggested at the top.
> + mod->hw_interface_idx = val;
> + break;
> + case AR_TKN_U32_MODULE_FMT_DATA:
> + mod->data_format = val;
> + break;
> + case AR_TKN_U32_MODULE_HW_IF_TYPE:
> + mod->hw_interface_type = val;
where are we using this?
> + break;
> + case AR_TKN_U32_MODULE_SYNC_SRC:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->sync_src = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_CTRL_DATA_OUT_ENABLE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->ctrl_data_out_enable = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_SLOT_MASK:
> + mod->slot_mask = val;
> + break;
> + case AR_TKN_U32_MODULE_NSLOTS_PER_FRAME:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->nslots_per_frame = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_SLOT_WIDTH:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->slot_width = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_INTF_MODE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->intf_mode = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_SYNC_MODE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->sync_mode = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_CTRL_INVERT_SYNC_PULSE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->ctrl_invert_sync_pulse = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_CTRL_SYNC_DATA_DELAY:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->ctrl_sync_data_delay = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_QAIF_TYPE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->qaif_type = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_ACTIVE_LANE_MASK:
> + mod->active_lane_mask = val;
> + break;
> + case AR_TKN_U32_MODULE_FRAME_SYNC_RATE:
> + mod->frame_sync_rate = val;
> + break;
> + case AR_TKN_U32_MODULE_BIT_CLK_TYPE:
> + if (val > U16_MAX)
> + return -EINVAL;
> + mod->bit_clk_type = (u16)val;
> + break;
> + case AR_TKN_U32_MODULE_INV_INT_BIT_CLK:
> + if (val > U8_MAX)
> + return -EINVAL;
> + mod->inv_int_bit_clk = (u8)val;
> + break;
> + case AR_TKN_U32_MODULE_INV_EXT_BIT_CLK:
> + if (val > U8_MAX)
> + return -EINVAL;
> + mod->inv_ext_bit_clk = (u8)val;
> + break;
> + default:
> + break;
> + }
> + tkn_count++;
> + mod_elem++;
> + }
> +
> + return 0;
> +}
^ permalink raw reply
* Re: [PATCH v3 0/4] Add DRM driver for LG LH609QH1 Panel with SiliconWorks SW49410 DDIC
From: Maxime Ripard @ 2026-06-15 9:19 UTC (permalink / raw)
To: Paul Sajna
Cc: Neil Armstrong, Maarten Lankhorst, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thierry Reding, Sam Ravnborg, Jessica Zhang,
linux-kernel, dri-devel, devicetree, David Heidelberg,
phone-devel, Amir Dahan
In-Reply-To: <20260614-judyln-panel-v3-0-07f4134441bd@postmarketos.org>
[-- Attachment #1: Type: text/plain, Size: 739 bytes --]
Hi,
On Sun, Jun 14, 2026 at 05:07:57PM -0700, Paul Sajna wrote:
> This patch series adds a drm panel driver for the LG SW49410 panel found
> in the LG G7 ThinQ (codename judyln).
>
> The basic driver skeleton was generated by
> https://github.com/msm8916-mainline/linux-mdss-dsi-panel-driver-generator from the vendor
> device-tree.
>
> There seems to still be some power supply issues, the bottom-left
> corner of the screen is dark, and the rest of the screen develops
> shadow-y burn-in-like patterns when resumed after being left off for a
> while. https://i.imgur.com/oJZSHzE.jpeg
If it's not reliable, why should we merge it, especially if it can lead
to ABI-breaking changes like it happened already.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v4 4/7] drm/rcar-du: dsi: Support DSC in the pipeline
From: Laurent Pinchart @ 2026-06-15 9:19 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Magnus Damm, Marek Vasut,
Kieran Bingham, Philipp Zabel, linux-renesas-soc, linux-clk,
linux-kernel, dri-devel, devicetree
In-Reply-To: <20260615-rcar-du-dsc-v4-4-93096a1b56a3@ideasonboard.com>
Hi Tomi,
Thank you for the patch.
On Mon, Jun 15, 2026 at 09:28:09AM +0300, Tomi Valkeinen wrote:
> Enabling DSI clocks on rcar-du needs some tricks as the DU dot clock is
> provided by the DSI. Thus, we call rcar_mipi_dsi_pclk_enable() from the
> crtc, when enabling the crtc.
>
> With DSC (added in upcoming patch) in the pipeline, between the DU and
> the DSI, the above call path is broken as the crtc tries to call
> rcar_mipi_dsi_pclk_enable() on the DSC.
>
> To solve this problem, add checks to rcar_du_crtc_atomic_enable() and
> rcar_du_crtc_atomic_disable() to detect the DSC via the bridge type, and
> skip the DCS bridge when needed.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c | 18 ++++++++++++++++++
> drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c | 1 +
> 2 files changed, 19 insertions(+)
>
> diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c
> index 6c07c406f725..f14fd89f9104 100644
> --- a/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_du_crtc.c
> @@ -754,6 +754,15 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
> (BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) {
> struct drm_bridge *bridge = rcdu->dsi[rcrtc->index];
>
> + /*
> + * When we have a DSC block between the DU and the DSI,
> + * the "bridge" points to the DSC. Detect the DSC by looking
> + * at the bridge type, and skip the DSC if the bridge is not
> + * the DSI bridge.
> + */
> + if (bridge->type != DRM_MODE_CONNECTOR_DSI)
> + bridge = bridge->next_bridge;
> +
Is there a reason you don't do this in rcar_du_encoder_init() instead ?
It would avoid running this code on every enable/disable.
> rcar_mipi_dsi_pclk_enable(bridge, state);
> }
>
> @@ -796,6 +805,15 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
> (BIT(RCAR_DU_OUTPUT_DSI0) | BIT(RCAR_DU_OUTPUT_DSI1)))) {
> struct drm_bridge *bridge = rcdu->dsi[rcrtc->index];
>
> + /*
> + * When we have a DSC block between the DU and the DSI,
> + * the "bridge" points to the DSC. Detect the DSC by looking
> + * at the bridge type, and skip the DSC if the bridge is not
> + * the DSI bridge.
> + */
> + if (bridge->type != DRM_MODE_CONNECTOR_DSI)
> + bridge = bridge->next_bridge;
> +
> /*
> * Disable the DSI clock output, see
> * rcar_du_crtc_atomic_enable().
> diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
> index aaafee1c060b..f429f03a380c 100644
> --- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
> +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
> @@ -957,6 +957,7 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host *host,
>
> /* Initialize the DRM bridge. */
> dsi->bridge.of_node = dsi->dev->of_node;
> + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
> drm_bridge_add(&dsi->bridge);
>
> return 0;
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v3 4/4] Revert "dt-bindings: display: panel: panel-simple: Add lg,sw49410 compatible"
From: Maxime Ripard @ 2026-06-15 9:17 UTC (permalink / raw)
To: Paul Sajna
Cc: Neil Armstrong, Maarten Lankhorst, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thierry Reding, Sam Ravnborg, Jessica Zhang,
linux-kernel, dri-devel, devicetree, David Heidelberg,
phone-devel, Amir Dahan
In-Reply-To: <20260614-judyln-panel-v3-4-07f4134441bd@postmarketos.org>
[-- Attachment #1: Type: text/plain, Size: 574 bytes --]
On Sun, Jun 14, 2026 at 05:08:01PM -0700, Paul Sajna wrote:
> This reverts commit a74c2e55ab66519ffa2069ac9ae83cd937bff4c4.
>
> It isn't actually panel-simple-compatible, and we knew as much by the
> time this merged, but I guess maintainers needed something to prevent
> the dt-bindings error going off while I was working on these patches.
I had a look at the patch and discussion that commit was from, and I
didn't see anyone bringing up that it wasn't actually panel-simple
compatible.
If you knew as much back then, why wasn't this brought up?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply
* Re: [PATCH v4 3/7] drm/rcar-du: dsc: Add rudimentary Renesas R-Car V4H DSC driver
From: Laurent Pinchart @ 2026-06-15 9:16 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Geert Uytterhoeven, Michael Turquette, Stephen Boyd,
Andrzej Hajda, Neil Armstrong, Robert Foss, Jonas Karlman,
Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Magnus Damm, Marek Vasut,
Kieran Bingham, Philipp Zabel, linux-renesas-soc, linux-clk,
linux-kernel, dri-devel, devicetree
In-Reply-To: <20260615-rcar-du-dsc-v4-3-93096a1b56a3@ideasonboard.com>
Hi Tomi, Marek,
Thank you for the patch.
On Mon, Jun 15, 2026 at 09:28:08AM +0300, Tomi Valkeinen wrote:
> From: Marek Vasut <marek.vasut+renesas@mailbox.org>
>
> The Renesas DSC Display Stream Compression is a bridge embedded in the
> Renesas R-Car V4H SoC. The bridge performs VESA DSC encoding of up to
> 8k or 400 Mpixel/s. Add rudimentary driver, which currently acts as a
> pass-through bridge and allows DSI1 to be operational on R-Car V4H.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
> [tomi.valkeinen: use bridge->next_bridge, minor changes]
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/renesas/rcar-du/Kconfig | 12 +++
> drivers/gpu/drm/renesas/rcar-du/Makefile | 1 +
> drivers/gpu/drm/renesas/rcar-du/rcar_dsc.c | 149 +++++++++++++++++++++++++++++
> 3 files changed, 162 insertions(+)
>
> diff --git a/drivers/gpu/drm/renesas/rcar-du/Kconfig b/drivers/gpu/drm/renesas/rcar-du/Kconfig
> index 840305fdeb49..80bd770ae0f6 100644
> --- a/drivers/gpu/drm/renesas/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/renesas/rcar-du/Kconfig
> @@ -25,6 +25,18 @@ config DRM_RCAR_CMM
> def_tristate DRM_RCAR_DU
> depends on DRM_RCAR_USE_CMM
>
> +config DRM_RCAR_USE_DSC
> + bool "R-Car DU DSC Encoder Support"
> + depends on DRM_BRIDGE && OF
> + depends on DRM_RCAR_DU || COMPILE_TEST
> + default DRM_RCAR_DU
> + help
> + Enable support for the R-Car Display Unit embedded DSC encoder.
> +
> +config DRM_RCAR_DSC
> + def_tristate DRM_RCAR_DU
> + depends on DRM_RCAR_USE_DSC
> +
> config DRM_RCAR_DW_HDMI
> tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support"
> depends on DRM && OF
> diff --git a/drivers/gpu/drm/renesas/rcar-du/Makefile b/drivers/gpu/drm/renesas/rcar-du/Makefile
> index 6f132325c8b7..9ab7a0ac45d8 100644
> --- a/drivers/gpu/drm/renesas/rcar-du/Makefile
> +++ b/drivers/gpu/drm/renesas/rcar-du/Makefile
> @@ -10,6 +10,7 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o
> rcar-du-drm-$(CONFIG_DRM_RCAR_WRITEBACK) += rcar_du_writeback.o
>
> obj-$(CONFIG_DRM_RCAR_CMM) += rcar_cmm.o
> +obj-$(CONFIG_DRM_RCAR_DSC) += rcar_dsc.o
> obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
> obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o
> obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o
> diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_dsc.c b/drivers/gpu/drm/renesas/rcar-du/rcar_dsc.c
> new file mode 100644
> index 000000000000..5a2ff3149136
> --- /dev/null
> +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_dsc.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * R-Car DSC Encoder
> + *
> + * Copyright (C) 2025 Marek Vasut <marek.vasut+renesas@mailbox.org>
> + * Copyright (C) 2025 Renesas Electronics Corporation
> + */
> +
> +#include <linux/container_of.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +
> +struct rcar_dsc {
> + struct drm_bridge bridge;
> +
> + struct device *dev;
> +};
> +
> +static inline struct rcar_dsc *bridge_to_rcar_dsc(struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct rcar_dsc, bridge);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Bridge
> + */
> +
> +static int rcar_dsc_attach(struct drm_bridge *bridge,
> + struct drm_encoder *encoder,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct rcar_dsc *dsc = bridge_to_rcar_dsc(bridge);
> +
> + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
> + return -EINVAL;
> +
> + return drm_bridge_attach(encoder, dsc->bridge.next_bridge, bridge,
> + DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +}
> +
> +static void rcar_dsc_atomic_enable(struct drm_bridge *bridge,
> + struct drm_atomic_commit *commit)
> +{
> + struct rcar_dsc *dsc = bridge_to_rcar_dsc(bridge);
> +
> + WARN_ON(pm_runtime_get_sync(dsc->dev));
> +}
> +
> +static void rcar_dsc_atomic_disable(struct drm_bridge *bridge,
> + struct drm_atomic_commit *commit)
> +{
> + struct rcar_dsc *dsc = bridge_to_rcar_dsc(bridge);
> +
> + pm_runtime_put(dsc->dev);
> +}
> +
> +static enum drm_mode_status
> +rcar_dsc_bridge_mode_valid(struct drm_bridge *bridge,
> + const struct drm_display_info *info,
> + const struct drm_display_mode *mode)
> +{
> + if (mode->hdisplay < 320 || mode->hdisplay > 8190)
> + return MODE_BAD_HVALUE;
> +
> + if (mode->vdisplay < 160 || mode->vdisplay > 8190)
> + return MODE_BAD_VVALUE;
> +
> + if (mode->clock > 400000) /* Really 400 Mpixel/s */
> + return MODE_CLOCK_HIGH;
> +
> + return MODE_OK;
> +}
> +
> +static const struct drm_bridge_funcs rcar_dsc_bridge_ops = {
> + .attach = rcar_dsc_attach,
> + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> + .atomic_reset = drm_atomic_helper_bridge_reset,
> + .atomic_enable = rcar_dsc_atomic_enable,
> + .atomic_disable = rcar_dsc_atomic_disable,
> + .mode_valid = rcar_dsc_bridge_mode_valid,
> +};
> +
> +/* -----------------------------------------------------------------------------
> + * Probe & Remove
> + */
> +
> +static int rcar_dsc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct rcar_dsc *dsc;
> + int ret;
> +
> + dsc = devm_drm_bridge_alloc(dev, struct rcar_dsc, bridge,
> + &rcar_dsc_bridge_ops);
> + if (IS_ERR(dsc))
> + return PTR_ERR(dsc);
> +
> + platform_set_drvdata(pdev, dsc);
> +
> + dsc->dev = &pdev->dev;
> +
> + dsc->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node,
> + 1, 0);
> + if (IS_ERR(dsc->bridge.next_bridge))
> + return PTR_ERR(dsc->bridge.next_bridge);
> +
> + dsc->bridge.of_node = dev->of_node;
> +
> + ret = devm_drm_bridge_add(dev, &dsc->bridge);
> + if (ret)
> + return ret;
> +
> + pm_runtime_enable(&pdev->dev);
> +
> + return 0;
> +}
> +
> +static void rcar_dsc_remove(struct platform_device *pdev)
> +{
> + pm_runtime_disable(&pdev->dev);
> +}
> +
> +static const struct of_device_id rcar_dsc_of_table[] = {
> + { .compatible = "renesas,rcar-dsc" },
> + {}
> +};
> +
> +MODULE_DEVICE_TABLE(of, rcar_dsc_of_table);
> +
> +static struct platform_driver rcar_dsc_platform_driver = {
> + .probe = rcar_dsc_probe,
> + .remove = rcar_dsc_remove,
> + .driver = {
> + .name = "rcar-dsc",
> + .of_match_table = rcar_dsc_of_table,
> + },
> +};
> +
> +module_platform_driver(rcar_dsc_platform_driver);
> +
> +MODULE_DESCRIPTION("Renesas R-Car DSC Encoder Driver");
> +MODULE_LICENSE("GPL");
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [PATCH v4 2/2] phy: qcom-qmp-ufs: Add UFS PHY support on Hawi
From: palash.kambar @ 2026-06-15 9:12 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
nitin.rawat, Palash Kambar
In-Reply-To: <20260615091242.1617492-1-palash.kambar@oss.qualcomm.com>
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
Add the init sequence tables and config for the UFS QMP phy found in
the Hawi SoC.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
.../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h | 24 +++
.../qualcomm/phy-qcom-qmp-qserdes-com-v8.h | 13 +-
.../phy-qcom-qmp-qserdes-txrx-ufs-v8.h | 37 +++++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 139 ++++++++++++++++++
4 files changed, 212 insertions(+), 1 deletion(-)
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
new file mode 100644
index 000000000000..e80d3dd6a190
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_UFS_V7_H_
+#define QCOM_PHY_QMP_PCS_UFS_V7_H_
+
+/* Only for QMP V7 PHY - UFS PCS registers */
+#define QPHY_V7_PCS_UFS_PHY_START 0x000
+#define QPHY_V7_PCS_UFS_POWER_DOWN_CONTROL 0x004
+#define QPHY_V7_PCS_UFS_SW_RESET 0x008
+#define QPHY_V7_PCS_UFS_PCS_CTRL1 0x01C
+#define QPHY_V7_PCS_UFS_PLL_CNTL 0x028
+#define QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x02C
+#define QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY 0x060
+#define QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY 0x094
+#define QPHY_V7_PCS_UFS_LINECFG_DISABLE 0x140
+#define QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2 0x150
+#define QPHY_V7_PCS_UFS_READY_STATUS 0x16c
+#define QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1 0x1b8
+#define QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1 0x1c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
index d8ac4c4a2c31..d416113bcb3c 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
*/
#ifndef QCOM_PHY_QMP_QSERDES_COM_V8_H_
@@ -71,5 +71,16 @@
#define QSERDES_V8_COM_ADDITIONAL_MISC 0x1b4
#define QSERDES_V8_COM_CMN_STATUS 0x2c8
#define QSERDES_V8_COM_C_READY_STATUS 0x2f0
+#define QSERDES_V8_COM_PLL_IVCO_MODE1 0xf8
+#define QSERDES_V8_COM_CMN_IETRIM 0xfc
+#define QSERDES_V8_COM_CMN_IPTRIM 0x100
+#define QSERDES_V8_COM_VCO_TUNE_CTRL 0x13c
+#define QSERDES_V8_COM_ADAPTIVE_ANALOG_CONFIG 0x268
+#define QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE0 0x26c
+#define QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE0 0x270
+#define QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE0 0x274
+#define QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE1 0x278
+#define QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE1 0x27c
+#define QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE1 0x280
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
new file mode 100644
index 000000000000..5f923c3e64ec
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX (0x34)
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX (0x38)
+#define QSERDES_UFS_V8_TX_LANE_MODE_1 (0x80)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2 (0x1BC)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4 (0x1C4)
+#define QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4 (0x1DC)
+#define QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1 (0x2C8)
+#define QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS (0x1E4)
+#define QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3 (0x2D0)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 (0x120)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 (0xD4)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 (0xEC)
+#define QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL (0x288)
+#define QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4 (0x2B0)
+#define QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4 (0x324)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7 (0x3B4)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9 (0x3BC)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7 (0x3E0)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9 (0x3E8)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7 (0x40C)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9 (0x414)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7 (0x438)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9 (0x440)
+#define QSERDES_UFS_V8_RX_UCDR_SO_SATURATION (0xF4)
+#define QSERDES_UFS_V8_RX_TERM_BW_CTRL0 (0x1AC)
+#define QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL (0x498)
+#define QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM (0x4d0)
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 0f4ad24aa405..d4aca22c181e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -29,9 +29,11 @@
#include "phy-qcom-qmp-pcs-ufs-v4.h"
#include "phy-qcom-qmp-pcs-ufs-v5.h"
#include "phy-qcom-qmp-pcs-ufs-v6.h"
+#include "phy-qcom-qmp-pcs-ufs-v7.h"
#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
#include "phy-qcom-qmp-qserdes-txrx-ufs-v7.h"
+#include "phy-qcom-qmp-qserdes-txrx-ufs-v8.h"
/* QPHY_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
@@ -84,6 +86,13 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
};
+static const unsigned int ufsphy_v7_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V7_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V7_PCS_UFS_READY_STATUS,
+ [QPHY_SW_RESET] = QPHY_V7_PCS_UFS_SW_RESET,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V7_PCS_UFS_POWER_DOWN_CONTROL,
+};
+
static const struct qmp_phy_init_tbl milos_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
@@ -1307,6 +1316,11 @@ static const struct regulator_bulk_data sm8750_ufsphy_vreg_l[] = {
{ .supply = "vdda-pll", .init_load_uA = 18300 },
};
+static const struct regulator_bulk_data hawi_ufsphy_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 324000 },
+ { .supply = "vdda-pll", .init_load_uA = 27000 },
+};
+
static const struct qmp_ufs_offsets qmp_ufs_offsets = {
.serdes = 0,
.pcs = 0xc00,
@@ -1325,6 +1339,15 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
.rx2 = 0x1a00,
};
+static const struct qmp_ufs_offsets qmp_ufs_offsets_v7 = {
+ .serdes = 0,
+ .pcs = 0x0400,
+ .tx = 0x2000,
+ .rx = 0x2000,
+ .tx2 = 0x3000,
+ .rx2 = 0x3000,
+};
+
static const struct qmp_phy_cfg milos_ufsphy_cfg = {
.lanes = 2,
@@ -1845,6 +1868,119 @@ static const struct qmp_phy_cfg sm8750_ufsphy_cfg = {
};
+static const struct qmp_phy_init_tbl hawi_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_CFG, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_IVCO, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_IVCO_MODE1, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_IETRIM, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_IPTRIM, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_CTRL, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_ADAPTIVE_ANALOG_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x92),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE1, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE1, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xbe),
+ QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_LANE_MODE_1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX, 0x17),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL, 0x8e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4, 0xb8),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_SATURATION, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_TERM_BW_CTRL0, 0xfa),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM, 0x77),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PCS_CTRL1, 0x42),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_g5_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PLL_CNTL, 0x3b),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05),
+};
+
+static const struct qmp_phy_cfg hawi_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v7,
+ .max_supported_gear = UFS_HS_G5,
+
+ .tbls = {
+ .serdes = hawi_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(hawi_ufsphy_serdes),
+ .tx = hawi_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(hawi_ufsphy_tx),
+ .rx = hawi_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(hawi_ufsphy_rx),
+ .pcs = hawi_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(hawi_ufsphy_pcs),
+ },
+
+ .tbls_hs_overlay[0] = {
+ .pcs = hawi_ufsphy_g5_pcs,
+ .pcs_num = ARRAY_SIZE(hawi_ufsphy_g5_pcs),
+ .max_gear = UFS_HS_G5,
+ },
+
+ .vreg_list = hawi_ufsphy_vreg_l,
+ .num_vregs = ARRAY_SIZE(hawi_ufsphy_vreg_l),
+ .regs = ufsphy_v7_regs_layout,
+};
+
static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
void __iomem *serdes = qmp->serdes;
@@ -2259,6 +2395,9 @@ static int qmp_ufs_probe(struct platform_device *pdev)
static const struct of_device_id qmp_ufs_of_match_table[] = {
{
+ .compatible = "qcom,hawi-qmp-ufs-phy",
+ .data = &hawi_ufsphy_cfg,
+ }, {
.compatible = "qcom,milos-qmp-ufs-phy",
.data = &milos_ufsphy_cfg,
}, {
--
2.34.1
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY compatible
From: palash.kambar @ 2026-06-15 9:12 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
nitin.rawat, Palash Kambar, Krzysztof Kozlowski
In-Reply-To: <20260615091242.1617492-1-palash.kambar@oss.qualcomm.com>
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
Document QMP UFS PHY compatible for Hawi SoC.
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
.../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
index b2c5c9a375a3..4efe40c0dc97 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
@@ -38,6 +38,7 @@ properties:
- qcom,kaanapali-qmp-ufs-phy
- const: qcom,sm8750-qmp-ufs-phy
- enum:
+ - qcom,hawi-qmp-ufs-phy
- qcom,milos-qmp-ufs-phy
- qcom,msm8996-qmp-ufs-phy
- qcom,msm8998-qmp-ufs-phy
@@ -108,6 +109,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,hawi-qmp-ufs-phy
- qcom,milos-qmp-ufs-phy
- qcom,msm8998-qmp-ufs-phy
- qcom,sa8775p-qmp-ufs-phy
--
2.34.1
^ permalink raw reply related
* [PATCH v4 0/2] Add Hawi UFS PHY and Controller support
From: palash.kambar @ 2026-06-15 9:12 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
nitin.rawat, Palash Kambar
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
This series introduces devicetree binding documentation and PHY
initialization support required to enable UFS on this platform.
1. Devicetree binding documentation for the QMP UFS PHY
used on Qualcomm Hawi.
2. Initialization sequence tables and configuration required
for the QMP UFS PHY on Hawi SoC.
---
changes from V1
1) Addressed Dmitry's comments to fix versioning for PCS and qserdes.
2) Addressed Mani's comments and fixed missed compatible string and
binding name correction.
changes from V2
1) Addressed Dmitry's comments to remove whitespace and stray line.
changes from V3:
1) Addressed Vinod's comment on missing macros.
2) Binding patch for UFS controller has been merged, so removed here.
Palash Kambar (2):
dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY
compatible
phy: qcom-qmp-ufs: Add UFS PHY support on Hawi
.../phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 2 +
.../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h | 24 +++
.../qualcomm/phy-qcom-qmp-qserdes-com-v8.h | 13 +-
.../phy-qcom-qmp-qserdes-txrx-ufs-v8.h | 37 +++++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 139 ++++++++++++++++++
5 files changed, 214 insertions(+), 1 deletion(-)
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
--
2.34.1
^ permalink raw reply
* Re: Re: [PATCH net-next v8 6/6] riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet controller
From: 李志 @ 2026-06-15 9:08 UTC (permalink / raw)
To: sashiko-reviews; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260611013250.985401F00898@smtp.kernel.org>
> -----Original Messages-----
> From: sashiko-bot@kernel.org
> Send time:Thursday, 11/06/2026 09:32:50
> To: lizhi2@eswincomputing.com
> Cc: conor+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org
> Subject: Re: [PATCH net-next v8 6/6] riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet controller
>
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Low] Device Tree compiler warning: unit address without `reg` property.
> - [Low] Device Tree schema validation warnings: non-standard node names.
> --
>
> commit 61fe87b2af33a89c6531d0d7ec8f49899a52057e
> Author: Zhi Li <lizhi2@eswincomputing.com>
>
> riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet controller
>
> Enable the on-board Gigabit Ethernet controller on the
> HiFive Premier P550 development board.
>
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > index 131ed1fc6b2ed..edd91b04e2515 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > @@ -13,11 +13,251 @@ / {
>
> [ ... ]
>
> > chosen {
> > stdout-path = "serial0:115200n8";
> > };
> > +
> > + vcc_1v8: vcc1v8 {
> ^^^^^^
> [Severity: Low]
> Should this node be named using the generic regulator-* pattern, such as
> regulator-1v8? The current name might trigger dtbs_check validation warnings
> for the fixed-regulator schema.
>
> > + compatible = "regulator-fixed";
> > + regulator-name = "vcc1v8";
> > + regulator-always-on;
>
> [ ... ]
>
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > index c3ed93008bca1..c77bc8b1b7bc0 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > +++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
>
> [ ... ]
>
> > @@ -202,6 +205,11 @@ pmu {
> > <0x00000000 0x0000000f 0xfffffffc 0x000000ff 0x00000078>;
> > };
> >
> > + xtal24m: oscillator {
> ^^^^^^^^^^
> [Severity: Low]
> Would it be better to use the generic clock-* pattern for this node name,
> such as clock-24m? Using oscillator might trigger dtbs_check warnings
> against the fixed-clock binding schema.
>
> > + compatible = "fixed-clock";
> > + #clock-cells = <0>;
> > + };
> > +
> > soc {
> > compatible = "simple-bus";
> > ranges;
> > @@ -245,6 +253,85 @@ plic: interrupt-controller@c000000 {
> > #interrupt-cells = <1>;
> > };
> >
> > + hsp_power_domain: bus@50400000 {
> ^^^^^^^^^^^^
> [Severity: Low]
> Does this node need a reg property? It has a unit address (@50400000), which
> usually requires a matching reg property. Without it, the devicetree compiler
> might generate a unit_address_vs_reg warning.
>
> > + compatible = "simple-pm-bus";
> > + ranges;
> > + clocks = <&clk 171>;
> > + #address-cells = <2>;
> > + #size-cells = <2>;
>
It's only for the reviewer to get a full picture of the dts. It will NOT be upstreamed.
As mentioned by Andrew Lunn at:
https://lore.kernel.org/lkml/64bf6b40-b947-4ffa-8d48-4d6341931327@lunn.ch/
^ permalink raw reply
* Re: [PATCH net-next v2 2/2] net: pse-pd: add Realtek/Broadcom PSE MCU driver
From: Simon Horman @ 2026-06-15 9:07 UTC (permalink / raw)
To: jelonek.jonas
Cc: Simon Horman, o.rempel, kory.maincent, andrew+netdev, davem,
edumazet, kuba, pabeni, robh, krzk+dt, conor+dt, netdev,
devicetree, linux-kernel, daniel, bjorn
In-Reply-To: <20260612132944.460646-3-jelonek.jonas@gmail.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
net: pse-pd: add Realtek/Broadcom PSE MCU driver
This patch adds a driver for a microcontroller that fronts Realtek and
Broadcom PSE silicon on PoE switches, exposing the MCU over I2C/SMBus or
UART using a 12-byte fixed-frame protocol. The driver is split into a
shared core plus two transport modules, with a per-dialect opcode table
and parser hooks for the Realtek vs Broadcom variants.
> diff --git a/drivers/net/pse-pd/Kconfig b/drivers/net/pse-pd/Kconfig
> index 7ef29657ee5d..b065b19db126 100644
> --- a/drivers/net/pse-pd/Kconfig
> +++ b/drivers/net/pse-pd/Kconfig
> @@ -13,6 +13,34 @@ menuconfig PSE_CONTROLLER
>
> if PSE_CONTROLLER
>
> +config PSE_REALTEK
> + tristate
> + help
> + Shared core for the Realtek/Broadcom PSE MCU driver. This is
> + selected automatically by the transport options below.
> +
> +config PSE_REALTEK_I2C
> + tristate "Realtek/Broadcom PSE MCU driver (I2C transport)"
> + depends on I2C
> + select PSE_REALTEK
> + help
> + Driver for the microcontroller (MCU) that fronts the PSE
> + hardware on switches with Realtek or Broadcom PSE chips, attached
> + via I2C/SMBus. The MCU exposes a message-based protocol; the actual
> + PSE silicon is not accessed directly. To compile this driver as a
> + module, choose M here: the module will be called realtek-pse-i2c.
> +
> +config PSE_REALTEK_UART
> + tristate "Realtek/Broadcom PSE MCU driver (UART transport)"
> + depends on SERIAL_DEV_BUS
> + select PSE_REALTEK
> + help
> + Driver for the microcontroller (MCU) that fronts the PSE
> + hardware on switches with Realtek or Broadcom PSE chips, attached
> + via UART. The MCU exposes a message-based protocol; the actual PSE
> + silicon is not accessed directly. To compile this driver as a
> + module, choose M here: the module will be called realtek-pse-uart.
> +
[Medium]
The realtek, vendor prefix is used for both the Realtek dialect and the
Broadcom dialect compatibles (realtek,pse-mcu-rtk and
realtek,pse-mcu-bcm), and the binding documentation explicitly notes
that the prefix "reflects the platform" rather than the silicon vendor.
DT compatibles are stable ABI once accepted.
Would a brcm, prefix (or per-MCU-part compatibles) for the Broadcom
dialect be more appropriate, given that the BCM variant uses Broadcom
PSE silicon driven by an MCU built by Nuvoton or STMicro and has no
Realtek involvement?
Similarly, would describing the I2C wire framing (native vs SMBus) via
separate compatibles be preferable to encoding it in the
realtek,i2c-protocol DT property, and would describing the actual PSE
chip in DT (rather than relying on runtime device-id detection) match
the usual binding patterns?
> config PSE_REGULATOR
> tristate "Regulator based PSE controller"
> help
[ ... ]
> diff --git a/drivers/net/pse-pd/realtek-pse-core.c b/drivers/net/pse-pd/realtek-pse-core.c
> new file mode 100644
> index 000000000000..3a601cfb6280
> --- /dev/null
> +++ b/drivers/net/pse-pd/realtek-pse-core.c
[ ... ]
> +static int rtpse_port_cmd(struct rtpse_ctrl *pse, unsigned int port, u8 opcode, u8 arg)
> +{
> + struct rtpse_mcu_msg req, resp;
> + int ret;
> +
> + rtpse_mcu_msg_init(&req, opcode);
> + req.payload[0] = port;
> + req.payload[1] = arg;
> +
> + ret = rtpse_do_xfer(pse, &req, &resp);
> + if (ret)
> + return ret;
> +
> + if (resp.payload[0] != port || resp.payload[1] != 0)
> + return -EIO;
> +
> + return 0;
> +}
[Medium]
Can an all-zero 12-byte buffer be silently accepted as a successful
PORT_ENABLE/PORT_DISABLE on the BCM dialect for port 0?
For the BCM dialect, RTPSE_CMD_PORT_ENABLE maps to opcode 0x00, and the
checksum of eleven zero bytes is 0, so an all-zero response passes the
opcode and checksum checks in rtpse_do_xfer():
if (resp->opcode != req->opcode ||
resp->checksum != rtpse_checksum((u8 *)resp, RTPSE_MCU_MSG_SIZE - 1))
return -EBADMSG;
rtpse_port_cmd() then verifies payload[0] == port and payload[1] == 0,
both of which pass when port == 0 and arg is 0 (disable) or when arg is
1 but the MCU never observed the command and the buffer is all zero
anyway since payload[1] is checked against 0.
The seq_num field exists in struct rtpse_mcu_msg and is filled with 0xff
by rtpse_mcu_msg_init() but is never checked on the response side. Could
a seq_num round-trip check (or a non-zero opcode sentinel for the BCM
dialect) reject stale or zeroed-out frames here?
[ ... ]
> +static int rtpse_discover(struct rtpse_ctrl *pse, struct rtpse_mcu_info *info)
> +{
> + struct rtpse_mcu_ext_config ext_config;
> + unsigned long deadline;
> + int ret;
> +
> + /*
> + * The MCU may not answer on the bus yet right after power-up or
> + * enable-gpios assertion: depending on the transport it either stays
> + * silent (-ETIMEDOUT) or does not ACK its address at all (-ENXIO /
> + * -EREMOTEIO). Retry within a bounded wall-time window so a slow boot
> + * still probes, while a genuinely unresponsive MCU fails with its real
> + * error instead of deferring forever and masking it.
> + */
> + deadline = jiffies + msecs_to_jiffies(RTPSE_MCU_BOOT_TIMEOUT_MS);
> + do {
> + ret = rtpse_mcu_get_info(pse, info);
> + if (ret != -ETIMEDOUT && ret != -ENXIO &&
> + ret != -EREMOTEIO && ret != -EAGAIN)
> + break;
> + msleep(RTPSE_MCU_BOOT_RETRY_MS);
> + } while (time_before(jiffies, deadline));
[Low]
The comment says the loop is meant to tolerate a slow-boot MCU, but the
retry whitelist excludes -EBADMSG and -EIO.
rtpse_do_xfer() returns -EBADMSG when the opcode or checksum mismatch
fires, and rtpse_port_query()/rtpse_port_cmd() return -EIO when the
echoed port byte does not match the request. On a UART-attached MCU
that emits a single garbled frame while its serial peripheral
stabilises, or on an I2C-attached MCU that returns stale boot-ROM bytes
right after enable-gpios assertion, the first attempt would surface as
one of those errors rather than -ETIMEDOUT or -ENXIO, and the loop
would break out immediately.
Should -EBADMSG (and arguably -EIO) be added to the retry set so the
documented intent matches the actual behaviour?
[ ... ]
> +int rtpse_register(struct rtpse_ctrl *pse)
> +{
[ ... ]
> + if (!info.system_enable) {
> + ret = rtpse_set_global_state(pse, true);
> + /* Dialects without a global-state concept (e.g. BCM) return
> + * -EOPNOTSUPP; treat that as "no separate enable required".
> + */
> + if (ret && ret != -EOPNOTSUPP)
> + return dev_err_probe(pse->dev, ret,
> + "failed to enable PSE system\n");
> + }
> +
> + ret = regulator_enable(pse->poe_supply);
> + if (ret)
> + return dev_err_probe(pse->dev, ret, "failed to enable PoE supply\n");
> +
> + ret = devm_add_action_or_reset(pse->dev, rtpse_regulator_disable, pse->poe_supply);
> + if (ret)
> + return ret;
[Low]
If rtpse_set_global_state(pse, true) succeeds but a later step in
rtpse_register() fails (regulator_enable, devm_add_action_or_reset, or
devm_pse_controller_register), is the MCU left with the PSE subsystem
enabled while the kernel detaches?
The regulator is rolled back via rtpse_regulator_disable through
devm_add_action_or_reset, but there does not seem to be a matching
devm_add_action_or_reset to call rtpse_set_global_state(false) on
probe-failure or driver-removal. Is that asymmetry intentional?
[ ... ]
> diff --git a/drivers/net/pse-pd/realtek-pse-uart.c b/drivers/net/pse-pd/realtek-pse-uart.c
> new file mode 100644
> index 000000000000..785407b379a4
> --- /dev/null
> +++ b/drivers/net/pse-pd/realtek-pse-uart.c
[ ... ]
> +static size_t rtpse_uart_receive(struct serdev_device *serdev,
> + const u8 *buf, size_t count)
> +{
> + struct rtpse_uart *ctx = serdev_device_get_drvdata(serdev);
> + bool done = false;
> + size_t take;
> +
> + scoped_guard(spinlock_irqsave, &ctx->rx_lock) {
> + take = min(count, sizeof(ctx->rx_buf) - ctx->rx_len);
> + if (take) {
> + memcpy(ctx->rx_buf + ctx->rx_len, buf, take);
> + ctx->rx_len += take;
> + done = (ctx->rx_len == sizeof(ctx->rx_buf));
> + }
> + }
> + if (done)
> + complete(&ctx->rx_done);
> +
> + /* consume all to avoid desync/misalignment */
> + return count;
> +}
[ ... ]
> +static int rtpse_uart_send(struct rtpse_ctrl *pse, const struct rtpse_mcu_msg *req)
> +{
> + struct rtpse_uart *ctx = to_rtpse_uart(pse);
> + int written;
> +
> + /* clear any leftover rx state before transmitting */
> + reinit_completion(&ctx->rx_done);
> + scoped_guard(spinlock_irqsave, &ctx->rx_lock)
> + ctx->rx_len = 0;
[High]
Is there a race between reinit_completion() here and the asynchronous
serdev receive_buf callback when a previous transaction has timed out
with bytes still in flight?
reinit_completion() is an unlocked x->done = 0 write, and the matching
complete() in rtpse_uart_receive() is called outside rx_lock. The
following interleave seems possible:
rtpse_uart_send() runs reinit_completion() /* done = 0 */
rtpse_uart_receive() takes rx_lock, fills rx_buf
to 12 bytes, computes done=true, releases lock
rtpse_uart_send() takes rx_lock, sets rx_len = 0,
releases lock
rtpse_uart_receive() calls complete(&ctx->rx_done) /* done = 1 */
rtpse_uart_send() writes the new request
rtpse_uart_recv() wait_for_completion_timeout()
returns immediately (done was 1), then sees
rx_len == 0 and returns -EIO
rtpse_discover()'s retry whitelist covers -ETIMEDOUT, -ENXIO,
-EREMOTEIO, and -EAGAIN but not -EIO, so a single occurrence of this
race during the boot retry window would break out of the loop and turn
into a permanent dev_err_probe() failure.
Would moving complete() inside rx_lock in rtpse_uart_receive(), or
performing reinit_completion() and rx_len = 0 together inside rx_lock
while excluding the completer, close this window?
> +
> + written = serdev_device_write(ctx->serdev, (const u8 *)req, sizeof(*req),
> + RTPSE_UART_TX_TIMEOUT);
> + if (written < 0)
> + return written;
> + if (written != sizeof(*req))
> + return -EIO;
> +
> + return 0;
> +}
[ ... ]
^ permalink raw reply
* Re: [PATCH v4 4/6] drm/verisilicon: add DC8000 (DCUltraLite) display controller support
From: sashiko-bot @ 2026-06-15 9:04 UTC (permalink / raw)
To: Joey Lu; +Cc: dri-devel, devicetree, conor+dt, robh
In-Reply-To: <20260615065003.76661-5-a0987203069@gmail.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [High] Missing RUNNING bit configuration in panel_enable_ex prevents panel output.
- [High] Framebuffer enable bit placed in CRTC callbacks prevents independent plane disablement, causing Use-After-Free.
- [High] Pixel clock is disabled before writing to CRTC registers during disablement.
- [High] Uninitialized stack memory leak when reading IRQ status registers.
- [Medium] Positional clock-names array causes schema validation failure for abbreviated clock topologies.
Pre-existing issues:
- [High] DC8200 primary plane disable hook erroneously sets the enable bit.
- [High] IRQ handler registration races with drm_dev initialization, causing NULL pointer dereference.
--
commit 7f62f89410b84fe09c3b006e2a2c8a7c5dedfeaa
Author: Joey Lu <a0987203069@gmail.com>
drm/verisilicon: add DC8000 (DCUltraLite) display controller support
This commit adds support for the Verisilicon DC8000 (DCUltraLite) display
controller found on the Nuvoton MA35D1 SoC. It handles differences in register
layout, commit cycles, and clock topology by introducing a new vs_dc8000_funcs
structure.
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c
> index 9729b693d360e..9499fffbca58e 100644
> --- a/drivers/gpu/drm/verisilicon/vs_dc.c
> +++ b/drivers/gpu/drm/verisilicon/vs_dc.c
[ ... ]
> @@ -134,7 +134,10 @@ static int vs_dc_probe(struct platform_device *pdev)
> dev_info(dev, "Found DC%x rev %x customer %x\n", dc->identity.model,
> dc->identity.revision, dc->identity.customer_id);
>
> - dc->funcs = &vs_dc8200_funcs;
> + if (dc->identity.generation == VSDC_GEN_DC8200)
> + dc->funcs = &vs_dc8200_funcs;
[Severity: High]
This is a pre-existing issue, but does vs_dc8200_primary_plane_disable_ex()
fail to disable the hardware plane?
It uses regmap_set_bits() for VSDC_FB_CONFIG_EX_FB_EN instead of clearing it:
vs_dc8200.c:vs_dc8200_primary_plane_disable_ex() {
regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output),
VSDC_FB_CONFIG_EX_FB_EN);
...
}
Will the display controller continue accessing the freed memory when DRM frees
the framebuffer after the atomic commit, leading to a use-after-free?
[Severity: High]
This is also a pre-existing issue, but does vs_dc_probe() register the IRQ
handler before the DRM device is fully initialized?
If an interrupt fires immediately after devm_request_irq(), could
vs_drm_handle_irq() dereference dc->drm_dev->crtcs[i] and dc->drm_dev->base
before vs_drm_initialize() has allocated dc->drm_dev?
> + else
> + dc->funcs = &vs_dc8000_funcs;
>
> if (port_count > dc->identity.display_count) {
> dev_err(dev, "too many downstream ports than HW capability\n");
[ ... ]
> diff --git a/drivers/gpu/drm/verisilicon/vs_dc8000.c b/drivers/gpu/drm/verisilicon/vs_dc8000.c
> new file mode 100644
> index 0000000000000..be0c0d7baf52e
> --- /dev/null
> +++ b/drivers/gpu/drm/verisilicon/vs_dc8000.c
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0-only
[ ... ]
> +static void vs_dc8000_panel_enable_ex(struct vs_dc *dc, unsigned int output)
> +{
> + regmap_set_bits(dc->regs, VSDC_FB_CONFIG(output),
> + VSDC_FB_CONFIG_RESET);
> +}
[Severity: High]
Does this function miss configuring the RUNNING bit?
The commit message states that panel output starts when PANEL_CONFIG.RUNNING
is set, but this implementation only sets VSDC_FB_CONFIG_RESET. Will the
display controller fail to output pixels to the panel without setting
VSDC_DISP_PANEL_CONFIG_RUNNING?
[ ... ]
> +static void vs_dc8000_crtc_enable(struct vs_dc *dc, unsigned int output)
> +{
> + regmap_set_bits(dc->regs, VSDC_FB_CONFIG(output),
> + VSDC_FB_CONFIG_ENABLE);
> +}
[Severity: High]
Does placing the framebuffer enable bit in the CRTC enable callback prevent
independent plane disablement?
If the DRM core disables the primary plane while keeping the CRTC active,
vs_primary_plane_atomic_disable() will act as a no-op because the plane
disable hook is NULL in vs_dc8000_funcs. Will the hardware continue scanning
out from the freed framebuffer, resulting in a use-after-free and potential
IOMMU faults?
> +static void vs_dc8000_crtc_disable(struct vs_dc *dc, unsigned int output)
> +{
> + regmap_clear_bits(dc->regs, VSDC_FB_CONFIG(output),
> + VSDC_FB_CONFIG_ENABLE);
> +}
[Severity: High]
Will writing to the CRTC register during disablement cause a bus fault?
In vs_crtc_atomic_disable(), clk_disable_unprepare() is called on the
pixel clock before invoking the crtc_disable hook:
vs_crtc.c:vs_crtc_atomic_disable() {
clk_disable_unprepare(dc->pix_clk[output]);
if (dc->funcs->crtc_disable)
dc->funcs->crtc_disable(dc, output);
...
}
Does this cause vs_dc8000_crtc_disable() to access hardware registers
after their corresponding clock is disabled?
[ ... ]
> +static u32 vs_dc8000_irq_ack(struct vs_dc *dc)
> +{
> + u32 irqs;
> +
> + regmap_read(dc->regs, VSDC_DISP_IRQ_STA, &irqs);
> + return irqs;
> +}
[Severity: High]
Can this leak uninitialized stack memory?
If regmap_read() fails, the irqs variable remains uninitialized. Will this
cause the function to return garbage data that is then passed to
vs_drm_handle_irq(), potentially causing an information leak when logged by
drm_warn_once or spurious execution of VBLANK handlers?
[ ... ]
[Severity: Medium]
Will the abbreviated clock topology cause device tree validation failures?
Since the commit makes the axi and ahb clocks optional, the device tree could
use a simpler topology with just core and pix0. However, the DT binding schema
in verisilicon,dc.yaml uses a rigid positional items array for clock-names
(expecting axi at index 1). Would a node using clock-names = "core", "pix0"
fail validation because pix0 is evaluated against the const: axi requirement?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615065003.76661-1-a0987203069@gmail.com?part=4
^ permalink raw reply
* Re: [PATCH v8 1/2] dt-bindings: ufs: Document static TX Equalization settings properties
From: sashiko-bot @ 2026-06-15 9:01 UTC (permalink / raw)
To: Can Guo; +Cc: devicetree, conor+dt, linux-scsi, robh
In-Reply-To: <20260615085027.2102882-2-can.guo@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The new TX Equalization properties incorrectly use `uint32-matrix` instead of `uint32-array`, causing `dt_binding_check` validation to fail unconditionally on all valid device trees.
--
commit 3028e214ba5cd87e73e5059697a94d86be2b33c8
Author: Can Guo <can.guo@oss.qualcomm.com>
Date: Mon Jun 15 08:50:25 2026 +0000
dt-bindings: ufs: Document static TX Equalization settings properties
This commit documents vendor-neutral properties for UFS static TX
Equalization settings in UFS v5.0/UFSHCI v5.0. It defines properties
for tx-precode-enable-g6, txeq-preshoot-g[1-6], and txeq-deemphasis-g[1-6]
to compensate for channel loss and improve high-speed signal integrity.
> diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
> index ed97f56825093..145a6416e1dff 100644
> --- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml
> +++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
> @@ -105,6 +105,61 @@ properties:
> Restricts the UFS controller to rate-a or rate-b for both TX and
> RX directions.
>
> + tx-precode-enable-g6:
> + $ref: /schemas/types.yaml#/definitions/uint32-matrix
[Severity: Medium]
Should this reference /schemas/types.yaml#/definitions/uint32-array instead
of uint32-matrix?
Because uint32-matrix evaluates as an array of inner arrays, applying flat
scalar constraints like the enum sequence below makes the constraints
structurally impossible to satisfy. Will this cause make dtbs_check
validation to fail unconditionally on any device tree implementing this
property?
> + oneOf:
> + - items:
> + - description: Host_Lane0 precode
> + - description: Device_Lane0 precode
[ ... ]
> +patternProperties:
> + "^txeq-preshoot-g[1-6]$":
> + $ref: /schemas/types.yaml#/definitions/uint32-matrix
[Severity: Medium]
Does this pattern property also require uint32-array instead of
uint32-matrix for the scalar enum constraints to apply correctly?
> + oneOf:
> + - items:
> + - description: Host_Lane0 Preshoot value
> + - description: Device_Lane0 Preshoot value
[ ... ]
> + "^txeq-deemphasis-g[1-6]$":
> + $ref: /schemas/types.yaml#/definitions/uint32-matrix
[Severity: Medium]
Would changing uint32-matrix to uint32-array here as well resolve the
schema validation failures for these flat arrays?
> + oneOf:
> + - items:
> + - description: Host_Lane0 DeEmphasis value
> + - description: Device_Lane0 DeEmphasis value
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260615085027.2102882-1-can.guo@oss.qualcomm.com?part=1
^ permalink raw reply
* Re: [PATCH 0/3] ARM: dts: stm32: lxa: change stdout-path baud rate from 9600 to 115200
From: David Laight @ 2026-06-15 9:00 UTC (permalink / raw)
To: Ahmad Fatoum
Cc: Alexandre Torgue, Maxime Coquelin, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Leonard Göhrs,
Marc Kleine-Budde, Alexandre Torgue, devicetree, linux-stm32,
linux-arm-kernel, linux-kernel, kernel
In-Reply-To: <f0b7d0a0-9b75-4d63-bc1a-f0891c86b2b9@pengutronix.de>
On Mon, 15 Jun 2026 09:53:49 +0200
Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> Hello David,
>
> On 6/12/26 8:53 AM, David Laight wrote:
> > On Thu, 11 Jun 2026 22:33:18 +0200
> > Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> >
> >> Hi David,
> >>
> >> On 6/11/26 21:43, David Laight wrote:
> >>> On Thu, 11 Jun 2026 20:12:32 +0200
> >>> Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> >>>
> >>>> The LXA boards are the only STM32 boards that set stdout-path = &uart*
> >>>> instead of explicitly specifying a baud rate.
> >>>>
> >>>> This would mean the default of 9600 is used, but it goes unnoticed when
> >>>> booting normally as barebox fixes up a console= line that includes a
> >>>> baud rate.
> >>>>
> >>>> When EFI booting GRUB however, GRUB will not pass along the console=
> >>>> line and thus the board ends up with a 9600 baud Linux console,
> >>>> confusing users.
> >>>
> >>> Is it possible to determine the current baud rate (by reading the hardware
> >>> register) and default to that value.
> >>> Then if grub has initialised the uart the kernel will use the same
> >>> baud rate.
> >>
> >> I think so, yes. In addition to the register divider configuration, one
> >> would need the input clock rate as well, but that's not a problem.
> >>
> >> Do you know if any drivers already do this?
> >
> > I've seen it done somewhere, certainly x86, but possibly NetBSD.
> > That would have been preserving the baud rate set by the bios.
> > You don't want the baud rate changing half way through the boot sequence.
>
> I agree in general, but in this case here, the BIOS defaults to 115200:
That would certainly make 115200 a better default than 9600.
David
>
> https://github.com/linux-automation/meta-lxatac/blob/wrynose/meta-lxatac-bsp/recipes-bsp/barebox/files/lxatac/defconfig#L171
> https://elixir.bootlin.com/barebox/v2026.06.0/source/common/console.c#L349
>
> Cheers,
> Ahmad
>
> >
> > David
> >
> >>
> >> Nevertheless, I would like the LXA device trees changed, even if only
> >> to align them with all other existing STM32 device trees.
> >>
> >> Cheers,
> >> Ahmad
> >>
> >>
> >>>
> >>> David
> >>>
> >>>>
> >>>> This series fixes this. As the device trees were added at different
> >>>> times, they are fixed each in a separate commit with its own Fixes: tag.
> >>>>
> >>>> ---
> >>>> Ahmad Fatoum (3):
> >>>> ARM: dts: stm32: lxa-mc1: change stdout-path baud rate from 9600 to 115200
> >>>> ARM: dts: stm32: lxa-tac: change stdout-path baud rate from 9600 to 115200
> >>>> ARM: dts: stm32: fairytux2: change stdout-path baud rate from 9600 to 115200
> >>>>
> >>>> arch/arm/boot/dts/st/stm32mp153c-lxa-fairytux2.dtsi | 2 +-
> >>>> arch/arm/boot/dts/st/stm32mp157c-lxa-mc1.dts | 2 +-
> >>>> arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi | 2 +-
> >>>> 3 files changed, 3 insertions(+), 3 deletions(-)
> >>>> ---
> >>>> base-commit: 4549871118cf616eecdd2d939f78e3b9e1dddc48
> >>>> change-id: 20260611-lxa-stdout-path-baudrate-7cf454cdae07
> >>>>
> >>>> Best regards,
> >>>> --
> >>>> Ahmad Fatoum <a.fatoum@pengutronix.de>
> >>>>
> >>>>
> >>>
> >>>
> >>
> >>
> >
> >
>
^ permalink raw reply
* Re: [PATCH v2 05/16] usb: hub: Associate port@ fwnode with USB port device
From: Bartosz Golaszewski @ 2026-06-15 9:00 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Heikki Krogerus, Bartosz Golaszewski, Greg Kroah-Hartman,
Daniel Scally, Sakari Ailus, Rafael J. Wysocki, Danilo Krummrich,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Alan Stern, linux-acpi, driver-core,
linux-pm, linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Andy Shevchenko
In-Reply-To: <CAGXv+5Hf_V4=mkAc3pN8_K9i+FfH2Wv7HVJBq71-f8sMFYL3fA@mail.gmail.com>
On Fri, 12 Jun 2026 07:46:26 +0200, Chen-Yu Tsai <wenst@chromium.org> said:
> On Fri, Jun 12, 2026 at 3:54 AM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
>>
>> On Thu, Jun 11, 2026 at 06:48:56PM +0300, Heikki Krogerus wrote:
>> > On Thu, Jun 11, 2026 at 11:35:13AM +0200, Bartosz Golaszewski wrote:
>> > > On Thu, Jun 11, 2026 at 10:37 AM Andy Shevchenko
>> > > <andriy.shevchenko@linux.intel.com> wrote:
>> > > > On Thu, Jun 11, 2026 at 04:20:58AM -0400, Bartosz Golaszewski wrote:
>> > > > > On Wed, 10 Jun 2026 16:16:12 +0200, Andy Shevchenko
>> > > > > <andriy.shevchenko@linux.intel.com> said:
>> > > > > > On Wed, Jun 10, 2026 at 04:40:39PM +0800, Chen-Yu Tsai wrote:
>> > > > > >> When a USB hub port is connected to a connector in a firmware node
>> > > > > >> graph, the port itself has a node in the graph.
>> > > > > >>
>> > > > > >> Associate the port's firmware node with the USB port's device,
>> > > > > >> usb_port::dev. This is used in later changes for the M.2 slot power
>> > > > > >> sequencing provider to match against the requesting port.
>> > > > > >
>> > > > > > Okay, would this affect ACPI-based systems? if so, how?
>> > > > > > Can you elaborate on that, please?
>> > > > >
>> > > > > Is it possible that there's an ACPI device node associated with the port like
>> > > > > on some DT systems? I don't think so and there should be no impact IMO but I
>> > > > > also don't know enough about ACPI.
>> >
>> > There are device nodes for the USB ports in ACPI, and I think they get
>> > always assigned in drivers/usb/core/usb-acpi.c.
>> >
>> > > > The API is agnostic. There is a possibility to have software nodes associated
>> > > > with the port. I think the best is to be sure that ACPI-aware people who are
>> > > > experts in USB will check this (Heikki?).
>> >
>> > I can't say what's the impact from this patch - I'm not an expert with
>> > this side of USB. Is there a danger that we end up overwriting the
>> > ACPI node for the port, or something else?
>>
>> Exactly this one is my worrying, but I haven't checked the actual flow.
>
> Looking through ACPI code, ACPI_COMPANION_SET() is used, which boils
> down to
>
> set_primary_fwnode(dev, acpi_fwnode_handle(acpi_dev))
>
> This is called through
>
> usb_hub_create_port_device()
> device_register()
> device_add()
> device_platform_notify()
> acpi_device_notify()
> usb_acpi_find_companion()
> usb_acpi_find_companion_for_port()
> acpi_bind_one()
> ACPI_COMPANION_SET()
> set_primary_fwnode()
>
> Looking at device_add_software_node(), all swnodes are secondary.
>
> set_primary_fwnode() seems to be able to make the ACPI handle / fwnode
> the primary, keeping any existing fwnode as the secondary. However
> if we do end up assigning a primary fwnode to the device using
> device_set_node() as in this patch, set_primary_fwnode() is going
> to complain loudly.
>
> On another front, the ACPI representation of the USB ports looks nothing
> like the OF graphs, at least on my X1 Carbon:
>
> For a usb port device on the root hub such as
>
> /sys/bus/usb/devices/4-0:1.0/usb4-port1/firmware_node/path
>
> looks like
>
> \_SB_.PC00.XHCI.RHUB.SS01
>
> while a usb port's firmware node link
>
> /sys/bus/usb/devices/4-0:1.0/usb4-port1//firmware_node
>
> resolves to
>
> /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:19/device:1a/device:29
>
> Neither looks anything like the graph "port" / "endpoint" node names.
> So maybe we're in the clear here.
>
> Besides the loud warning from set_primary_fwnode(), the major issue stemming
> from a wrong node is that power management (through ACPI) is likely to fail.
>
> If we're still concerned, I think we can skip the assignment if the fwnode
> is an ACPI node, i.e. check it with is_acpi_node().
>
Agreed, I think this is a good compromise.
Bart
>
> I've never worked on ACPI systems, so this is just me checking the code.
>
>
> Thanks
> ChenYu
>
^ permalink raw reply
* Re: [PATCH v4 6/6] drm/verisilicon: extend Kconfig to support ARCH_MA35 platforms
From: Icenowy Zheng @ 2026-06-15 8:58 UTC (permalink / raw)
To: Joey Lu, maarten.lankhorst, mripard, tzimmermann, airlied, simona,
robh, krzk+dt, conor+dt
Cc: ychuang3, schung, yclu4, dri-devel, devicetree, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260615065003.76661-7-a0987203069@gmail.com>
在 2026-06-15一的 14:50 +0800,Joey Lu写道:
> The DCUltraLite hardware ops and HWDB entry added in the preceding
> commits
> enable the driver to work on Nuvoton MA35D1 hardware. Allow the
> driver
> to be built when ARCH_MA35 is selected; this dependency is meaningful
> only
> now that all supporting code is in place.
The explaination of patch sequence is not needed, but anyway,
`Reviewed-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>`
Thanks,
Icenowy
>
> Signed-off-by: Joey Lu <a0987203069@gmail.com>
> ---
> drivers/gpu/drm/verisilicon/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/verisilicon/Kconfig
> b/drivers/gpu/drm/verisilicon/Kconfig
> index 7cce86ec8603..295d246eb4b4 100644
> --- a/drivers/gpu/drm/verisilicon/Kconfig
> +++ b/drivers/gpu/drm/verisilicon/Kconfig
> @@ -2,7 +2,7 @@
> config DRM_VERISILICON_DC
> tristate "DRM Support for Verisilicon DC-series display
> controllers"
> depends on DRM && COMMON_CLK
> - depends on RISCV || COMPILE_TEST
> + depends on RISCV || ARCH_MA35 || COMPILE_TEST
> select DRM_BRIDGE_CONNECTOR
> select DRM_CLIENT_SELECTION
> select DRM_DISPLAY_HELPER
^ permalink raw reply
* Re: [PATCH v4 5/6] drm/verisilicon: add DCUltraLite chip identity to HWDB
From: Icenowy Zheng @ 2026-06-15 8:57 UTC (permalink / raw)
To: Joey Lu, maarten.lankhorst, mripard, tzimmermann, airlied, simona,
robh, krzk+dt, conor+dt
Cc: ychuang3, schung, yclu4, dri-devel, devicetree, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260615065003.76661-6-a0987203069@gmail.com>
在 2026-06-15一的 14:50 +0800,Joey Lu写道:
> Register the Nuvoton MA35D1 DCUltraLite chip identity in
> vs_chip_identities[]:
> model = 0x0 (DCUltraLite; Verisilicon uses 0 for this IP)
> revision = 0x5560
> customer_id = 0x305
> generation = VSDC_GEN_DC8000
> display_count = 1
> max_cursor_size = 32
I suggest make this more human-readable instead of replicating the
machine-readable data of HWDB.
My proposal here:
```
The Nuvoton MA35D1 chip contains a DCUltraLite display controller with
model number 0x0 (sic, the model name contains no number either),
revision 0x5560 and customer ID 0x305. It has a similar register map
with DC8000, only one display output and only 32x32 cursor supported.
```
>
> Placing this entry last makes it the gate that enables MA35D1
> hardware
> recognition only after all the supporting ops and DT binding changes
> are
> in place.
It's a little ambiguous that "last" here means whether the last in the
patchset or the last in the HWDB array, although I think it's not so
needed to explain the reason of the place in the patchset.
I propose just say `Adding it to the HWDB to enable it to be usable
with the verisilicon driver.` .
>
> Signed-off-by: Joey Lu <a0987203069@gmail.com>
> ---
> drivers/gpu/drm/verisilicon/vs_hwdb.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/gpu/drm/verisilicon/vs_hwdb.c
> b/drivers/gpu/drm/verisilicon/vs_hwdb.c
> index 91524d16f778..7d630a667a3f 100644
> --- a/drivers/gpu/drm/verisilicon/vs_hwdb.c
> +++ b/drivers/gpu/drm/verisilicon/vs_hwdb.c
> @@ -129,6 +129,16 @@ static struct vs_chip_identity
> vs_chip_identities[] = {
> .max_cursor_size = 64,
> .formats = &vs_formats_no_yuv444,
> },
> + {
> + .model = 0x0, /* DCUltraLite */
> + .revision = 0x5560,
> + .customer_id = 0x305,
> +
> + .generation = VSDC_GEN_DC8000,
> + .display_count = 1,
> + .max_cursor_size = 32,
> + .formats = &vs_formats_no_yuv444,
> + },
> };
>
> int vs_fill_chip_identity(struct regmap *regs,
^ permalink raw reply
* Re: [PATCH v5 2/7] clk: qcom: Add generic clkref_en support
From: Qiang Yu @ 2026-06-15 8:56 UTC (permalink / raw)
To: Stephen Boyd
Cc: Bjorn Andersson, Brian Masney, Conor Dooley, Konrad Dybcio,
Krzysztof Kozlowski, Michael Turquette, Rob Herring, Taniya Das,
linux-arm-msm, linux-clk, devicetree, linux-kernel,
krishna.chundru
In-Reply-To: <178139077723.819343.8364833855890359860@localhost.localdomain>
On Sat, Jun 13, 2026 at 03:46:17PM -0700, Stephen Boyd wrote:
> Quoting Qiang Yu (2026-06-02 01:02:18)
> > Before XO refclk is distributed to PCIe/USB/eDP PHYs, it passes through
> > a QREF block. QREF is powered by dedicated LDO rails, and the clkref_en
> > register controls whether refclk is gated through to the PHY side.
> >
> > These clkref controls are different from typical GCC branch clocks:
> > - only a single enable bit is present, without branch-style config bits
> > - regulators must be voted before enable and unvoted after disable
> >
> > Model this as a dedicated clk_ref clock type with custom clk_ops instead
> > of reusing struct clk_branch semantics.
> >
> > Also provide a common registration/probe API so the same clkref model
> > can be reused regardless of where clkref_en registers are placed, e.g.
> > TCSR on glymur and TLMM on SM8750.
> >
> > Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
> > ---
> [...]
> > diff --git a/include/linux/clk/qcom.h b/include/linux/clk/qcom.h
> > new file mode 100644
> > index 000000000000..09e2e3178cfb
> > --- /dev/null
> > +++ b/include/linux/clk/qcom.h
>
> Why are we making this file in linux/clk when only drivers/clk/qcom/ is
> going to use it? We can have some qref.h header in the qcom clk driver
> area.
The header is placed under include/linux/clk/ intentionally for reuse
across different drivers. On glymur the clkref_en registers are in TCSR,
but on SM8750 they are in TLMM, so the registration API needs to be
accessible from outside drivers/clk/qcom/. Keeping it under
include/linux/clk/ allows the TLMM driver to call qcom_clk_ref_probe().
See this earlier attempt for context:
https://lore.kernel.org/linux-arm-msm/20260202-topic-8750_tcsr-v1-4-cd7e6648c64f@oss.qualcomm.com/
- Qiang Yu
^ permalink raw reply
* Re: [PATCH v3 3/3] regulator: qcom-refgen: add support for the IPQ9650 SoC
From: Kathiravan Thirumoorthy @ 2026-06-15 8:54 UTC (permalink / raw)
To: sashiko-reviews; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260615084646.4F0A31F000E9@smtp.kernel.org>
On 6/15/2026 2:16 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The `.is_enabled` callback maps to `regulator_is_enabled_regmap` without enabling clocks, causing a synchronous bus hang on IPQ9650 during probe.
> --
>
> commit 57e8a1a06a52f828e01d53b16f6c708e7f6df23e
> Author: Kathiravan Thirumoorthy <kathiravan.thirumoorthy@oss.qualcomm.com>
>
> regulator: qcom-refgen: add support for the IPQ9650 SoC
>
> This commit adds support for the IPQ9650 SoC to the qcom-refgen regulator
> driver. It introduces explicit clock management for the REFGEN blocks, as
> they are not enabled on power up for this specific SoC.
>
>> diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c
>> index 6a3795469927e..4b8aa40d7efe0 100644
>> --- a/drivers/regulator/qcom-refgen-regulator.c
>> +++ b/drivers/regulator/qcom-refgen-regulator.c
> [ ... ]
>> +static const struct regulator_desc ipq9650_refgen_desc = {
>> + .enable_reg = REFGEN_REG_REFGEN_STATUS,
>> + .enable_mask = REFGEN_STATUS_OUT_MASK,
>> + .enable_val = REFGEN_STATUS_OUT_ENABLE,
>> + .enable_time = 5,
>> + .name = "refgen",
>> + .owner = THIS_MODULE,
>> + .type = REGULATOR_CURRENT,
>> + .ops = &(const struct regulator_ops) {
>> + .enable = qcom_ipq9650_refgen_enable,
>> + .disable = qcom_ipq9650_refgen_disable,
>> + .is_enabled = regulator_is_enabled_regmap,
> [Severity: High]
> Does this result in an unclocked MMIO read?
>
> During device probe, the regulator core calls the is_enabled callback via
> devm_regulator_register() to determine the initial state:
>
> qcom_refgen_probe()
> devm_regulator_register()
> regulator_is_enabled_regmap()
>
> Since the IPQ9650 clocks are disabled on power up and only enabled later in
> qcom_ipq9650_refgen_enable(), regulator_is_enabled_regmap() will perform an
> MMIO read on the REFGEN_REG_REFGEN_STATUS register without the required
> clocks enabled.
REFGEN block can be accessed without the clocks enabled as part of this
change. Hence there will no issue while checking the STATUS register in
the regulator_is_enabled_regmap().
>
> Could this cause a synchronous external abort and a kernel panic during
> boot?
>
>> + },
>> +};
^ permalink raw reply
* Re: [PATCH v5 5/9] block: implement NVMEM provider
From: Bartosz Golaszewski @ 2026-06-15 8:53 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan
In-Reply-To: <20260612-block-as-nvmem-v5-5-95e0b30fff90@oss.qualcomm.com>
On Fri, 12 Jun 2026 15:20:57 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> From: Daniel Golle <daniel@makrotopia.org>
>
> On embedded devices using an eMMC it is common that one or more partitions
> on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM
> data. Allow referencing the partition in device tree for the kernel and
> Wi-Fi drivers accessing it via the NVMEM layer.
>
> For now, NVMEM is only registered for the whole disk block device, as the
> OF node is currently only associated to it.
>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
> Co-developed-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> ---
> block/Kconfig | 9 ++++
> block/Makefile | 1 +
> block/blk-nvmem.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++
> block/blk.h | 8 ++++
> block/genhd.c | 4 ++
> include/linux/blk_types.h | 3 ++
> include/linux/blkdev.h | 1 +
> 7 files changed, 135 insertions(+)
>
> diff --git a/block/Kconfig b/block/Kconfig
> index 15027963472d7b40e27b9097a5993c457b5b3054..0b33747e16dc33473683706f75c92bdf8b648f7c 100644
> --- a/block/Kconfig
> +++ b/block/Kconfig
> @@ -209,6 +209,15 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
> by falling back to the kernel crypto API when inline
> encryption hardware is not present.
>
> +config BLK_NVMEM
> + bool "Block device NVMEM provider"
> + depends on OF
> + depends on NVMEM
> + help
> + Allow block devices (or partitions) to act as NVMEM providers,
> + typically used with eMMC to store MAC addresses or Wi-Fi
> + calibration data on embedded devices.
> +
> source "block/partitions/Kconfig"
>
> config BLK_PM
> diff --git a/block/Makefile b/block/Makefile
> index 7dce2e44276c4274c11a0a61121c83d9c43d6e0c..d7ac389e71902bc091a8800ea266190a43b3e63d 100644
> --- a/block/Makefile
> +++ b/block/Makefile
> @@ -36,3 +36,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \
> blk-crypto-sysfs.o
> obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o
> obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o
> +obj-$(CONFIG_BLK_NVMEM) += blk-nvmem.o
> diff --git a/block/blk-nvmem.c b/block/blk-nvmem.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..c005f059d9fe56242ebaef9905673dff902b5686
> --- /dev/null
> +++ b/block/blk-nvmem.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * block device NVMEM provider
> + *
> + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * Useful on devices using a partition on an eMMC for MAC addresses or
> + * Wi-Fi calibration EEPROM data.
> + */
> +
> +#include <linux/file.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of.h>
> +#include <linux/pagemap.h>
> +#include <linux/property.h>
> +
> +#include "blk.h"
> +
> +static int blk_nvmem_reg_read(void *priv, unsigned int from, void *val, size_t bytes)
> +{
> + blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES;
> + dev_t devt = (dev_t)(uintptr_t)priv;
> + size_t bytes_left = bytes;
> + loff_t pos = from;
> + int ret = 0;
> +
> + struct file *bdev_file __free(fput) = bdev_file_open_by_dev(devt, mode, priv, NULL);
> + if (IS_ERR(bdev_file))
> + return PTR_ERR(bdev_file);
> +
> + while (bytes_left) {
> + pgoff_t f_index = pos >> PAGE_SHIFT;
> + struct folio *folio;
> + size_t folio_off;
> + size_t to_read;
> +
> + folio = read_mapping_folio(bdev_file->f_mapping, f_index, NULL);
> + if (IS_ERR(folio)) {
> + ret = PTR_ERR(folio);
> + break;
> + }
> +
> + folio_off = offset_in_folio(folio, pos);
> + to_read = min(bytes_left, folio_size(folio) - folio_off);
> + memcpy_from_folio(val, folio, folio_off, to_read);
> + pos += to_read;
> + bytes_left -= to_read;
> + val += to_read;
> + folio_put(folio);
> + }
> +
> + return ret;
> +}
> +
> +void blk_nvmem_add(struct block_device *bdev)
> +{
> + struct device *dev = &bdev->bd_device;
> + struct nvmem_config config = {};
> +
> + /* skip devices which do not have a device tree node */
> + if (!dev_of_node(dev))
> + return;
> +
> + /* skip devices without an nvmem layout defined */
> + struct device_node *child __free(device_node) =
> + of_get_child_by_name(dev_of_node(dev), "nvmem-layout");
> + if (!child)
> + return;
> +
> + /*
> + * skip block device too large to be represented as NVMEM devices,
> + * the NVMEM reg_read callback uses an unsigned int offset
> + */
> + if (bdev_nr_bytes(bdev) > UINT_MAX) {
> + dev_warn(dev, "block device too large to be an NVMEM provider\n");
> + return;
> + }
> +
> + config.id = NVMEM_DEVID_NONE;
> + config.dev = dev;
> + config.name = dev_name(dev);
> + config.owner = THIS_MODULE;
> + config.priv = (void *)(uintptr_t)dev->devt;
> + config.reg_read = blk_nvmem_reg_read;
> + config.size = bdev_nr_bytes(bdev);
> + config.word_size = 1;
> + config.stride = 1;
> + config.read_only = true;
> + config.root_only = true;
> + config.ignore_wp = true;
> + config.of_node = to_of_node(dev->fwnode);
> +
> + bdev->bd_nvmem = nvmem_register(&config);
> + if (IS_ERR(bdev->bd_nvmem)) {
> + dev_err_probe(dev, PTR_ERR(bdev->bd_nvmem),
> + "Failed to register NVMEM device\n");
Using dev_err_probe() only makes sense with a return value. Which makes me
think: we won't retry this after a probe deferral. I think we should return
int from this function just for this use-case. Also: if we *do* have
a layout, shouldn't we treat a failure to register the nvmem provider as
a an error and propagate it up the stack?
> + bdev->bd_nvmem = NULL;
> + }
> +}
> +
> +void blk_nvmem_del(struct block_device *bdev)
> +{
> + if (bdev->bd_nvmem)
Nvmem core already performs a NULL check.
> + nvmem_unregister(bdev->bd_nvmem);
> +
> + bdev->bd_nvmem = NULL;
> +}
> diff --git a/block/blk.h b/block/blk.h
> index ec4674cdf2ead4fd259ff5fc42401f591e684ee9..cd3c7ca723391c40be56f1dd4810e641b7c8a2b3 100644
> --- a/block/blk.h
> +++ b/block/blk.h
> @@ -757,4 +757,12 @@ static inline void blk_debugfs_unlock(struct request_queue *q,
> memalloc_noio_restore(memflags);
> }
>
> +#ifdef CONFIG_BLK_NVMEM
> +void blk_nvmem_add(struct block_device *bdev);
> +void blk_nvmem_del(struct block_device *bdev);
> +#else
> +static inline void blk_nvmem_add(struct block_device *bdev) {}
> +static inline void blk_nvmem_del(struct block_device *bdev) {}
> +#endif
> +
> #endif /* BLK_INTERNAL_H */
> diff --git a/block/genhd.c b/block/genhd.c
> index 7d6854fd28e95ae9134309679a7c6a937f5b7db8..1b2382de6fb30c1e5f60f45c04dc03ed3bf5d5f2 100644
> --- a/block/genhd.c
> +++ b/block/genhd.c
> @@ -421,6 +421,8 @@ static void add_disk_final(struct gendisk *disk)
> */
> dev_set_uevent_suppress(ddev, 0);
> disk_uevent(disk, KOBJ_ADD);
> +
> + blk_nvmem_add(disk->part0);
> }
>
> blk_apply_bdi_limits(disk->bdi, &disk->queue->limits);
> @@ -704,6 +706,8 @@ static void __del_gendisk(struct gendisk *disk)
>
> disk_del_events(disk);
>
> + blk_nvmem_del(disk->part0);
> +
> /*
> * Prevent new openers by unlinked the bdev inode.
> */
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 8808ee76e73c09e0ceaac41ba59e86fb0c4efc64..ace6f59b860d0813665b2f62a1c03a1f4be94059 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -73,6 +73,9 @@ struct block_device {
> int bd_writers;
> #ifdef CONFIG_SECURITY
> void *bd_security;
> +#endif
> +#ifdef CONFIG_BLK_NVMEM
> + struct nvmem_device *bd_nvmem;
> #endif
> /*
> * keep this out-of-line as it's both big and not needed in the fast
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 890128cdea1ce66863c5baa36f3b336ec4550807..f15d2b5bf9e4fd2368b8a70416a978e22c0d4333 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -30,6 +30,7 @@
>
> struct module;
> struct request_queue;
> +struct nvmem_device;
> struct elevator_queue;
> struct blk_trace;
> struct request;
>
> --
> 2.34.1
>
>
I like this approach better than the previous one.
Thanks,
Bartosz
^ permalink raw reply
* [PATCH v4 2/2] thermal/drivers/qcom/tsens: Add support for ipq9650 tsens
From: Varadarajan Narayanan @ 2026-06-15 8:52 UTC (permalink / raw)
To: amitk, thara.gopinath, rafael, daniel.lezcano, rui.zhang,
lukasz.luba, robh, krzk+dt, conor+dt, linux-arm-msm, linux-pm,
devicetree, linux-kernel
Cc: Varadarajan Narayanan, Konrad Dybcio, Dmitry Baryshkov
In-Reply-To: <20260615085218.1421347-1-varadarajan.narayanan@oss.qualcomm.com>
ipq9650's tsens is similar to ipq5332 tsens but has different number of
sensors. Re-use the ipq5332 data for ipq9650 and modify the sensor related
information.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>
---
v4: Pick R-b Dmitry Baryshkov
---
drivers/thermal/qcom/tsens-v2.c | 8 ++++++++
drivers/thermal/qcom/tsens.c | 3 +++
drivers/thermal/qcom/tsens.h | 2 +-
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c
index 2ee117aa91ba..70ee5ca4ece2 100644
--- a/drivers/thermal/qcom/tsens-v2.c
+++ b/drivers/thermal/qcom/tsens-v2.c
@@ -299,6 +299,14 @@ const struct tsens_plat_data data_ipq5424 = {
.fields = tsens_v2_regfields,
};
+const struct tsens_plat_data data_ipq9650 = {
+ .num_sensors = 11,
+ .ops = &ops_ipq5332,
+ .hw_ids = (unsigned int []){5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ .feat = &ipq5332_feat,
+ .fields = tsens_v2_regfields,
+};
+
/* Kept around for backward compatibility with old msm8996.dtsi */
struct tsens_plat_data data_8996 = {
.num_sensors = 13,
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 6e3714ecab1d..3e09a06db06b 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -1173,6 +1173,9 @@ static const struct of_device_id tsens_table[] = {
}, {
.compatible = "qcom,ipq8074-tsens",
.data = &data_ipq8074,
+ }, {
+ .compatible = "qcom,ipq9650-tsens",
+ .data = &data_ipq9650,
}, {
.compatible = "qcom,mdm9607-tsens",
.data = &data_9607,
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index e8376accdff3..2514f1161794 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -676,7 +676,7 @@ extern const struct tsens_plat_data data_ipq5018;
/* TSENS v2 targets */
extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
-extern const struct tsens_plat_data data_ipq5332, data_ipq5424;
+extern const struct tsens_plat_data data_ipq5332, data_ipq5424, data_ipq9650;
/* TSENS automotive targets */
extern struct tsens_plat_data data_automotive_v2;
--
2.34.1
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: thermal: tsens: add ipq5210 & ipq9650 compatible
From: Varadarajan Narayanan @ 2026-06-15 8:52 UTC (permalink / raw)
To: amitk, thara.gopinath, rafael, daniel.lezcano, rui.zhang,
lukasz.luba, robh, krzk+dt, conor+dt, linux-arm-msm, linux-pm,
devicetree, linux-kernel
Cc: Varadarajan Narayanan
In-Reply-To: <20260615085218.1421347-1-varadarajan.narayanan@oss.qualcomm.com>
Add the compatible for the thermal sensors on the ipq5210 and ipq9650. The
ipq5210 uses ipq5332-tsens as a fallback, while ipq9650 is added as a
standalone v2 TSENS compatible with combined interrupt.
Signed-off-by: Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>
---
v4: Fix version number
v3: patch version no. mixup
Include ipq9650 to all applicable constraints
https://lore.kernel.org/linux-arm-msm/20260610081241.1468507-1-varadarajan.narayanan@oss.qualcomm.com/
v2: Fix fallback definition
https://lore.kernel.org/linux-arm-msm/20260609065447.4024695-1-varadarajan.narayanan@oss.qualcomm.com/
---
.../devicetree/bindings/thermal/qcom-tsens.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index f0efaa8349ee..bcec314e0532 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -95,6 +95,13 @@ properties:
- qcom,ipq5332-tsens
- qcom,ipq5424-tsens
- qcom,ipq8074-tsens
+ - qcom,ipq9650-tsens
+
+ - description: v2 of TSENS with combined interrupt
+ items:
+ - enum:
+ - qcom,ipq5210-tsens
+ - const: qcom,ipq5332-tsens
- description: v2 of TSENS with combined interrupt
items:
@@ -306,6 +313,7 @@ allOf:
- qcom,ipq5332-tsens
- qcom,ipq5424-tsens
- qcom,ipq8074-tsens
+ - qcom,ipq9650-tsens
then:
properties:
interrupts:
@@ -323,6 +331,7 @@ allOf:
- qcom,ipq5332-tsens
- qcom,ipq5424-tsens
- qcom,ipq8074-tsens
+ - qcom,ipq9650-tsens
- qcom,tsens-v0_1
- qcom,tsens-v1
- qcom,tsens-v2
--
2.34.1
^ permalink raw reply related
* [PATCH v4 0/2] Add support tsens in ipq5210 & ipq9650
From: Varadarajan Narayanan @ 2026-06-15 8:52 UTC (permalink / raw)
To: amitk, thara.gopinath, rafael, daniel.lezcano, rui.zhang,
lukasz.luba, robh, krzk+dt, conor+dt, linux-arm-msm, linux-pm,
devicetree, linux-kernel
Cc: Varadarajan Narayanan
ipq5210 and ipq9560 have the Qualcomm tsens-v2 IP. The tsens framework
in these two SoCs are similar to the one found in ipq5332. This series
adds the sensor data to the tsens-v2 driver.
v4: Fix version number
v3: (incorrect version number)
Add additional constraints for ipq9650
https://lore.kernel.org/linux-arm-msm/20260610081241.1468507-1-varadarajan.narayanan@oss.qualcomm.com/
v2: Combine bindings and driver patches
Use fallback for ipq5210 and dropped the driver changes
https://lore.kernel.org/linux-arm-msm/20260609065447.4024695-1-varadarajan.narayanan@oss.qualcomm.com/
v1: bindings - https://lore.kernel.org/linux-arm-msm/20260515-tsens-yaml-v1-1-8039c62cc249@oss.qualcomm.com/
driver - https://lore.kernel.org/linux-arm-msm/20260515-tsens-driver-v1-0-015ca76f1418@oss.qualcomm.com/
Varadarajan Narayanan (2):
dt-bindings: thermal: tsens: add ipq5210 & ipq9650 compatible
thermal/drivers/qcom/tsens: Add support for ipq9650 tsens
.../devicetree/bindings/thermal/qcom-tsens.yaml | 9 +++++++++
drivers/thermal/qcom/tsens-v2.c | 8 ++++++++
drivers/thermal/qcom/tsens.c | 3 +++
drivers/thermal/qcom/tsens.h | 2 +-
4 files changed, 21 insertions(+), 1 deletion(-)
--
2.34.1
^ permalink raw reply
* [PATCH v8 1/2] dt-bindings: ufs: Document static TX Equalization settings properties
From: Can Guo @ 2026-06-15 8:50 UTC (permalink / raw)
To: krzk, bvanassche, beanhuo, peter.wang, martin.petersen, mani
Cc: linux-scsi, Can Guo, Alim Akhtar, Avri Altman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ram Kumar Dwivedi,
Zhaoming Luo,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list
In-Reply-To: <20260615085027.2102882-1-can.guo@oss.qualcomm.com>
UFS v5.0/UFSHCI v5.0 adds HS-G6 support (46.6 Gbps/lane) via UniPro
v3.0 and M-PHY v6.0. These specs define TX Equalization for all
High-Speed Gears (not only HS-G6) to compensate channel loss and
improve signal integrity at high speed.
For HS-G6, M-PHY uses PAM4 1b1b line coding. Pre-Coding may also be
required depending on channel characteristics.
Document vendor-neutral properties in ufs-common.yaml:
- txeq-preshoot-g[1-6]
- txeq-deemphasis-g[1-6]
- tx-precode-enable-g6
Values are per-lane Host/Device tuples (2 values for x1, 4 values for
x2). PreShoot/DeEmphasis range from 0..7, and Precode is 0/1.
These are board-specific signal-integrity tuning values. They depend on
channel SI/PHY characterization and validation (host PHY, device PHY,
package, and board routing), and are determined by HW/PHY designers.
Although UFSHCI v5.0 supports TX Equalization Training via UniPro v3.0,
which allows host software to determine optimal TX Equalization at
runtime, static board-specific TX Equalization settings in the Device
Tree are still necessary because:
- TX Equalization Training is not supported for HS-G3 and below
- TX Equalization Training is disabled on some platforms
Signed-off-by: Can Guo <can.guo@oss.qualcomm.com>
---
.../devicetree/bindings/ufs/ufs-common.yaml | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
index ed97f5682509..145a6416e1df 100644
--- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml
+++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
@@ -105,6 +105,61 @@ properties:
Restricts the UFS controller to rate-a or rate-b for both TX and
RX directions.
+ tx-precode-enable-g6:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ oneOf:
+ - items:
+ - description: Host_Lane0 precode
+ - description: Device_Lane0 precode
+ - items:
+ - description: Host_Lane0 precode
+ - description: Device_Lane0 precode
+ - description: Host_Lane1 precode
+ - description: Device_Lane1 precode
+ items:
+ enum: [0, 1]
+ description:
+ Static TX Precode enable values for HS-G6 only.
+
+patternProperties:
+ "^txeq-preshoot-g[1-6]$":
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ oneOf:
+ - items:
+ - description: Host_Lane0 Preshoot value
+ - description: Device_Lane0 Preshoot value
+ - items:
+ - description: Host_Lane0 Preshoot value
+ - description: Device_Lane0 Preshoot value
+ - description: Host_Lane1 Preshoot value
+ - description: Device_Lane1 Preshoot value
+ items:
+ enum: [0, 1, 2, 3, 4, 5, 6, 7]
+ description: |
+ Static TX Equalization PreShoot settings for High Speed Gears. These
+ values are programmed to the corresponding UniPro PA layer attribute
+ PA_TxEQG[1-6]Setting. Each value selects a Pre-Shoot level as defined
+ by the MIPI M-PHY specification (TX_HS_PreShoot_Setting).
+
+ "^txeq-deemphasis-g[1-6]$":
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ oneOf:
+ - items:
+ - description: Host_Lane0 DeEmphasis value
+ - description: Device_Lane0 DeEmphasis value
+ - items:
+ - description: Host_Lane0 DeEmphasis value
+ - description: Device_Lane0 DeEmphasis value
+ - description: Host_Lane1 DeEmphasis value
+ - description: Device_Lane1 DeEmphasis value
+ items:
+ enum: [0, 1, 2, 3, 4, 5, 6, 7]
+ description: |
+ Static TX Equalization DeEmphasis settings for High Speed Gears. These
+ values are programmed to the corresponding UniPro PA layer attribute
+ PA_TxEQG[1-6]Setting. Each value selects a De-Emphasis level as defined
+ by the MIPI M-PHY specification (TX_HS_DeEmphasis_Setting).
+
dependencies:
freq-table-hz: [ clocks ]
operating-points-v2: [ clocks, clock-names ]
--
2.34.1
^ 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