Skip to content

spi: phytium: update phytium spi controller driver support#1538

Open
newearth-ss wants to merge 7 commits intodeepin-community:linux-6.6.yfrom
newearth-ss:spi-6.6.0.3
Open

spi: phytium: update phytium spi controller driver support#1538
newearth-ss wants to merge 7 commits intodeepin-community:linux-6.6.yfrom
newearth-ss:spi-6.6.0.3

Conversation

@newearth-ss
Copy link
Contributor

@newearth-ss newearth-ss commented Mar 10, 2026

This patch updates the support for phytium spi controller driver.

Summary by Sourcery

Update Phytium SPI and QSPI controller drivers with improved SPI-NOR handling, debugging/logging support, and configuration fixes.

New Features:

  • Add debug log buffer discovery and dumping for Phytium SPI controllers using regfile configuration.

Bug Fixes:

  • Correct QSPI flash capacity encoding by using left shifts instead of right shifts.
  • Fix QSPI dummy-cycle configuration when executing operations to use the proper shift and value calculation.
  • Prevent enabling direct mapping when there are zero flashes attached to the QSPI controller.
  • Adjust SPI-NOR write/erase handling to correctly recognize erase operations and gate write commands based on the associated spi_mem instance.
  • Ensure chip select can toggle even when transfer state is active, avoiding premature returns that block CS changes.

Enhancements:

  • Mark the Phytium SPI master as half-duplex capable and wire up a debug error handler hook.
  • Increment driver version numbers for the Phytium SPI and QSPI platform drivers.
  • Change the default global chip-select configuration for the Phytium SPI v2 platform driver.

If the mtd_debug tool is used for erasing data, the user layer
does not split the erasing. The core layer handles the split
operation.

Mainline: NA
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
Functions that configure capacity registers should shift left
instead of right, which will lead to capacity register configured
error.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
The dummy bit of the cmd_port register is incorrectly
configured, which will results in a 1-1-4 indirect read error.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
If the device tree or ACPI table does not describe the flash
node, the capacity register should not be configured for the
QSPI controller driver.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
The error information is stored to the specified ddr
address, and when an exception occurs, the error
information can be retrieved from this address.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
The spi-v2 driver is adapted to the mcp251x device.
Furthermore, spi-v2 currently only supports half-duplex.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
The spi-v2 driver is adapted to the tpm device.
Furthermore, spi-v2 currently only supports half-duplex.

Mainline: Open-Source
Signed-off-by: Cui Fulong <cuifulong2112@phytium.com.cn>
Signed-off-by: Peng Min <pengmin1540@phytium.com.cn>
Signed-off-by: Wang Yinfeng <wangyinfeng@phytium.com.cn>
@deepin-ci-robot deepin-ci-robot requested a review from myml March 10, 2026 09:46
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign avenger-285714 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 10, 2026

Reviewer's Guide

Updates Phytium SPI and QSPI controller drivers to better integrate with spi-mem/spi-nor, fix capacity/dummy-cycle handling, add debug-log support, and adjust controller flags and probe defaults.

Sequence diagram for spi_mem spi_nor command handling in spi_phyt_transfer_one

sequenceDiagram
    participant spi_core
    participant spi_master
    participant phytium_spi as fts
    participant spi_device as spi
    participant spi_mem
    participant spi_nor as nor

    spi_core->>spi_master: queue transfer_one(spi, transfer)
    spi_master->>fts: spi_phyt_transfer_one(master, spi, transfer)
    activate fts
    fts->>spi: spi_get_ctldata(spi)
    fts->>spi: spi_get_drvdata(spi)
    spi-->>fts: spi_mem pointer
    alt has_spi_mem
        fts->>spi_mem: spi_mem_get_drvdata(mem)
        spi_mem-->>fts: spi_nor pointer nor
        alt single_byte_tx_for_nor
            fts->>fts: check mem == nor.spimem
            fts->>fts: set tx, rx, len
            alt tx_is_SPINOR_OP_WREN and spi_write_flag == 0
                fts->>fts: spi_phytium_write_pre(..., 0)
                fts-->>spi_master: return 0
                deactivate fts
            else tx_is_SPINOR_OP_BE_4K and spi_write_flag == 1 and flash_read == 0 and flash_erase != 1
                fts->>fts: spi_write_flag++
                fts->>fts: flash_erase = 1
                fts-->>spi_master: return 0
                activate fts
                deactivate fts
            else other_command
                fts->>fts: flags = 0
                fts->>fts: spi_phytium_write(..., flags, spi_write_flag)
                fts-->>spi_master: return status
                activate fts
                deactivate fts
            end
        else not_single_byte_or_not_nor
            fts-->>spi_master: handle as generic transfer
            activate fts
            deactivate fts
        end
    else no_spi_mem
        fts-->>spi_master: handle as generic transfer
        activate fts
        deactivate fts
    end
Loading

Class diagram for updated phytium_spi structure and callbacks

classDiagram
    class phytium_spi {
        +void __iomem *base
        +struct spi_master *master
        +u32 tx_len
        +u32 rx_len
        +void *tx
        +void *tx_end
        +void *rx
        +u32 len
        +u32 cur_rx_head
        +u32 cur_rx_tail
        +u32 cur_tx_head
        +u32 cur_tx_tail
        +struct completion cmd_completion
        +u8 flags
        +u8 spi_write_flag
        +u8 flash_erase
        +u8 flash_read
        +bool debug_enabled
        +bool alive_enabled
        +struct timer_list timer
        +u32 runtimes
        +u64 ddr_paddr
        +char *log
        +u32 log_size
        +void (*watchdog)(struct phytium_spi *fts)
        +void (*handle_debug_err)(struct phytium_spi *fts)
    }

    class spi_master {
        +struct device dev
        +u32 flags
    }

    class device {
        +struct device_node *of_node
        +struct fwnode_handle *fwnode
    }

    class spi_phyt_hw_init {
        +void spi_phyt_hw_init(struct device *dev, struct phytium_spi *fts)
    }

    class spi_handle_debug_err {
        +void spi_handle_debug_err(struct phytium_spi *fts)
    }

    class spi_phytium_print_status {
        +int spi_phytium_print_status(struct phytium_spi *fts, u8 status0, u8 status1)
    }

    class spi_phyt_add_host {
        +int spi_phyt_add_host(struct device *dev, struct phytium_spi *fts)
    }

    phytium_spi --> spi_master : master
    spi_master --> device : dev

    spi_phyt_hw_init --> phytium_spi : initializes
    spi_phyt_hw_init --> device : uses

    spi_handle_debug_err --> phytium_spi : uses

    spi_phytium_print_status --> phytium_spi : uses

    spi_phyt_add_host --> phytium_spi : configures
    spi_phyt_add_host --> spi_master : allocates

    phytium_spi ..> spi_handle_debug_err : handle_debug_err callback
    phytium_spi ..> spi_phyt_hw_init : uses log setup
    phytium_spi ..> spi_phytium_print_status : status based debug
    spi_phyt_add_host ..> spi_handle_debug_err : assigns callback
Loading

File-Level Changes

Change Details Files
Adjust SPI v2 controller transfer and chip-select handling to cooperate with spi-mem/spi-nor and refine write/erase logic.
  • Remove early returns in chip-select helper so CS toggling is no longer skipped when TX/RX buffers are active or during specific message types
  • In transfer_one, obtain spi_mem and spi_nor from the spi device driver data to identify NOR flash operations
  • Gate the WREN handling on matching the spi_mem instance and a 1-byte TX transfer to target NOR command writes only
  • Relax the BE_4K erase detection condition so it only checks that flash_erase is not already set rather than strictly zero
  • Introduce a flags field in the controller state and pass it down to spi_phytium_write instead of a hard-coded literal, resetting it before writes
drivers/spi/spi-phytium-v2.c
drivers/spi/spi-phytium.h
Add debug-log infrastructure for the SPI v2 controller, including memory-mapped log buffer setup and conditional log dumping on error.
  • Extend regfile debug bitfield definitions to cover log presence, size and address fields plus constants for DDR address high bits, per-log size, and max log line length
  • Augment controller state with DDR physical address, mapped log pointer, log buffer size, and a handle_debug_err callback
  • In hardware init, read the debug regfile value to derive DDR log buffer address and size, ioremap the buffer, and clear its contents
  • Implement spi_handle_debug_err to check the debug regfile for available logs, print them in bounded line chunks, clear the buffer, and clear the HAVE_LOG bit
  • Wire the watchdog-style debug handler into the controller instance and invoke it from spi_phytium_print_status when debug is enabled
drivers/spi/spi-phytium.h
drivers/spi/spi-phytium-v2.c
drivers/spi/spi-phytium-common.c
Set SPI master/controller flags and probe defaults to match hardware capabilities and system integration requirements.
  • Mark the spi-phytium v2 master as half-duplex in addition to GPIO-controlled chip select
  • Change the platform driver's default global_cs value from 0 to 1 during probe to alter chip select handling policy
  • Bump the spi-phytium platform v2 driver version string from 1.0.6 to 1.0.8
drivers/spi/spi-phytium-v2.c
drivers/spi/spi-phytium-plat-v2.c
Correct QSPI capacity encoding and dummy-cycle configuration, and tighten direct-mapping enable conditions.
  • Fix capacity encoding to use left shifts instead of right shifts when inserting 4-bit size codes into the capability field
  • Adjust dummy-cycle programming to use (nbytes*8 - 1)/buswidth and shift by QSPI_CMD_PORT_DUMMY_SHIFT rather than the latency shift mask, aligning with hardware spec
  • Require nonzero flash count (fnum != 0) in addition to nodirmap being false before enabling direct-mapped access in probe
  • Update the QSPI driver version string from 1.0.2 to 1.0.3
drivers/spi/spi-phytium-qspi.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot
Copy link

Hi @newearth-ss. Thanks for your PR.

I'm waiting for a deepin-community member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In spi_phyt_transfer_one(), struct spi_nor *nor can be used uninitialized or NULL (e.g. when mem == NULL or spi_mem_get_drvdata(mem) returns NULL) in the if (mem == nor->spimem && ...) condition; add proper NULL checks and initialization before dereferencing nor.
  • In spi_phyt_hw_init(), fts->log_size derived from SPI_REGFILE_SIZE_MASK can be zero, which leads to devm_ioremap() with size 0 and later loops over fts->log_size; add a guard to skip mapping and log handling when the encoded size is zero or otherwise invalid.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `spi_phyt_transfer_one()`, `struct spi_nor *nor` can be used uninitialized or NULL (e.g. when `mem == NULL` or `spi_mem_get_drvdata(mem)` returns NULL) in the `if (mem == nor->spimem && ...)` condition; add proper NULL checks and initialization before dereferencing `nor`.
- In `spi_phyt_hw_init()`, `fts->log_size` derived from `SPI_REGFILE_SIZE_MASK` can be zero, which leads to `devm_ioremap()` with size 0 and later loops over `fts->log_size`; add a guard to skip mapping and log handling when the encoded size is zero or otherwise invalid.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Phytium SPI and QSPI controller drivers with bug fixes, a new debug log buffer feature, and configuration adjustments. The changes include fixing critical shift-direction bugs in QSPI flash capacity encoding, adding debug log buffer discovery/dumping for the SPI v2 controller, adjusting SPI-NOR write/erase handling, and preventing direct mapping when no flashes are attached.

Changes:

  • Fix QSPI flash capacity encoding (right shift → left shift), dummy-cycle configuration, and direct mapping guard for zero flashes.
  • Add debug log buffer support (MMIO-mapped log region, error handler hook) and mark the SPI v2 master as half-duplex capable.
  • Adjust SPI-NOR transfer_one logic to gate write/erase commands based on the spi_mem instance, remove premature CS return guards, and change default global_cs to 1.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
drivers/spi/spi-phytium.h Add debug log defines, flags, ddr_paddr, log, log_size, and handle_debug_err fields to the phytium_spi struct
drivers/spi/spi-phytium-v2.c Remove CS early-return guards, add spi_mem/spi_nor-based gating in transfer_one, add debug log handler and hw_init log mapping, set half-duplex flag, wire up debug_err hook, fix includes
drivers/spi/spi-phytium-qspi.c Fix >> to << in capacity encoding, fix dummy cycle shift constant, add fnum != 0 guard for direct mapping, bump version
drivers/spi/spi-phytium-plat-v2.c Change default global_cs from 0 to 1, bump driver version
drivers/spi/spi-phytium-common.c Call handle_debug_err when debug is enabled and an error status is detected

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 139 to +161
@@ -158,7 +158,7 @@ static int spi_phyt_transfer_one(struct spi_master *master,
chip->tmode = TMOD_TO;
}

if (fts->tx) {
if (mem == nor->spimem && fts->tx && fts->len == 1) {
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical null-pointer dereference: when mem is NULL (i.e., the SPI device is not backed by a spi-mem driver), nor is uninitialized. On line 161, the code unconditionally dereferences nor->spimem regardless of whether mem was NULL. This will crash with a null/garbage pointer dereference for any non-SPI-NOR SPI device.

The condition should check mem before accessing nor, e.g., if (mem && mem == nor->spimem && fts->tx && fts->len == 1).

Copilot uses AI. Check for mistakes.
Comment on lines +443 to +451
fts->log = devm_ioremap(dev, fts->ddr_paddr, fts->log_size);

if (IS_ERR(fts->log)) {
dev_err(dev, "log_addr is err\n");
return;
}

for (i = 0; i < fts->log_size; i++)
fts->log[i] = 0;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

devm_ioremap() returns NULL on failure, not an ERR_PTR. The IS_ERR() check will never catch a NULL return, so a NULL fts->log will be passed through to the subsequent loop where fts->log[i] = 0 will cause a null-pointer dereference.

The check should use if (!fts->log) instead of if (IS_ERR(fts->log)).

Additionally, when log_size is 0 (the size bits in the register are zero), devm_ioremap will be called with a size of 0, which is also problematic. A guard for log_size == 0 should be added before the devm_ioremap call.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +19
#include <linux/spi/spi-mem.h>
#include <linux/mtd/spi-nor.h>
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate include: <linux/mtd/spi-nor.h> is included on both line 19 and line 27. The second include is redundant and should be removed.

Copilot uses AI. Check for mistakes.
Comment on lines +417 to +418
dev_info(dev, "log len :%d,addr: 0x%llx,size:%d\n",
len, (u64)fts->log, fts->log_size);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging a kernel pointer via (u64)fts->log leaks kernel address information to the kernel log, which is a security concern (KASLR bypass). Use %p or %px format specifier instead of casting to u64 and printing with %llx. In production code, %p is preferred as it prints a hashed pointer.

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +211
char *log;
u32 log_size;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log field is declared as char * in the struct, but devm_ioremap() returns void __iomem *. Accessing MMIO memory through a plain char * pointer using direct array indexing (e.g., fts->log[i] = 0, strnlen(fts->log, ...)) bypasses the __iomem annotation and can trigger sparse warnings. MMIO memory should be accessed through readb()/writeb() or memset_io()/memcpy_fromio() accessors.

Copilot uses AI. Check for mistakes.
Comment on lines +408 to +416
void spi_handle_debug_err(struct phytium_spi *fts)
{
struct device *dev = &fts->master->dev;
u32 reg, len, i;

reg = phytium_read_regfile(fts, SPI_REGFILE_DEBUG);

if (reg & SPI_REGFILE_HAVE_LOG) {
len = strnlen(fts->log, fts->log_size);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spi_handle_debug_err does not check if fts->log is NULL before calling strnlen(fts->log, ...) and accessing fts->log[i]. If spi_phyt_hw_init failed to map the log buffer (or log_size was 0), this will crash. A null check for fts->log and a zero check for fts->log_size should be added at the top of this function.

Copilot uses AI. Check for mistakes.
Comment on lines +261 to +264
fts->flags = 0;

ret = spi_phytium_write(fts, spi->chip_select, transfer->bits_per_word,
spi->mode, chip->tmode, 1, fts->spi_write_flag);
spi->mode, chip->tmode, fts->flags, fts->spi_write_flag);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting fts->flags = 0 and then immediately passing fts->flags as the argument on the next line is functionally equivalent to just passing 0 directly (which was the original value 1). Using an instance field (fts->flags) for what is effectively a local constant is confusing — it appears to be a field meant for some other purpose elsewhere, but here it's unconditionally set to 0 and then read. If the intent is to always pass 0 here, just pass the literal 0 and document why this changed from 1. If fts->flags is meant to carry state across calls, setting it to 0 unconditionally right before use defeats that purpose.

Copilot uses AI. Check for mistakes.
Comment on lines +419 to +424
if (len > SPI_LOG_LINE_MAX_LEN) {
for (i = 0; i + SPI_LOG_LINE_MAX_LEN < len; i += SPI_LOG_LINE_MAX_LEN)
dev_info(dev, "(log)%.*s\n", SPI_LOG_LINE_MAX_LEN, &fts->log[i]);
} else {
dev_info(dev, "(log)%.*s\n", SPI_LOG_LINE_MAX_LEN, &fts->log[0]);
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When len > SPI_LOG_LINE_MAX_LEN, the loop prints full chunks of SPI_LOG_LINE_MAX_LEN characters but never prints the remaining tail portion. For example, if len is 500, it prints characters 0-399 but characters 400-499 are silently dropped. After the for-loop, the remaining len - i bytes should also be printed.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants