Skip to content

Conversation

@decsny
Copy link
Member

@decsny decsny commented Mar 20, 2025

  • Problem Description:

    1. SPI transaction timing (and some other) parameters mostly come from the SPI bus peripherals, not the controller. This information is found by looking at the datasheets for the SPI devices. These are hardware requirements and should be specified on the bus peripheral nodes in DT.
    2. Currently, delay value can only be provided for a GPIO CS in microseconds. This is, in almost all cases, not useful if the timing is really important, because almost all the spi device timing requirements for these parameters are on the order of a few nanoseconds. Many SPI controller have the ability to natively handle these timings without a GPIO CS, so this RFC is giving a way to configure the actual controller hardware properly. Especially for small transfers, if maximum resolution on these parameter is in 1 microsecond increments, but the transfer is only one byte which can be transferred in nanoseconds on the bus, then this is a huge waste of time on utilizing the SPI bus efficiently.
  • Proposed Change:
    Add the parameters to the common spi-device.yaml DT binding file, based on same linux parameters. Get these values from DT in the SPI DT macros. Add to the spi config structs to be able to pass this info to the drivers through the SPI API calls.

  • Detailed RFC:

  • Dependencies:
    Impact to users of the API will be that they just need to remove the third argument (delay) from the SPI DT macros, as this will now automatically get retrieved from DT by the same macros, so this argument is no longer necessary. If they don't make this change then there will be a build-time preprocessor error. The rest of the API change was intentionally designed to be backward compatible and not to cause any other breakages.

Expand the struct spi_cs_control to be able to specify hardware timing parameters for a SPI peripheral, primarily intended to be generated from properties in DT on the spi device nodes, inspired by linux binding at https://www.kernel.org/doc/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml

Support these parameters in NXP LPSPI driver

If the PR approach is okay, then TODO on this PR:

  • Figure out what new testing is needed
  • Documentation review
  • Update release notes / migration guide about changes to multiple things that are consumers of SPI in addition to SPI changes themselves.
  • Update driver API version?
  • Fixing any CI issues

Copy link
Contributor

@tbursztyka tbursztyka left a comment

Choose a reason for hiding this comment

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

This needs further thoughts.

For instance, you set the size of the ns delay to uint8_t, will that be sufficient in all cases?

Another issue as well: how device drivers are going to know which from the delay to the anonymous struct to use? there is no flag anywhere for mitigation. Unless we want to move to a new delay system, which case we will need to make delay attribute obsolete etc...

a few additional comments inline

};

/** @brief Delay between data frames in nanoseconds (0 means 50% of frequency) */
uint16_t dfs_delay_ns;
Copy link
Contributor

Choose a reason for hiding this comment

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

and this could go into the anonymous struct you added, in the union.

That way: to change in structure size.

That said, this is very much spi controller specific. Some controller do not offer anything to configure this.
And 0 as 50% of the frequency, why? why not just "hardware default"?

Copy link
Member Author

@decsny decsny Mar 21, 2025

Choose a reason for hiding this comment

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

I thought about this too but since the struct was called spi_cs_control and this was not related I thought it would be confusing

the reason for 50% of period is because of the same reason that is motivating this PR, which is that the hardware default for the NXP spi is the shortest possible, which causes problems and looks strange, and people often report it as a bug because the users actually expect that the behavior will be 50% of period by default, and don't even think about configuring it.

And this expectation is I think , not specific to people using the NXP part. A 50% delay of clk period between words means that the clock signal does not have any blips between words. Also this makes perhaps applications more portable because the hardware default can be totally different between parts but like I said maybe they just always expect 50% of period like has been reported to me

* Delay in microseconds to wait before starting the
* transmission and before releasing the CS line.
* Timing configuration.
* For GPIO CS, delay is microseconds to wait before starting
Copy link
Contributor

Choose a reason for hiding this comment

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

this was not only meant for gpio cs actually. thus why the structure was called spi_cs_control, and not spi_gpio_cs_control (for instance)

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, that was convenient that it was already named generically, I noticed

@decsny
Copy link
Member Author

decsny commented Mar 21, 2025

This needs further thoughts.

For instance, you set the size of the ns delay to uint8_t, will that be sufficient in all cases?

I think almost all data sheets I have seen have CS delay parameters of < 10 ns, but if someone knows about some relevant hardware that is going to need delays of over 1/4 of a microsecond then I am open to putting them at uint16_t. I thought about doing this but the reason I put at uint8_t is because there are also some other CS related timing parameters that people might want to add in the future. But maybe not since I think many of them such as like pcs-pcs delay are not relevant to zephyr API since we expect CS asserted through whole spi_buf_set.

Another issue as well: how device drivers are going to know which from the delay to the anonymous struct to use? there is no flag anywhere for mitigation. Unless we want to move to a new delay system, which case we will need to make delay attribute obsolete etc...

Actually, this is not an issue, and I did think it out, but does require a change on this PR, which is on my TODO list in the PR message, maybe I didn't explain it well or should have finished the work before submitting the PR, but I'm just low on bandwidth so wanted the idea reviewed before I did it.

Basically this information about the chip select pretty much always comes from DT already right now, for GPIO CS. And there is no source of information for native CS. GPIO cs information comes from the cs-gpios property on the DT node and is initialized by the SPI_DT_SPEC_GET macro. That macro can just be edited to use initialize the struct using the new spi timing properties on the peripheral nodes if they are there and there is no cs-gpios, to initialize the struct to be gpio port as null and use the hw timing members of the union

@decsny decsny added the DNM This PR should not be merged (Do Not Merge) label Mar 21, 2025
@decsny
Copy link
Member Author

decsny commented Mar 21, 2025

I forgot to put DNM since this PR is really only a WIP draft but I opened it as non-draft to get feedback on the idea from relevant reviewers

@tbursztyka
Copy link
Contributor

Basically this information about the chip select pretty much always comes from DT already right now, for GPIO CS. And there is no source of information for native CS.

The source of native CS is reg in spi-device.yaml. Not very much intuitive I agree as is also selects the right slot of cs-gpios when this one is present.

@decsny
Copy link
Member Author

decsny commented Mar 27, 2025

Basically this information about the chip select pretty much always comes from DT already right now, for GPIO CS. And there is no source of information for native CS.

The source of native CS is reg in spi-device.yaml. Not very much intuitive I agree as is also selects the right slot of cs-gpios when this one is present.

I'm not seeing anything there right now, which property are you talking about? To be clear I am saying I will add it on this PR if we agree about this. Right now I just see spi-cpol, spi-cpha, spi-hold-cs,frame-format,spi-max-frequency, and duplex on the spi-device.yaml. Maybe you are thinking about the spi-controller.yaml ?

To be clear, the main point of what I am saying here is that the spi clock timing parameters should be defined on the device/slave/peripheral DT node, and not the controller/master node. Right now we have at least spi-max-frequency on the SPI device nodes, but we also should put these other timing parameters which would come from the datasheets of spi devices to describe the digital AC characteristics of the signals required to interface properly to the device.

Now as for whether to use a gpio or not for CS, that should remain on the controller node

/** @brief Delay from PCS assertion to first SCK edge in nanoseconds.
* If set to 0, hardware default will be used.
*/
uint8_t pcs_to_sck_delay_ns;
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious what the standard is here, was looking at this relative to dw_spi and the delay is clock speed relative, not time relative. Might be worth also adding some helpers.

Copy link
Member Author

Choose a reason for hiding this comment

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

For NXP, the register programming model is also relative to an equation relating some clock speed and transfer prescalers, and not nanoseconds. But since this is generic API it seems better to use a standard unit which would mean the same no matter the platform, and driver can calculate how to program hardware.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then that follows up that we should create some generic helpers if common platforms are going to be doing the same math

Copy link
Member Author

@decsny decsny Apr 1, 2025

Choose a reason for hiding this comment

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

No, because the math is completely platform specific, that's the point of why we need to specify in ns in the first place

@decsny
Copy link
Member Author

decsny commented Apr 1, 2025

FYI I plan to flesh out this PR based on discussion and remaining TODO I mentioned, but not a top priority for a few weeks probably

@github-actions
Copy link

github-actions bot commented Jun 1, 2025

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Jun 1, 2025
@decsny decsny marked this pull request as draft June 1, 2025 02:28
@github-actions github-actions bot removed the Stale label Jun 2, 2025
@decsny
Copy link
Member Author

decsny commented Jul 30, 2025

I think I am going to try to work on this PR again, I think the goal specifically should be to associate timing parameters with the peripherals of the bus, as opposed to the controller, and then have the controller be able to tell what it should do based on what the peripheral needs. That's what is actually important I think. And not worrying so much about native vs gpio control etc.

@decsny decsny changed the title include: spi.h: Add native HW timing parameters to config API struct WIP: RFC: Add parameters to spi peripherals Jul 30, 2025
@decsny decsny requested a review from kartben September 25, 2025 15:42
@zephyrbot zephyrbot requested a review from erwango September 25, 2025 15:44
Add spi parameters for spi peripherals to spi-device.yaml.

These properties and their names are mostly inspired by linux
spi-peripheral-props.yaml.

Signed-off-by: Declan Snyder <[email protected]>
The CS delay parameter did not make a distinction between the setup and
hold time of the CS, and also did not specify very fine control which
can be done usually by a native controller CS. So use the new nanosecond
DT properties to get the delay values and make distinction.

Add deprecation warning if consumer supplies the delay parameter and
make it still work the old way in that case for backward compatibility
following API lifecycle process.

Update driver API version to 1.1.0 due to this change

Signed-off-by: Declan Snyder <[email protected]>
Convert all drivers and other consumers to use SPI macros without the
delay parameters.

Signed-off-by: Declan Snyder <[email protected]>
- Get bit ordering from DT property in SPI_CONFIG_DT.
  More precisely, set LSB first if set in DT.

- Get CS polarity from DT property in SPI_CONFIG_DT.

- Add inter-word delay parameter to spi_config struct. If value is 0, the
  value will be half of the period.

Signed-off-by: Declan Snyder <[email protected]>
Use the timing params from spi_config that are specific to the slave
instead of using the same timing for the controller for all slaves.
Remove these properties from the LPSPI DT binding.

Signed-off-by: Declan Snyder <[email protected]>
Tested case of using these new properties

Signed-off-by: Declan Snyder <[email protected]>
@decsny
Copy link
Member Author

decsny commented Sep 29, 2025

update: rebase, fix build error in ADC driver, change names from lead->setup_ns and lag->hold_ns

@sonarqubecloud
Copy link

@decsny
Copy link
Member Author

decsny commented Sep 29, 2025

@tbursztyka @bjarki-andreasen @erwango @kartben review preferably before next merge conflict

@jhedberg jhedberg merged commit 48a9b04 into zephyrproject-rtos:main Oct 1, 2025
30 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Architecture Review Oct 1, 2025
@jhedberg
Copy link
Member

jhedberg commented Oct 1, 2025

@decsny looks like this caused a CI failure in main: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18160982496/job/51691443328

zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj -MF zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj.d -o zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj -c /__w/zephyr/zephyr/drivers/sensor/pni/rm3100/rm3100.c
/__w/zephyr/zephyr/drivers/sensor/pni/rm3100/rm3100.c:262:29: error: too many arguments provided to function-like macro invocation
  262 | DT_INST_FOREACH_STATUS_OKAY(RM3100_DEFINE)
      |                             ^
/__w/zephyr/zephyr/include/zephyr/drivers/spi.h:1364:9: note: macro 'SPI_DT_IODEV_DEFINE' defined here
 1364 | #define SPI_DT_IODEV_DEFINE(name, node_id, operation_)                          \
      |         ^
1 error generated.
ninja: build stopped: subcommand failed.

@jhedberg
Copy link
Member

jhedberg commented Oct 1, 2025

@decsny looks like this caused a CI failure in main: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18160982496/job/51691443328

My attempt at fixing this: #96859

@decsny
Copy link
Member Author

decsny commented Oct 1, 2025

@decsny looks like this caused a CI failure in main: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18160982496/job/51691443328

zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj -MF zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj.d -o zephyr/drivers/sensor/pni/rm3100/CMakeFiles/drivers__sensor__pni__rm3100.dir/rm3100.c.obj -c /__w/zephyr/zephyr/drivers/sensor/pni/rm3100/rm3100.c
/__w/zephyr/zephyr/drivers/sensor/pni/rm3100/rm3100.c:262:29: error: too many arguments provided to function-like macro invocation
  262 | DT_INST_FOREACH_STATUS_OKAY(RM3100_DEFINE)
      |                             ^
/__w/zephyr/zephyr/include/zephyr/drivers/spi.h:1364:9: note: macro 'SPI_DT_IODEV_DEFINE' defined here
 1364 | #define SPI_DT_IODEV_DEFINE(name, node_id, operation_)                          \
      |         ^
1 error generated.
ninja: build stopped: subcommand failed.

yeah i am not surprised TBH, I tried to keep up with all the changes on main while I was waiting for reviews but it was taking a long time. I think at least one of the failure was a new usage of the macro in a new sensor driver someone added literally a few hours or less before this PR merged.

@KurtE
Copy link
Contributor

KurtE commented Oct 9, 2025

Quick follow on to the issue I created yesterday #97212 - which was closed.

I have some test sketches that use SPI, but do not use the hardware CS pins. I suspect that will run into this again with
the Arduino wrapper of SPI. In my case I am trying to run my own display driver code: ST7796 on an Arduino Portenta H7.

In my overlay I have:

&spi2 {
	status = "okay";
	pinctrl-0 = <&spi2_sck_pi1
		     &spi2_miso_pc2 &spi2_mosi_pc3>;
	pinctrl-names = "default";
	/* added for sketch */
	generic_tft_spi_dev: generic_tft_spi_dev@0 {
		status = "okay";
		compatible = "vnd,spi-device";
		reg = <0>;
		spi-max-frequency = <30000000>;
	};
};

It also defines some pins I use with it for: CS, DC, Reset

/ {

	zephyr,user {
		generic_tft-gpios = <&gpioj 11 GPIO_ACTIVE_HIGH>,	/* CS D2 */
						<&gpioc 7 GPIO_ACTIVE_HIGH>,	/* DC D4 */
						<&gpiog 7 GPIO_ACTIVE_HIGH>;	/* RST D3 */
	};
};

In main line code, in this case it is main.cpp I have:

#define SPI_OP (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB )
static struct spi_dt_spec generic_tft_spi =
	SPI_DT_SPEC_GET(DT_NODELABEL(generic_tft_spi_dev), SPI_OP, 0);

Which built and ran on the Portenta using zephyr synced maybe 10+ days ago

Does not build now. The migration guide mentioned to not use the third parameter so I remove it and try to build and it still fails:

In file included from d:\zephyrproject\zephyr_test_sketches\ili9341_library\include\ili9341_giga_zephyr.h:88,
                 from D:/zephyrproject/zephyr_test_sketches/spi_build_test/src/main.cpp:21:
D:/zephyrproject/zephyr/include/zephyr/drivers/spi.h:567:9: error: designator order for field 'spi_cs_control::<anonymous>' does not match declaration order in 'spi_cs_control'
  567 |         }
      |         ^
D:/zephyrproject/zephyr_test_sketches/spi_build_test/src/main.cpp:27:9: note: in expansion of macro 'SPI_DT_SPEC_GET'
   27 |         SPI_DT_SPEC_GET(DT_NODELABEL(generic_tft_spi_dev), SPI_OP);
      |         ^~~~~~~~~~~~~~~

I found only two examples that used SPI_DT_SPEC_GET, one did not build, Nordic something... might of if I added additional
parameters to build, but that was not mentioned in Readme (sorry side track) and the other example had a CS pin and the
only thing I saw in it that maybe changed was to remove the ,0

So my question is, did this change create a new issue, or is there something else that needs to be changed in sketches
that do not use/define hardware CS pins?

Thanks

@decsny
Copy link
Member Author

decsny commented Oct 9, 2025

@KurtE that's interesting, can you check if this patch fixes that: #97292 , it's just a guess

@KurtE
Copy link
Contributor

KurtE commented Oct 9, 2025

@KurtE that's interesting, can you check if this patch fixes that: #97292 , it's just a guess

That did the trick

Thanks

static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET(
0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8),
DT_INST_PROP(0, controller_cs_delay_us));
0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8))
Copy link
Contributor

Choose a reason for hiding this comment

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

Semicolon is missing.

Copy link
Member Author

Choose a reason for hiding this comment

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

@JarmouniA
Copy link
Contributor

JarmouniA commented Oct 10, 2025

This change broke mipi-dbi-spi #97318

Proposed fix #97366

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: API Changes to public APIs area: SPI SPI bus platform: NXP Drivers NXP Semiconductors, drivers

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.