-
Notifications
You must be signed in to change notification settings - Fork 7.7k
LPSPI optimizations 5/19/25 #90182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LPSPI optimizations 5/19/25 #90182
Changes from 4 commits
50000e1
bc34d1c
abd21b9
0197baf
1677ec1
4a207d2
ddced0a
7fb9c6f
081cdf7
ccd7222
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,13 @@ | |
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/* | ||
* This is a collection of functions that would be useful for any driver for LPSPI. | ||
* This function/file has no knowledge of lpspi usage model by the driver | ||
* beyond basic configuration and should avoid making any assumptions about how | ||
* the driver is going to achieve the zephyr API. | ||
*/ | ||
|
||
#include <zephyr/logging/log.h> | ||
LOG_MODULE_REGISTER(spi_lpspi, CONFIG_SPI_LOG_LEVEL); | ||
|
||
|
@@ -53,12 +60,24 @@ static inline clock_ip_name_t lpspi_get_clock(LPSPI_Type *const base) | |
} | ||
#endif | ||
|
||
void lpspi_wait_tx_fifo_empty(const struct device *dev) | ||
int lpspi_wait_tx_fifo_empty(const struct device *dev) | ||
{ | ||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); | ||
int arbitrary_cycle_limit = CONFIG_SPI_NXP_LPSPI_TXFIFO_WAIT_CYCLES; | ||
bool limit_wait = arbitrary_cycle_limit > 0; | ||
|
||
while (FIELD_GET(LPSPI_FSR_TXCOUNT_MASK, base->FSR) != 0) { | ||
if (!limit_wait) { | ||
continue; | ||
} | ||
|
||
while (LPSPI_GetTxFifoCount(base) != 0) { | ||
if (arbitrary_cycle_limit-- < 0) { | ||
LOG_WRN("Failed waiting for TX fifo empty"); | ||
return -EIO; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's supposed to vary by processor speed. It's just a number of attempts to try before quitting. It's simply a basic safety mechanism, which is just about being more safe than sorry, not a unique feature. It shouldn't even be needed. Most likely this consumption by the fifo happens immediately, and this loop isn't necessary. But people wanted to expand the scope of this PR, so here it is. I'm not overcomplicating it any more by making it time -based based on CPU frequency calculations. Also the specific suggestion to use k_busy_wait is not a good idea. That function is not isr safe. This function is called in isr context. k_busy_wait is implemented by polling kernel time, which can't increment due to this function would be blocking in isr context, causing a likely infinite loop in the kernel. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is polling a register waiting for some truth expression with a timeout, WAIT_FOR is the appropriate tool. It uses cycles not ticks while accepting us timeouts. If you see any bugs in this do send fixes. https://docs.zephyrproject.org/apidoc/latest/group__sys-util.html#ga68eb35df6b4715714312df90209accee |
||
} | ||
|
||
return 0; | ||
} | ||
|
||
int spi_lpspi_release(const struct device *dev, const struct spi_config *spi_cfg) | ||
|
@@ -131,23 +150,20 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf | |
return ret; | ||
} | ||
|
||
if (already_configured) { | ||
/* Setting the baud rate in LPSPI_MasterInit requires module to be disabled. Only | ||
* disable if already configured, otherwise the clock is not enabled and the | ||
* CR register cannot be written. | ||
*/ | ||
LPSPI_Enable(base, false); | ||
while ((base->CR & LPSPI_CR_MEN_MASK) != 0U) { | ||
/* Wait until LPSPI is disabled. Datasheet: | ||
* After writing 0, MEN (Module Enable) remains set until the LPSPI has | ||
* completed the current transfer and is idle. | ||
*/ | ||
} | ||
/* specific driver implementation should set up watermarks and interrupts. | ||
* we reset them here to avoid any unexpected events during configuring. | ||
*/ | ||
base->FCR = 0; | ||
base->IER = 0; | ||
|
||
/* this is workaround for ERR050456 */ | ||
base->CR |= LPSPI_CR_RST_MASK; | ||
base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK; | ||
|
||
/* this is workaround for ERR050456 */ | ||
base->CR |= LPSPI_CR_RST_MASK; | ||
base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK; | ||
base->CR = 0x00U; | ||
/* Setting the baud rate requires module to be disabled. */ | ||
base->CR = 0; | ||
while ((base->CR & LPSPI_CR_MEN_MASK) != 0) { | ||
/* According to datasheet, should wait for this MEN bit to clear once idle */ | ||
} | ||
|
||
data->ctx.config = spi_cfg; | ||
|
@@ -181,7 +197,7 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf | |
base->CR |= LPSPI_CR_DBGEN_MASK; | ||
} | ||
|
||
return 0; | ||
return lpspi_wait_tx_fifo_empty(dev); | ||
} | ||
|
||
static void lpspi_module_system_init(LPSPI_Type *base) | ||
|
@@ -204,15 +220,15 @@ int spi_nxp_init_common(const struct device *dev) | |
|
||
DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); | ||
|
||
data->dev = dev; | ||
|
||
if (!device_is_ready(config->clock_dev)) { | ||
LOG_ERR("clock control device not ready"); | ||
return -ENODEV; | ||
} | ||
|
||
lpspi_module_system_init(base); | ||
|
||
data->major_version = (base->VERID & LPSPI_VERID_MAJOR_MASK) >> LPSPI_VERID_MAJOR_SHIFT; | ||
|
||
err = spi_context_cs_configure_all(&data->ctx); | ||
if (err < 0) { | ||
return err; | ||
|
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@decsny now zephyr project enables copilot review, but copilot is not good at Kconfig staff.