bef0010e69
This commit fixes an issue introduced in 5ee9392
where FlexSPI
pinctrl states where applied based on the SoC type.
However multiple FlexSPI instances can be active, some of which
are not pre-configured from ROM.
Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
222 lines
5.9 KiB
C
222 lines
5.9 KiB
C
/*
|
|
* Copyright 2020 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT nxp_imx_flexspi
|
|
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/sys/util.h>
|
|
#ifdef CONFIG_PINCTRL
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#endif
|
|
|
|
#include "memc_mcux_flexspi.h"
|
|
|
|
|
|
/*
|
|
* NOTE: If CONFIG_FLASH_MCUX_FLEXSPI_XIP is selected, Any external functions
|
|
* called while interacting with the flexspi MUST be relocated to SRAM or ITCM
|
|
* at runtime, so that the chip does not access the flexspi to read program
|
|
* instructions while it is being written to
|
|
*/
|
|
#if defined(CONFIG_FLASH_MCUX_FLEXSPI_XIP) && (CONFIG_MEMC_LOG_LEVEL > 0)
|
|
#warning "Enabling memc driver logging and XIP mode simultaneously can cause \
|
|
read-while-write hazards. This configuration is not recommended."
|
|
#endif
|
|
|
|
LOG_MODULE_REGISTER(memc_flexspi, CONFIG_MEMC_LOG_LEVEL);
|
|
|
|
/* flexspi device data should be stored in RAM to avoid read-while-write hazards */
|
|
struct memc_flexspi_data {
|
|
FLEXSPI_Type *base;
|
|
uint8_t *ahb_base;
|
|
bool xip;
|
|
bool ahb_bufferable;
|
|
bool ahb_cacheable;
|
|
bool ahb_prefetch;
|
|
bool ahb_read_addr_opt;
|
|
bool combination_mode;
|
|
bool sck_differential_clock;
|
|
flexspi_read_sample_clock_t rx_sample_clock;
|
|
#ifdef CONFIG_PINCTRL
|
|
const struct pinctrl_dev_config *pincfg;
|
|
#endif
|
|
size_t size[kFLEXSPI_PortCount];
|
|
};
|
|
|
|
void memc_flexspi_wait_bus_idle(const struct device *dev)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
|
|
while (false == FLEXSPI_GetBusIdleStatus(data->base)) {
|
|
}
|
|
}
|
|
|
|
bool memc_flexspi_is_running_xip(const struct device *dev)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
|
|
return data->xip;
|
|
}
|
|
|
|
int memc_flexspi_update_lut(const struct device *dev, uint32_t index,
|
|
const uint32_t *cmd, uint32_t count)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
|
|
FLEXSPI_UpdateLUT(data->base, index, cmd, count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int memc_flexspi_set_device_config(const struct device *dev,
|
|
const flexspi_device_config_t *device_config,
|
|
flexspi_port_t port)
|
|
{
|
|
struct memc_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(data->base,
|
|
(flexspi_device_config_t *) device_config,
|
|
port);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int memc_flexspi_reset(const struct device *dev)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
|
|
FLEXSPI_SoftwareReset(data->base);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int memc_flexspi_transfer(const struct device *dev,
|
|
flexspi_transfer_t *transfer)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
status_t status = FLEXSPI_TransferBlocking(data->base, transfer);
|
|
|
|
if (status != kStatus_Success) {
|
|
LOG_ERR("Transfer error: %d", status);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *memc_flexspi_get_ahb_address(const struct device *dev,
|
|
flexspi_port_t port, off_t offset)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
int i;
|
|
|
|
if (port >= kFLEXSPI_PortCount) {
|
|
LOG_ERR("Invalid port number: %u", port);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < port; i++) {
|
|
offset += data->size[port];
|
|
}
|
|
|
|
return data->ahb_base + offset;
|
|
}
|
|
|
|
static int memc_flexspi_init(const struct device *dev)
|
|
{
|
|
struct memc_flexspi_data *data = dev->data;
|
|
flexspi_config_t flexspi_config;
|
|
|
|
/* we should not configure the device we are running on */
|
|
if (memc_flexspi_is_running_xip(dev)) {
|
|
LOG_DBG("XIP active on %s, skipping init", dev->name);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* SOCs such as the RT1064 and RT1024 have internal flash, and no pinmux
|
|
* settings, continue if no pinctrl state found.
|
|
*/
|
|
#ifdef CONFIG_PINCTRL
|
|
int ret;
|
|
|
|
ret = pinctrl_apply_state(data->pincfg, PINCTRL_STATE_DEFAULT);
|
|
if (ret < 0 && ret != -ENOENT) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
FLEXSPI_GetDefaultConfig(&flexspi_config);
|
|
|
|
flexspi_config.ahbConfig.enableAHBBufferable = data->ahb_bufferable;
|
|
flexspi_config.ahbConfig.enableAHBCachable = data->ahb_cacheable;
|
|
flexspi_config.ahbConfig.enableAHBPrefetch = data->ahb_prefetch;
|
|
flexspi_config.ahbConfig.enableReadAddressOpt = data->ahb_read_addr_opt;
|
|
#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && \
|
|
FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
|
|
flexspi_config.enableCombination = data->combination_mode;
|
|
#endif
|
|
flexspi_config.enableSckBDiffOpt = data->sck_differential_clock;
|
|
flexspi_config.rxSampleClock = data->rx_sample_clock;
|
|
|
|
FLEXSPI_Init(data->base, &flexspi_config);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI)
|
|
#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi))
|
|
#elif defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI2)
|
|
#define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi2))
|
|
#elif defined(CONFIG_SOC_SERIES_IMX_RT6XX) || defined(CONFIG_SOC_SERIES_IMX_RT5XX)
|
|
#define MEMC_FLEXSPI_CFG_XIP(node_id) IS_ENABLED(CONFIG_XIP)
|
|
#else
|
|
#define MEMC_FLEXSPI_CFG_XIP(node_id) false
|
|
#endif
|
|
|
|
#ifdef CONFIG_PINCTRL
|
|
#define PINCTRL_DEFINE(n) PINCTRL_DT_INST_DEFINE(n);
|
|
#define PINCTRL_INIT(n) .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),
|
|
#else
|
|
#define PINCTRL_DEFINE(n)
|
|
#define PINCTRL_INIT(n)
|
|
#endif
|
|
|
|
#define MEMC_FLEXSPI(n) \
|
|
PINCTRL_DEFINE(n) \
|
|
static struct memc_flexspi_data \
|
|
memc_flexspi_data_##n = { \
|
|
.base = (FLEXSPI_Type *) DT_INST_REG_ADDR(n), \
|
|
.xip = MEMC_FLEXSPI_CFG_XIP(DT_DRV_INST(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), \
|
|
.sck_differential_clock = DT_INST_PROP(n, sck_differential_clock), \
|
|
.rx_sample_clock = DT_INST_PROP(n, rx_clock_source), \
|
|
PINCTRL_INIT(n) \
|
|
}; \
|
|
\
|
|
DEVICE_DT_INST_DEFINE(n, \
|
|
memc_flexspi_init, \
|
|
NULL, \
|
|
&memc_flexspi_data_##n, \
|
|
NULL, \
|
|
POST_KERNEL, \
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
|
NULL);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI)
|