- 
                Notifications
    You must be signed in to change notification settings 
- Fork 8.2k
drivers: flash: Introduce i.MX RT FlexSPI driver #31034
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
Changes from all commits
e38d451
              0be7b68
              2fb2fe9
              3b6d0c8
              3977410
              b43810d
              0ba6e3d
              5ac0286
              ee96a9a
              fce215f
              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 | 
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| /* | ||
| * Copyright 2020 NXP | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|  | ||
| #define DT_DRV_COMPAT nxp_imx_flexspi | ||
|  | ||
| #include <drivers/flash.h> | ||
| #include <logging/log.h> | ||
| #include <sys/util.h> | ||
| #include "flash_mcux_flexspi.h" | ||
|  | ||
| LOG_MODULE_REGISTER(flash_flexspi, CONFIG_FLASH_LOG_LEVEL); | ||
|  | ||
| struct flash_flexspi_config { | ||
| FLEXSPI_Type *base; | ||
| uint8_t *ahb_base; | ||
| bool ahb_bufferable; | ||
| bool ahb_cacheable; | ||
| bool ahb_prefetch; | ||
| bool ahb_read_addr_opt; | ||
| bool combination_mode; | ||
| flexspi_read_sample_clock_t rx_sample_clock; | ||
|          | ||
| }; | ||
|  | ||
| struct flash_flexspi_data { | ||
| size_t size[kFLEXSPI_PortCount]; | ||
| }; | ||
|  | ||
| int flash_flexspi_update_lut(const struct device *dev, uint32_t index, | ||
| const uint32_t *cmd, uint32_t count) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
|  | ||
| FLEXSPI_UpdateLUT(config->base, index, cmd, count); | ||
|  | ||
| return 0; | ||
| } | ||
|  | ||
| int flash_flexspi_set_flash_config(const struct device *dev, | ||
| const flexspi_device_config_t *device_config, | ||
| flexspi_port_t port) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
| struct flash_flexspi_data *data = dev->data; | ||
|  | ||
| if (port >= kFLEXSPI_PortCount) { | ||
| LOG_ERR("Invalid port number"); | ||
| return -EINVAL; | ||
| } | ||
|  | ||
| data->size[port] = device_config->flashSize * KB(1); | ||
|  | ||
| FLEXSPI_SetFlashConfig(config->base, | ||
| (flexspi_device_config_t *) device_config, | ||
| port); | ||
|  | ||
| return 0; | ||
| } | ||
|  | ||
| int flash_flexspi_reset(const struct device *dev) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
|  | ||
| FLEXSPI_SoftwareReset(config->base); | ||
|  | ||
| return 0; | ||
| } | ||
|  | ||
| int flash_flexspi_transfer(const struct device *dev, | ||
| flexspi_transfer_t *transfer) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
| status_t status = FLEXSPI_TransferBlocking(config->base, transfer); | ||
|  | ||
| if (status != kStatus_Success) { | ||
| LOG_ERR("Transfer error: %d", status); | ||
| return -EIO; | ||
| } | ||
|  | ||
| return 0; | ||
| } | ||
|  | ||
| void *flash_flexspi_get_ahb_address(const struct device *dev, | ||
| flexspi_port_t port, off_t offset) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
| struct flash_flexspi_data *data = dev->data; | ||
| int i; | ||
|  | ||
| if (port >= kFLEXSPI_PortCount) { | ||
| LOG_ERR("Invalid port number"); | ||
| return NULL; | ||
| } | ||
|  | ||
| for (i = 0; i < port; i++) { | ||
| offset += data->size[port]; | ||
| } | ||
|  | ||
| return config->ahb_base + offset; | ||
| } | ||
|  | ||
| static int flash_flexspi_init(const struct device *dev) | ||
| { | ||
| const struct flash_flexspi_config *config = dev->config; | ||
| flexspi_config_t flexspi_config; | ||
|  | ||
| FLEXSPI_GetDefaultConfig(&flexspi_config); | ||
|  | ||
| flexspi_config.ahbConfig.enableAHBBufferable = config->ahb_bufferable; | ||
|          | ||
| flexspi_config.ahbConfig.enableAHBCachable = config->ahb_cacheable; | ||
| flexspi_config.ahbConfig.enableAHBPrefetch = config->ahb_prefetch; | ||
| flexspi_config.ahbConfig.enableReadAddressOpt = config->ahb_read_addr_opt; | ||
| flexspi_config.enableCombination = config->combination_mode; | ||
| flexspi_config.rxSampleClock = config->rx_sample_clock; | ||
|  | ||
| FLEXSPI_Init(config->base, &flexspi_config); | ||
|  | ||
| return 0; | ||
| } | ||
|  | ||
| #define FLASH_FLEXSPI(n) \ | ||
| static const struct flash_flexspi_config \ | ||
| flash_flexspi_config_##n = { \ | ||
| .base = (FLEXSPI_Type *) DT_INST_REG_ADDR(n), \ | ||
| .ahb_base = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(n, 1), \ | ||
| .ahb_bufferable = DT_INST_PROP(n, ahb_bufferable), \ | ||
| .ahb_cacheable = DT_INST_PROP(n, ahb_cacheable), \ | ||
| .ahb_prefetch = DT_INST_PROP(n, ahb_prefetch), \ | ||
| .ahb_read_addr_opt = DT_INST_PROP(n, ahb_read_addr_opt),\ | ||
| .combination_mode = DT_INST_PROP(n, combination_mode), \ | ||
| .rx_sample_clock = DT_INST_PROP(n, rx_clock_source), \ | ||
| }; \ | ||
| \ | ||
| static struct flash_flexspi_data flash_flexspi_data_##n; \ | ||
| \ | ||
| DEVICE_DT_INST_DEFINE(n, \ | ||
| flash_flexspi_init, \ | ||
| device_pm_control_nop, \ | ||
| &flash_flexspi_data_##n, \ | ||
| &flash_flexspi_config_##n, \ | ||
| POST_KERNEL, \ | ||
| CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ | ||
| NULL); | ||
|  | ||
| DT_INST_FOREACH_STATUS_OKAY(FLASH_FLEXSPI) | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /* | ||
| * Copyright 2020 NXP | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|  | ||
| #include <drivers/flash.h> | ||
| #include <fsl_flexspi.h> | ||
|  | ||
| int flash_flexspi_update_lut(const struct device *dev, uint32_t index, | ||
| const uint32_t *cmd, uint32_t count); | ||
|  | ||
| int flash_flexspi_set_flash_config(const struct device *dev, | ||
| const flexspi_device_config_t *device_config, | ||
| flexspi_port_t port); | ||
|  | ||
| int flash_flexspi_reset(const struct device *dev); | ||
|  | ||
| int flash_flexspi_transfer(const struct device *dev, | ||
| flexspi_transfer_t *transfer); | ||
|  | ||
| void *flash_flexspi_get_ahb_address(const struct device *dev, | ||
| flexspi_port_t port, off_t offset); | 
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.
It'd be fine to have this be:
Then if somebody has an Adesto-specific driver it'd be picked up. It also makes more clear exactly what the flash chip is. Not required, but suggested.
The same applies to all the other flash device nodes.
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.
I like how this makes the flash chip more clear, but for it to work I think we'd need a compatible something like
nxp,imx-flexspi-nor-at25sf128a. Because an Adesto-specific driver would be different for each of the various SoC QSPI peripherals.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.
I'm not sure that's necessarily true. I'm thinking this would be useful in somebody's out-of-tree application where they didn't care that the underlying peripheral isn't represented in the compatible name, but their needs are such that their dedicated custom driver is preferred over the stock Zephyr one.
The primary purpose of the compatible is to accurately describe the device that's present in hardware, not the driver implementation to talk to that device. Kconfig figures out the best device. QSPI bus devices are perhaps an extreme case of this, but could be supported if we used
jedec,qspi-norand have the vendor-specific drivers all support that compatible, if it weren't for the fact the vendor drivers tend to need vendor-specific devicetree properties.