Add MSPI + flash driver for the TI K3 platform#88487
Add MSPI + flash driver for the TI K3 platform#88487m-braunschweig wants to merge 2 commits intozephyrproject-rtos:mainfrom
Conversation
| uint32_t exec_status = | ||
| MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); | ||
| while (exec_status != 0 && | ||
| k_cyc_to_us_floor32(k_uptime_get() - start_cycles) < req->timeout) { |
There was a problem hiding this comment.
k_uptime_get is the current uptime in milliseconds, calling k_cyc_to_us_floor32 is probably not what you want.
The timeout parameter is not well documented, but it appears to be in milliseconds (from looking at other drivers)
There was a problem hiding this comment.
Ahh my bad, I'm not familiar with mspi driver API and only looked at the struct definition. It would be helpful to mention it there too
There was a problem hiding this comment.
Ok I will update that to use milliseconds everywhere in the MSPI driver. I will also switch over to k_uptime_get so I don't need the conversions anymore
There was a problem hiding this comment.
Also: How are the Kconfig option and timeout field correlated? For me it seems quite unclear since it's used both in flash and MSPI drivers, additionally to the already existing timeout field
There was a problem hiding this comment.
Also: How are the Kconfig option and timeout field correlated? For me it seems quite unclear since it's used both in flash and MSPI drivers, additionally to the already existing
timeoutfield
The Kconfig option is offered as a setting to the controllers for its maximum timeout allowence. The timeout field is variable in the transfer struct but should not exceed this Kconfig option.
| MSPI_TI_K3_REG_WRITE(0, CONFIG, RESET_PIN, base_addr); | ||
|
|
||
| /* general clock cycle delays */ | ||
| MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_NSS, base_addr); |
There was a problem hiding this comment.
Seems like the chip select delay should come from struct mspi_ce_control
There was a problem hiding this comment.
No, not really. struct mspi_ce_control is for software controlled CE. However, I do think that this CE timing maybe peripheral device specific but not transfer specific. NXP have a similar setting as well. We can try add that to struct mspi_dev_cfg
Another option is to slide it in through struct mspi_timing_cfg along with your custom timing parameters.
There was a problem hiding this comment.
For now I'm going to add it to the mspi_dev_cfg to be read from the devicetree
I'm going to add a custom timing config
| #include <zephyr/sys/util.h> | ||
| #include <zephyr/sys/util_macro.h> | ||
|
|
||
| LOG_MODULE_REGISTER(flash_ti_k3_mspi, CONFIG_MSPI_LOG_LEVEL); |
There was a problem hiding this comment.
There are a number of mentions of "flash" in this file that should be removed.
This driver may be used for things other than flash memory
There was a problem hiding this comment.
Will update that. They are there because it initially started as a standalone flash driver
| int mspi_ti_k3_wait_for_idle(const struct device *controller) | ||
| { | ||
| const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); | ||
| uint32_t idle = MSPI_TI_K3_REG_READ_MASKED(CONFIG, IDLE, base_addr); |
There was a problem hiding this comment.
Consider using GENMASK/FIELD_PREP/FIELD_GET, the macro concatenations (TI_K3_OSPI_##reg##_##field##_FLD_OFFSET) make it difficult to navigate to the register definitions
#define TI_K3_OSPI_CONFIG_REG_IDLE_MASK GENMASK(31, 31)
uint32_t config_reg = sys_read32(base_addr + TI_K3_OSPI_CONFIG_REG_OFFSET);
uint32_t idle = FIELD_GET(TI_K3_OSPI_CONFIG_REG_IDLE_MASK, config_reg);There was a problem hiding this comment.
I would prefer to keep the macro since it keeps the code in the mspi_ti_k3.c quite short. I think I will add comments that explains the macros and register definitions
| }; | ||
|
|
||
| struct mspi_ti_k3_data { | ||
| struct k_mutex lock; |
There was a problem hiding this comment.
Add DEVICE_MMIO_RAM; as the first field
swift-tk
left a comment
There was a problem hiding this comment.
Are you not going to add any soc DTS for the controller?
To ensure compile across PRs, it is best to add the controller to one of the example or testcase.
| ce-gpios: | ||
| description: | | ||
| The used chip select GPIO pins. This property is not used since the driver | ||
| only supports the hardware controlled chip select pins. |
There was a problem hiding this comment.
It is used as part of device_id.
There was a problem hiding this comment.
Can you explain what you exactly mean with that?
Currently this driver uses hardware implemented chip select in the OSPI_CONFIG_REG via the PERIPH_CS_LINES_FLD field. There are 4 dedicated pins for that and they are only referenced by the numbers 0..3, which I directly use in the mspi_ti_k3_dev_config function. When I would use ce-gpios with phandle to the GPIO pins I think it would be necassary to do software CS control.
There was a problem hiding this comment.
Can you explain what you exactly mean with that?
Currently this driver uses hardware implemented chip select in the
OSPI_CONFIG_REGvia thePERIPH_CS_LINES_FLDfield. There are 4 dedicated pins for that and they are only referenced by the numbers 0..3, which I directly use in themspi_ti_k3_dev_configfunction. When I would usece-gpioswith phandle to the GPIO pins I think it would be necassary to do software CS control.
ce-gpios can be used to for software CE control, but it is also used as part of the device id, see struct mspi_dev_id which is filled by MSPI_DEVICE_ID_DT. So you would have to have at least a ce-gpio defined in controller dts. The dev_id should be used to validate the peripheral(child) device within the controller, although some choose not to as no plan to support software-multiperipheral function. i.e. switching between child devices by software under the same controller.
If your controller is capable of switching by hardware CE number, then you can pass that 0~3 number in struct mspi_dev_cfg.ce_num .
I do recognize there might be a compatiblity problem if your CEs are not within one of your GPIO alternate function but dedicated pin. But we will fix it when we get there.
There was a problem hiding this comment.
For now I removed the ce-gpios part from the bindings. However it's still ignored in the driver and added the requirement that GPIO has to be selected in the Kconfig
| MSPI_TI_K3_REG_WRITE(0, CONFIG, RESET_PIN, base_addr); | ||
|
|
||
| /* general clock cycle delays */ | ||
| MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_NSS, base_addr); |
There was a problem hiding this comment.
No, not really. struct mspi_ce_control is for software controlled CE. However, I do think that this CE timing maybe peripheral device specific but not transfer specific. NXP have a similar setting as well. We can try add that to struct mspi_dev_cfg
Another option is to slide it in through struct mspi_timing_cfg along with your custom timing parameters.
| uint32_t exec_status = | ||
| MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); | ||
| while (exec_status != 0 && | ||
| k_cyc_to_us_floor32(k_uptime_get() - start_cycles) < req->timeout) { |
I will add that to this PR when the AM2434 SoC and AM2434 Launchpad are officially supported. The AM2434 SoC support is currently being done in #87321. After that is merged I will add the AM243x LaunchPad board and after that I can also add the MSPI flash test to this PR. Before that I will only add it to the https://github.com/siemens/zephyr/commits/mika/ti/ti-am2434-native-boot/ branch |
def3678 to
1602101
Compare
|
@m-braunschweig You should squash the 13 commits into 2, one for the controller driver, one for the flash driver. That is zephyr PR policy. |
1602101 to
3b9d09f
Compare
|
@swift-tk done. |
|
Also I have some more questions to the MSPI driver API:
For the devicetree things I was unsure about I currently check during build time that they are unset. However I don't really like that solution and would be happy to hear about ideas to improve it |
The The settings given to
The device tree properties represent the target configuration that the device will run on most of the time. In the case of flash memory, it represents settings when conducting memory write and read. The default settings for device initialization should be stored as const and possibly used for all register access to maintain maximum compatibility as they should typically be low speed.
If your target operating mode is single mode, then swap the cmds in device tree with cmds used in single mode and the same way with quad mode. Mode switching should be done by
You have to check it each time when a config is passed from device driver. To reduce unnecessary config from repeated |
|
Hello, excellent work on the drivers. However, the MSPI controller would be redundant with the If preferred I can move the old cadence driver to the MSPI subsystem and rewrite the flash driver for |
| #define INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT 30 | ||
|
|
||
| /* opcodes 1-1-1 mode */ | ||
| #define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 |
There was a problem hiding this comment.
can reuse opcodes from the generic spi_nor.h definition
There was a problem hiding this comment.
ignore this, current approach is better
There was a problem hiding this comment.
We should reuse code from spi_nor.h when possible and leave only the special ones in this file.
| } | ||
|
|
||
| data->mspi_dev_cfg.addr_length = 4; | ||
|
|
There was a problem hiding this comment.
did you mean to do a ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); here?
There was a problem hiding this comment.
Yes. Good catch
Ok I sadly didn't know that TI used a Cadence IP core as octal SPI peripheral. The existing flash driver seems a bit odd with the N25Q support since I searched with zephyr/dts/arm64/intel/intel_socfpga_agilex.dtsi Lines 83 to 95 in 1207880 The N25Q option in the driver is basically always enabled since it's enabled by default and there is also no occurence where it gets disabled (confirmed via For the code itself I would also prefer no redundant drivers but it's probably necessary until we can confirm we have a driver that works with the already existing Agilex SoC FPGA (especially the micron part is interesting here; however if it doesn't have any odd features it might be enough to just use the generic MSPI flash driver with the right devicetree options) so we don't break anything. Going further I think the benefits of continuing this driver (I already test it locally with the AM2434 and it's a separate MSPI and flash driver) outweights the disadvantages (no XIP and timing configuration support) so my plan would be to rename the names so it reflects that it's for a cadence IP core and also incorporate the things from #88487 (comment). Maybe XIP and timing configuration can be taken from the existing driver later. I will probably continue with this PR once #87321 is merged. |
|
I also tested your MSPI driver with a draft S28H driver and it works perfectly, so I would also prefer to keep that around. In the process I have changed the S25H driver into a generic SEMPER driver that also supports octal configuration (for s28h). This is done by reading the SFDP. Do you mind if I open a PR in your fork to allow more discussion on this? |
|
It would probably be enough for me, if you push it somewhere and send me a link so I can I will probably also push new changes to my branch soon when I have my |
3b9d09f to
0db5b46
Compare
|
Owner for the controller is @m-braunschweig but we have decided that I will cherry-pick their changes onto my other PR, since it is a dependency. Maybe we should draft this one in the meantime. |
|
@natto1784 I updated the PR to address most change requests related to the MSPI driver. The old version is now on the branch mika/ti/ti-am2434-native-boot-pre-refactor. Due to the definition changes requested that I should have addressed way sooner it will sadly require some work in case you want to use it as base. My flash driver wasn't changed since your S28 one should be merged first. I tested the changes on the AM243x Launchpad by putting it into UART boot, sending a firmware that uses the flash driver by flashing received UART data to the flash and then flashing a blinky sample. The changes I made include:
Changes I didn't address:
Please tell me, if I should also look into converting your changes to the |
a2778f0 to
7a87fc7
Compare
|
Hi Mika, thank you for your work, it is well appreciated.
That is quite alright, no problem.
Okay that is good to know
Good addition, thanks.
We have TISCI now that most of the K3 devices use for clock and power management. However, we do not have any driver using it explicitly for the purpose. I will look into adding some conditional macro to get the clock rate but that is something that can be done after the drivers are merged.
That is alright, I will cherry-pick the new patch and drop the old one |
|
Can you add static keyword in front of these functions |
Ok. I also had a quick look and the main problems were the missing clock devicetree nodes and that we can't get the clock frequency in the init function due to the driver using a semaphore and the driver initialization happening before the kernel. But it seems these things are already fixed in your draft PR #101280 |
7a87fc7 to
e0583a4
Compare
Done |
|
|
||
| compatible: "infineon,s25h-flash" | ||
|
|
||
| on-bus: mspi |
There was a problem hiding this comment.
hi can you also get rid of this line as suggested here: #102513 (comment)
There was a problem hiding this comment.
Done. However you don't need to do another rebasing on my changes since you added your version for the generic MSPI flash driver in 767dbb2
There was a problem hiding this comment.
oh right my bad, i forgot that it's a different driver
e0583a4 to
95b90e5
Compare
| LOG_ERR("Device configuration includes ignored / not implemented " | ||
| "parameters. Check mspi_cadence.h to figure out what isn't " | ||
| "supported"); | ||
| return -ENOSYS; |
There was a problem hiding this comment.
im not sure if returning -ENOSYS here is a good choice since it causes problems with flash drivers (such as flash_mspi_nor to fail prematurely. Just an error/warning should suffice to inform that there are parameters in the request which we are going to ignore.
There was a problem hiding this comment.
I think returning no error value would be not acceptable since it would mean potentially silent failures (especially if no logging is available/enabled). Since the MSPI NOR driver sets nearly all flags for non-XIP usage (see [1]) it seems like it will be necessary to check more fields for undesired values (mem_boundary and time_to_break).
However the other problem is that it tries to set the frequency. I think the best solution for now would be to provide the reference clock frequency via the devicetree and then set MSTR_BAUD_DIV_FLD in the OSPI_CONFIG_REG register to achieve the frequency (or the highest possible lower than the desired frequency).
Additionally after looking at one of the Ambiq MSPI drivers (see [2]) I will change the "completly ignored parameters" to be based off a negation of what is implemented too (so if a new value is introduced it will fail due to not implementing that one). This will however lead to problems once the MSPI API is expanded but IMO it's favourable over completely silent failures.
I will implement and test these changes in the next few days.
[1] mspi_dev_config mask in MSPI NOR driver
zephyr/drivers/flash/flash_mspi_nor.c
Lines 19 to 26 in b246d3f
[2] bitmask that checks for unknown/unimplemented values in Ambiq driver
zephyr/drivers/mspi/mspi_ambiq_ap3.c
Lines 665 to 675 in b246d3f
There was a problem hiding this comment.
However the other problem is that it tries to set the frequency. I think the best solution for now would be to provide the reference clock frequency via the devicetree and then set
MSTR_BAUD_DIV_FLDin theOSPI_CONFIG_REGregister to achieve the frequency (or the highest possible lower than the desired frequency).
I can do this if you are not already working.
There was a problem hiding this comment.
I implemented the changes already (and noticed that we check for mem_boundary and time_to_break already). Before pushing I wanted to measure the frequency with a logic analyzer to be sure it works properly but I will only be able to do it on Monday (I however already tested the calculation manually and flashing with 50 MHz + 10 MHz). If you want I can already push these changes.
Also according to the AM64x TRM the OSPI clock is configured by the ROM bootloader to be either 200 MHz or 160 MHz. In UART and QSPI bootmode it is configured to be 200 MHz on the AM243x Launchpad (checked via tisci_cmd_clk_get_freq(dmsc, 75, 6, &frequency);). Do you happen to know under which circumstance it can be 160 MHz?
There was a problem hiding this comment.
Yes, OSPI only has two reference clock selections MAIN_PLL0_HSDIV5 (1000MHz / 5 = 200MHz) and PER0_PLL0_HSDIV4 (960MHz / 6 = 160MHz). The clock selection is done via the relevant CLKSEL register in the MMR region - this is done by the DM via TISCI calls. Personally during the testing I have done I manually set the frequency via TISCI calls to 200MHz which selects the former parent.
Now clock controlling is a separate and bigger topic, currently there are some bugfixes [1] pending post which I am going to add a small polling API for secproxy [2]. However I am going to remove the initialization part (power domains and clock frequencies) from the [2] and move it to the individual drivers instead i.e, the drivers will set the frequency (better yet, parent source) during init(). Now the problem with that is that is vendor specific clock configuration for TI - which is solved by a new proposed way of clock management [3]. Hence, it is hard to make decisions on which direction to move in.
P.S. I have personally never seen anyone using the 160MHz source.
There was a problem hiding this comment.
Just pushed it. I will verify that the frequency is actually what it should be on Monday.
The clock mainly concerns me since there might be cases where the ROM bootloader could choose the 160 MHz as reference clock instead of the 200 MHz meaning the calculation will be wrong (though a lower frequency shouldn't be a problem in most cases). Due to the current state of clocks that you mentioned the specification as constant in the devicetree is also mainly a workaround and should ideally be improved later.
There was a problem hiding this comment.
I verified the clock frequencies with the following values + an oscilloscope and they all were the one expected
| Request | Equal or highest possible lower frequency |
|---|---|
| 100 MHz | 100 MHz |
| 50.1 MHz | 50 MHz |
| 50.0 MHz | 50 MHz |
| 49.9 MHz | 33.3333 MHz |
| 7 MHz | 6.6667 MHz |
| 6.25 MHz | 6.25 MHz |
| 6 MHz | not possible |
There was a problem hiding this comment.
I see, that is great, thanks a lot for the effort.
d2868d0 to
016b292
Compare
I will remove the timing API and DT bindings but keep resetting the timing configuration during initialization to a default value |
016b292 to
d160a8a
Compare
e32cf0c to
ea47b80
Compare
ea47b80 to
b74346c
Compare
Add a Cadence MSPI peripheral driver, used in the TI K3 platform. The driver was tested in 1S-1S-1S and 4S-4S-4S mode with the onboard infineon s25h flash of the am243x launchpad and a custom driver for the flash using this interface. The command and dummy cycles are always taken from the xfer request and never from the devicetree since different commands might have different latencies. The driver is somewhat basic for now and lacks e.g. callback implementation. This is something that can be added in the future. If a non-supported / invalid request is detected a error code is returned. Signed-off-by: Mika Braunschweig <mika.braunschweig@siemens.com>
Add a infineon s25h mspi nor flash driver. This driver was tested on the am243x-lp board in 1S-1S-1S and 4S-4S-4S mode. It takes the initial configuration from the devicetree and then sends a reset command. After that it disables the uniform hybrid sector architecture, if activated, and applies the setting by resetting the flash again. After that the 4S-4S-4S mode is entered, if not disabled in the devicetree, and 4 byte adressing gets enabled. During these steps the JEDEC device and manufacturer ids from the devicetree are compared against the ones reported from the flash to ensure a valid connection. If the device isn't switched into 4S-4S-4S mode the driver can also be used in 1S-1S-1S mode with S28H flash. Due to the flash possibily entering continious read mode when undesired some read operations will read the JEDEC id to prevent this. Signed-off-by: Mika Braunschweig <mika.braunschweig@siemens.com>
b74346c to
6283524
Compare
|



This PR adds support for MSPI and the Infineon S25H flash on the TI K3 platform. It is tested with the onboard flash of the AM2434 launchpad.
(PR for the driver flash driver: #88446).It's now part of this PR.For running the code on the AM243x Launchpad this branch is used. Until the AM243x Launchpad is generally supported this shouldn't be merged. However I would still like some early review to speed up merging later. Especially on how to potentially handle the timeout parameter better and whether I interpreted the unit being microseconds right.
The driver itself is pretty basic (e.g. no async and XIP support) but enough for running MCUboot on the board (by loading the image into SRAM).
Edit: Mention that this PR also includes the S25H flash driver now