/* * Copyright 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nxp_s32_qspi #include LOG_MODULE_REGISTER(nxp_s32_qspi_memc, CONFIG_MEMC_LOG_LEVEL); #include #include #include #include #include "memc_nxp_s32_qspi.h" /* Mapping between QSPI chip select signals and devicetree chip select identifiers */ #define QSPI_PCSFA1 0 #define QSPI_PCSFA2 1 #define QSPI_PCSFB1 2 #define QSPI_PCSFB2 3 struct memc_nxp_s32_qspi_data { uint8_t instance; }; struct memc_nxp_s32_qspi_config { QuadSPI_Type *base; const struct pinctrl_dev_config *pincfg; const Qspi_Ip_ControllerConfigType *controller_cfg; }; static inline uint8_t get_instance(QuadSPI_Type *base) { QuadSPI_Type *const base_ptrs[QuadSPI_INSTANCE_COUNT] = IP_QuadSPI_BASE_PTRS; uint8_t i; for (i = 0; i < QuadSPI_INSTANCE_COUNT; i++) { if (base_ptrs[i] == base) { break; } } __ASSERT_NO_MSG(i < QuadSPI_INSTANCE_COUNT); return i; } static int memc_nxp_s32_qspi_init(const struct device *dev) { const struct memc_nxp_s32_qspi_config *config = dev->config; struct memc_nxp_s32_qspi_data *data = dev->data; Qspi_Ip_StatusType status; data->instance = get_instance(config->base); if (pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT)) { return -EIO; } status = Qspi_Ip_ControllerInit(data->instance, config->controller_cfg); if (status != STATUS_QSPI_IP_SUCCESS) { LOG_ERR("Fail to initialize QSPI controller %d (%d)", data->instance, status); return -EIO; } return 0; } uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) { struct memc_nxp_s32_qspi_data *data = dev->data; return data->instance; } #define QSPI_DATA_CFG(n) \ IF_ENABLED(FEATURE_QSPI_DDR, ( \ .dataRate = _CONCAT(QSPI_IP_DATA_RATE_, \ DT_INST_STRING_UPPER_TOKEN(n, data_rate)), \ .dataAlign = COND_CODE_1(DT_INST_PROP(n, hold_time_2x), \ (QSPI_IP_FLASH_DATA_ALIGN_2X_REFCLK), \ (QSPI_IP_FLASH_DATA_ALIGN_REFCLK)), \ )) #define QSPI_ADDR_CFG(n) \ IF_ENABLED(FEATURE_QSPI_ADDR_CFG, ( \ .columnAddr = DT_INST_PROP_OR(n, column_space, 0), \ .wordAddresable = DT_INST_PROP(n, word_addressable), \ )) #define QSPI_BYTES_SWAP_ADDR(n) \ IF_ENABLED(FEATURE_QSPI_BYTES_SWAP_ADDR, \ (.byteSwap = DT_INST_PROP(n, byte_swapping),)) #define QSPI_SAMPLE_DELAY(n) \ COND_CODE_1(DT_INST_PROP(n, sample_delay_half_cycle), \ (QSPI_IP_SAMPLE_DELAY_HALFCYCLE_EARLY_DQS), \ (QSPI_IP_SAMPLE_DELAY_SAME_DQS)) #define QSPI_SAMPLE_PHASE(n) \ COND_CODE_1(DT_INST_PROP(n, sample_phase_inverted), \ (QSPI_IP_SAMPLE_PHASE_INVERTED), \ (QSPI_IP_SAMPLE_PHASE_NON_INVERTED)) #define QSPI_AHB_BUFFERS(n) \ { \ .masters = DT_INST_PROP(n, ahb_buffers_masters), \ .sizes = DT_INST_PROP(n, ahb_buffers_sizes), \ .allMasters = (bool)DT_INST_PROP(n, ahb_buffers_all_masters), \ } #define QSPI_DLL_CFG(n, side, side_upper) \ IF_ENABLED(FEATURE_QSPI_HAS_DLL, ( \ .dllSettings##side_upper = { \ .dllMode = _CONCAT(QSPI_IP_DLL_, \ DT_INST_STRING_UPPER_TOKEN(n, side##_dll_mode)), \ .freqEnable = DT_INST_PROP(n, side##_dll_freq_enable), \ .coarseDelay = DT_INST_PROP(n, side##_dll_coarse_delay), \ .fineDelay = DT_INST_PROP(n, side##_dll_fine_delay), \ .tapSelect = DT_INST_PROP(n, side##_dll_tap_select), \ IF_ENABLED(FEATURE_QSPI_DLL_LOOPCONTROL, ( \ .referenceCounter = DT_INST_PROP(n, side##_dll_ref_counter), \ .resolution = DT_INST_PROP(n, side##_dll_resolution), \ )) \ }, \ )) #define QSPI_READ_MODE(n, side, side_upper) \ _CONCAT(QSPI_IP_READ_MODE_, DT_INST_STRING_UPPER_TOKEN(n, side##_rx_clock_source)) #define QSPI_IDLE_SIGNAL_DRIVE(n, side, side_upper) \ IF_ENABLED(FEATURE_QSPI_CONFIGURABLE_ISD, ( \ .io2IdleValue##side_upper = (uint8_t)DT_INST_PROP(n, side##_io2_idle_high),\ .io3IdleValue##side_upper = (uint8_t)DT_INST_PROP(n, side##_io3_idle_high),\ )) #define QSPI_PORT_SIZE_FN(node_id, side_upper, port) \ COND_CODE_1(IS_EQ(DT_REG_ADDR_RAW(node_id), QSPI_PCSF##side_upper##port), \ (COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(node_id), \ (.memSize##side_upper##port = DT_PROP(node_id, size) / 8,), \ (.memSize##side_upper##port = 0,))), \ (EMPTY)) #define QSPI_PORT_SIZE(n, side_upper) \ DT_INST_FOREACH_CHILD_VARGS(n, QSPI_PORT_SIZE_FN, side_upper, 1) \ DT_INST_FOREACH_CHILD_VARGS(n, QSPI_PORT_SIZE_FN, side_upper, 2) #define QSPI_SIDE_CFG(n, side, side_upper) \ QSPI_IDLE_SIGNAL_DRIVE(n, side, side_upper) \ QSPI_DLL_CFG(n, side, side_upper) \ QSPI_PORT_SIZE(n, side_upper) \ .readMode##side_upper = QSPI_READ_MODE(n, side, side_upper), #if FEATURE_QSPI_HAS_SFP #if QSPI_IP_SFP_ENABLE_MDAD #define SFP_MDAD_NODE(n) DT_INST_CHILD(n, sfp_mdad) #define QSPI_SECURE_ATTRIBUTE(node_id) \ (DT_PROP(node_id, secure_attribute) == NXP_S32_QSPI_NON_SECURE ? QSPI_IP_SFP_UNSECURE : \ (DT_PROP(node_id, secure_attribute) == NXP_S32_QSPI_SECURE ? QSPI_IP_SFP_SECURE : \ (DT_PROP(node_id, secure_attribute) == (NXP_S32_QSPI_NON_SECURE | NXP_S32_QSPI_SECURE) ?\ QSPI_IP_SFP_BOTH : \ QSPI_IP_SFP_RESERVED))) #define _QSPI_SFP_MDAD_CFG(node_id, n) \ { \ .SecureAttribute = QSPI_SECURE_ATTRIBUTE(node_id), \ .MaskType = DT_ENUM_IDX(node_id, mask_type), \ .Valid = true, \ .Mask = DT_PROP(node_id, mask), \ .DomainId = DT_PROP(node_id, domain_id), \ }, #define QSPI_SFP_MDAD_CFG(n) \ .Tg = { \ DT_FOREACH_CHILD_STATUS_OKAY_VARGS(SFP_MDAD_NODE(n), _QSPI_SFP_MDAD_CFG, n)\ }, #endif /* QSPI_IP_SFP_ENABLE_MDAD */ #if QSPI_IP_SFP_ENABLE_FRAD #define SFP_FRAD_NODE(n) DT_INST_CHILD(n, sfp_frad) #define QSPI_ACP_POLICY(node_id) \ (DT_PROP(node_id, master_domain_acp_policy) == NXP_S32_QSPI_SECURE ? \ QSPI_IP_SFP_ACP_SECURE :\ (DT_PROP(node_id, master_domain_acp_policy) == (NXP_S32_QSPI_NON_SECURE | \ NXP_S32_QSPI_PRIVILEGE) ? QSPI_IP_SFP_ACP_PRIVILEGED : \ (DT_PROP(node_id, master_domain_acp_policy) == (NXP_S32_QSPI_SECURE | \ NXP_S32_QSPI_PRIVILEGE) ? QSPI_IP_SFP_ACP_SECURE_PRIVILEGED :\ (DT_PROP(node_id, master_domain_acp_policy) == (NXP_S32_QSPI_NON_SECURE | \ NXP_S32_QSPI_SECURE | NXP_S32_QSPI_PRIVILEGE) ? QSPI_IP_SFP_ACP_ALL : \ QSPI_IP_SFP_ACP_NONE)))) #define QSPI_EXCLUSIVE_ACCESS_LOCK(node_id) \ (DT_ENUM_IDX(node_id, exclusive_access_lock) == 0 ? QSPI_IP_SFP_EAL_DISABLED : \ (DT_ENUM_IDX(node_id, exclusive_access_lock) == 1 ? QSPI_IP_SFP_EAL_OWNER : \ QSPI_IP_SFP_EAL_NONE)) #define _QSPI_SFP_FRAD_CFG(node_id, n) \ { \ .StartAddress = DT_REG_ADDR(node_id), \ .EndAddress = DT_REG_ADDR(node_id) + DT_REG_SIZE(node_id) - 1, \ .Valid = true, \ .Md0Acp = QSPI_ACP_POLICY(node_id), \ .Md1Acp = QSPI_ACP_POLICY(node_id), \ .ExclusiveAccessLock = QSPI_EXCLUSIVE_ACCESS_LOCK(node_id), \ .ExclusiveAccessOwner = DT_PROP(node_id, exclusive_access_owner), \ }, #define QSPI_SFP_FRAD_CFG(n) \ .Frad = { \ DT_FOREACH_CHILD_STATUS_OKAY_VARGS(SFP_FRAD_NODE(n), _QSPI_SFP_FRAD_CFG, n)\ }, #endif /* QSPI_IP_SFP_ENABLE_FRAD */ #define QSPI_SFP_MASTER_TIMEOUT_CYCLES 0xffff #define QSPI_SFP_CFG(n) \ IF_ENABLED(QSPI_IP_SFP_ENABLE_GLOBAL, \ (.SfpCfg = { \ .MasterTimeout = QSPI_SFP_MASTER_TIMEOUT_CYCLES, \ IF_ENABLED(QSPI_IP_SFP_ENABLE_MDAD, (QSPI_SFP_MDAD_CFG(n))) \ IF_ENABLED(QSPI_IP_SFP_ENABLE_FRAD, (QSPI_SFP_FRAD_CFG(n))) \ },)) #endif /* FEATURE_QSPI_HAS_SFP */ #define MEMC_NXP_S32_QSPI_CONTROLLER_CONFIG(n) \ BUILD_ASSERT(DT_INST_PROP_LEN(n, ahb_buffers_masters) == QSPI_IP_AHB_BUFFERS, \ "ahb-buffers-masters must be of size QSPI_IP_AHB_BUFFERS"); \ BUILD_ASSERT(DT_INST_PROP_LEN(n, ahb_buffers_sizes) == QSPI_IP_AHB_BUFFERS, \ "ahb-buffers-sizes must be of size QSPI_IP_AHB_BUFFERS"); \ BUILD_ASSERT( \ _CONCAT(FEATURE_QSPI_, DT_INST_STRING_UPPER_TOKEN(n, a_rx_clock_source)) == 1,\ "a-rx-clock-source source mode selected is not supported"); \ \ static const Qspi_Ip_ControllerConfigType \ memc_nxp_s32_qspi_controller_cfg_##n = { \ .csHoldTime = DT_INST_PROP(n, cs_hold_time), \ .csSetupTime = DT_INST_PROP(n, cs_setup_time), \ .sampleDelay = QSPI_SAMPLE_DELAY(n), \ .samplePhase = QSPI_SAMPLE_PHASE(n), \ .ahbConfig = QSPI_AHB_BUFFERS(n), \ QSPI_SIDE_CFG(n, a, A) \ QSPI_DATA_CFG(n) \ QSPI_ADDR_CFG(n) \ QSPI_BYTES_SWAP_ADDR(n) \ IF_ENABLED(FEATURE_QSPI_HAS_SFP, (QSPI_SFP_CFG(n))) \ } #define MEMC_NXP_S32_QSPI_INIT_DEVICE(n) \ PINCTRL_DT_INST_DEFINE(n); \ MEMC_NXP_S32_QSPI_CONTROLLER_CONFIG(n); \ static struct memc_nxp_s32_qspi_data memc_nxp_s32_qspi_data_##n; \ static const struct memc_nxp_s32_qspi_config memc_nxp_s32_qspi_config_##n = { \ .base = (QuadSPI_Type *)DT_INST_REG_ADDR(n), \ .controller_cfg = &memc_nxp_s32_qspi_controller_cfg_##n, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ }; \ DEVICE_DT_INST_DEFINE(n, \ memc_nxp_s32_qspi_init, \ NULL, \ &memc_nxp_s32_qspi_data_##n, \ &memc_nxp_s32_qspi_config_##n, \ POST_KERNEL, \ CONFIG_MEMC_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(MEMC_NXP_S32_QSPI_INIT_DEVICE)