mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Silicon_Labs/TARGET_EFM32/qspi_api.c@189:f392fc9709a3, 2019-02-20 (annotated)
- Committer:
- AnnaBridge
- Date:
- Wed Feb 20 22:31:08 2019 +0000
- Revision:
- 189:f392fc9709a3
- Parent:
- 188:bcfe06ba3d64
mbed library release version 165
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 188:bcfe06ba3d64 | 1 | /***************************************************************************//** |
AnnaBridge | 188:bcfe06ba3d64 | 2 | * @file rtc_rtcc.c |
AnnaBridge | 188:bcfe06ba3d64 | 3 | ******************************************************************************* |
AnnaBridge | 188:bcfe06ba3d64 | 4 | * @section License |
AnnaBridge | 188:bcfe06ba3d64 | 5 | * <b>(C) Copyright 2018 Silicon Labs, http://www.silabs.com</b> |
AnnaBridge | 188:bcfe06ba3d64 | 6 | ******************************************************************************* |
AnnaBridge | 188:bcfe06ba3d64 | 7 | * |
AnnaBridge | 188:bcfe06ba3d64 | 8 | * SPDX-License-Identifier: Apache-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 9 | * |
AnnaBridge | 188:bcfe06ba3d64 | 10 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
AnnaBridge | 188:bcfe06ba3d64 | 11 | * not use this file except in compliance with the License. |
AnnaBridge | 188:bcfe06ba3d64 | 12 | * You may obtain a copy of the License at |
AnnaBridge | 188:bcfe06ba3d64 | 13 | * |
AnnaBridge | 188:bcfe06ba3d64 | 14 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 15 | * |
AnnaBridge | 188:bcfe06ba3d64 | 16 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 188:bcfe06ba3d64 | 17 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
AnnaBridge | 188:bcfe06ba3d64 | 18 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 188:bcfe06ba3d64 | 19 | * See the License for the specific language governing permissions and |
AnnaBridge | 188:bcfe06ba3d64 | 20 | * limitations under the License. |
AnnaBridge | 188:bcfe06ba3d64 | 21 | * |
AnnaBridge | 188:bcfe06ba3d64 | 22 | ******************************************************************************/ |
AnnaBridge | 188:bcfe06ba3d64 | 23 | |
AnnaBridge | 188:bcfe06ba3d64 | 24 | #include "device.h" |
AnnaBridge | 188:bcfe06ba3d64 | 25 | #if DEVICE_QSPI && defined(QSPI_PRESENT) |
AnnaBridge | 188:bcfe06ba3d64 | 26 | |
AnnaBridge | 188:bcfe06ba3d64 | 27 | #include "stddef.h" |
AnnaBridge | 188:bcfe06ba3d64 | 28 | #include "qspi_api.h" |
AnnaBridge | 188:bcfe06ba3d64 | 29 | #include "mbed_error.h" |
AnnaBridge | 188:bcfe06ba3d64 | 30 | #include "em_cmu.h" |
AnnaBridge | 188:bcfe06ba3d64 | 31 | #include "em_qspi.h" |
AnnaBridge | 188:bcfe06ba3d64 | 32 | #include "pinmap.h" |
AnnaBridge | 188:bcfe06ba3d64 | 33 | #include "PeripheralPins.h" |
AnnaBridge | 188:bcfe06ba3d64 | 34 | #include "pinmap_function.h" |
AnnaBridge | 188:bcfe06ba3d64 | 35 | |
AnnaBridge | 188:bcfe06ba3d64 | 36 | qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode) |
AnnaBridge | 188:bcfe06ba3d64 | 37 | { |
AnnaBridge | 188:bcfe06ba3d64 | 38 | |
AnnaBridge | 188:bcfe06ba3d64 | 39 | #if defined(QSPI_FLASH_EN) |
AnnaBridge | 188:bcfe06ba3d64 | 40 | pin_mode(QSPI_FLASH_EN, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 41 | GPIO_PinOutSet((GPIO_Port_TypeDef)(QSPI_FLASH_EN >> 4 & 0xF), QSPI_FLASH_EN & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 42 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 43 | |
AnnaBridge | 188:bcfe06ba3d64 | 44 | // There's only one QSPI per chip for now |
AnnaBridge | 188:bcfe06ba3d64 | 45 | obj->instance = QSPI0; |
AnnaBridge | 188:bcfe06ba3d64 | 46 | obj->io0 = io0; |
AnnaBridge | 188:bcfe06ba3d64 | 47 | obj->io1 = io1; |
AnnaBridge | 188:bcfe06ba3d64 | 48 | obj->io2 = io2; |
AnnaBridge | 188:bcfe06ba3d64 | 49 | obj->io3 = io3; |
AnnaBridge | 188:bcfe06ba3d64 | 50 | obj->ssel = ssel; |
AnnaBridge | 188:bcfe06ba3d64 | 51 | obj->sclk = sclk; |
AnnaBridge | 188:bcfe06ba3d64 | 52 | |
AnnaBridge | 188:bcfe06ba3d64 | 53 | CMU_ClockEnable(cmuClock_GPIO, true); |
AnnaBridge | 188:bcfe06ba3d64 | 54 | |
AnnaBridge | 188:bcfe06ba3d64 | 55 | #if (CORE_CLOCK_SOURCE == HFXO) |
AnnaBridge | 188:bcfe06ba3d64 | 56 | CMU_ClockSelectSet(cmuClock_QSPI0REF, cmuSelect_HFXO); |
AnnaBridge | 188:bcfe06ba3d64 | 57 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 58 | |
AnnaBridge | 188:bcfe06ba3d64 | 59 | CMU_ClockEnable(cmuClock_QSPI0, true); |
AnnaBridge | 188:bcfe06ba3d64 | 60 | CMU_ClockEnable(cmuClock_QSPI0REF, true); |
AnnaBridge | 188:bcfe06ba3d64 | 61 | |
AnnaBridge | 188:bcfe06ba3d64 | 62 | qspi_frequency(obj, hz); |
AnnaBridge | 188:bcfe06ba3d64 | 63 | |
AnnaBridge | 188:bcfe06ba3d64 | 64 | if (mode) { |
AnnaBridge | 188:bcfe06ba3d64 | 65 | obj->instance->CONFIG |= QSPI_CONFIG_SELCLKPOL | QSPI_CONFIG_SELCLKPHASE; |
AnnaBridge | 188:bcfe06ba3d64 | 66 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 67 | obj->instance->CONFIG &= ~(QSPI_CONFIG_SELCLKPOL | QSPI_CONFIG_SELCLKPHASE); |
AnnaBridge | 188:bcfe06ba3d64 | 68 | } |
AnnaBridge | 188:bcfe06ba3d64 | 69 | |
AnnaBridge | 188:bcfe06ba3d64 | 70 | uint32_t loc = pin_location(io0, PinMap_QSPI_DQ0); |
AnnaBridge | 188:bcfe06ba3d64 | 71 | if (loc != pin_location(io1, PinMap_QSPI_DQ1) || |
AnnaBridge | 188:bcfe06ba3d64 | 72 | loc != pin_location(io2, PinMap_QSPI_DQ2) || |
AnnaBridge | 188:bcfe06ba3d64 | 73 | loc != pin_location(io3, PinMap_QSPI_DQ3) || |
AnnaBridge | 188:bcfe06ba3d64 | 74 | loc != pin_location(sclk, PinMap_QSPI_SCLK) || |
AnnaBridge | 188:bcfe06ba3d64 | 75 | loc != pin_location(ssel, PinMap_QSPI_CS0)) { |
AnnaBridge | 188:bcfe06ba3d64 | 76 | // All pins need to be on the same location number |
AnnaBridge | 188:bcfe06ba3d64 | 77 | qspi_free(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 78 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 79 | } |
AnnaBridge | 188:bcfe06ba3d64 | 80 | |
AnnaBridge | 188:bcfe06ba3d64 | 81 | // Configure QSPI pins |
AnnaBridge | 188:bcfe06ba3d64 | 82 | GPIO_PinOutClear((GPIO_Port_TypeDef)(io0 >> 4 & 0xF), io0 & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 83 | pin_mode(io0, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 84 | |
AnnaBridge | 188:bcfe06ba3d64 | 85 | GPIO_PinOutClear((GPIO_Port_TypeDef)(io1 >> 4 & 0xF), io1 & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 86 | pin_mode(io1, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 87 | |
AnnaBridge | 188:bcfe06ba3d64 | 88 | GPIO_PinOutClear((GPIO_Port_TypeDef)(io2 >> 4 & 0xF), io2 & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 89 | pin_mode(io2, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 90 | |
AnnaBridge | 188:bcfe06ba3d64 | 91 | GPIO_PinOutClear((GPIO_Port_TypeDef)(io3 >> 4 & 0xF), io3 & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 92 | pin_mode(io3, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 93 | |
AnnaBridge | 188:bcfe06ba3d64 | 94 | GPIO_PinOutClear((GPIO_Port_TypeDef)(sclk >> 4 & 0xF), sclk & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 95 | pin_mode(sclk, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 96 | |
AnnaBridge | 188:bcfe06ba3d64 | 97 | GPIO_PinOutSet((GPIO_Port_TypeDef)(ssel >> 4 & 0xF), ssel & 0xF); |
AnnaBridge | 188:bcfe06ba3d64 | 98 | pin_mode(ssel, PushPull); |
AnnaBridge | 188:bcfe06ba3d64 | 99 | |
AnnaBridge | 188:bcfe06ba3d64 | 100 | |
AnnaBridge | 188:bcfe06ba3d64 | 101 | // Configure QSPI routing to GPIO |
AnnaBridge | 188:bcfe06ba3d64 | 102 | obj->instance->ROUTELOC0 = loc; |
AnnaBridge | 188:bcfe06ba3d64 | 103 | obj->instance->ROUTEPEN = QSPI_ROUTEPEN_SCLKPEN |
AnnaBridge | 188:bcfe06ba3d64 | 104 | | QSPI_ROUTEPEN_CS0PEN |
AnnaBridge | 188:bcfe06ba3d64 | 105 | | QSPI_ROUTEPEN_DQ0PEN |
AnnaBridge | 188:bcfe06ba3d64 | 106 | | QSPI_ROUTEPEN_DQ1PEN |
AnnaBridge | 188:bcfe06ba3d64 | 107 | | QSPI_ROUTEPEN_DQ2PEN |
AnnaBridge | 188:bcfe06ba3d64 | 108 | | QSPI_ROUTEPEN_DQ3PEN; |
AnnaBridge | 188:bcfe06ba3d64 | 109 | |
AnnaBridge | 188:bcfe06ba3d64 | 110 | // Configure direct read |
AnnaBridge | 188:bcfe06ba3d64 | 111 | QSPI_ReadConfig_TypeDef readConfig = QSPI_READCONFIG_DEFAULT; |
AnnaBridge | 188:bcfe06ba3d64 | 112 | QSPI_ReadConfig(obj->instance, &readConfig); |
AnnaBridge | 188:bcfe06ba3d64 | 113 | |
AnnaBridge | 188:bcfe06ba3d64 | 114 | // Configure direct write |
AnnaBridge | 188:bcfe06ba3d64 | 115 | QSPI_WriteConfig_TypeDef writeConfig = QSPI_WRITECONFIG_DEFAULT; |
AnnaBridge | 188:bcfe06ba3d64 | 116 | QSPI_WriteConfig(obj->instance, &writeConfig); |
AnnaBridge | 188:bcfe06ba3d64 | 117 | |
AnnaBridge | 188:bcfe06ba3d64 | 118 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 119 | } |
AnnaBridge | 188:bcfe06ba3d64 | 120 | |
AnnaBridge | 188:bcfe06ba3d64 | 121 | qspi_status_t qspi_free(qspi_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 122 | { |
AnnaBridge | 188:bcfe06ba3d64 | 123 | pin_mode(obj->io0, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 124 | pin_mode(obj->io1, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 125 | pin_mode(obj->io2, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 126 | pin_mode(obj->io3, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 127 | pin_mode(obj->ssel, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 128 | pin_mode(obj->sclk, Disabled); |
AnnaBridge | 188:bcfe06ba3d64 | 129 | |
AnnaBridge | 188:bcfe06ba3d64 | 130 | obj->instance->ROUTEPEN = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 131 | |
AnnaBridge | 188:bcfe06ba3d64 | 132 | QSPI_Enable(obj->instance, false); |
AnnaBridge | 188:bcfe06ba3d64 | 133 | CMU_ClockEnable(cmuClock_QSPI0REF, false); |
AnnaBridge | 188:bcfe06ba3d64 | 134 | CMU_ClockEnable(cmuClock_QSPI0, false); |
AnnaBridge | 188:bcfe06ba3d64 | 135 | |
AnnaBridge | 188:bcfe06ba3d64 | 136 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 137 | } |
AnnaBridge | 188:bcfe06ba3d64 | 138 | |
AnnaBridge | 188:bcfe06ba3d64 | 139 | qspi_status_t qspi_frequency(qspi_t *obj, int hz) |
AnnaBridge | 188:bcfe06ba3d64 | 140 | { |
AnnaBridge | 188:bcfe06ba3d64 | 141 | if (hz <= 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 142 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 143 | } |
AnnaBridge | 188:bcfe06ba3d64 | 144 | |
AnnaBridge | 188:bcfe06ba3d64 | 145 | QSPI_Enable(obj->instance, false); |
AnnaBridge | 188:bcfe06ba3d64 | 146 | |
AnnaBridge | 188:bcfe06ba3d64 | 147 | // Need at least a DIV4 for non-PHY mode and SDR transfers |
AnnaBridge | 188:bcfe06ba3d64 | 148 | uint32_t basefreq = CMU_ClockFreqGet(cmuClock_QSPI0REF); |
AnnaBridge | 188:bcfe06ba3d64 | 149 | uint32_t basediv = 4; |
AnnaBridge | 188:bcfe06ba3d64 | 150 | if ((uint32_t)hz < (basefreq / basediv)) { |
AnnaBridge | 188:bcfe06ba3d64 | 151 | basediv = (basefreq / hz) + 1; |
AnnaBridge | 188:bcfe06ba3d64 | 152 | } |
AnnaBridge | 188:bcfe06ba3d64 | 153 | |
AnnaBridge | 188:bcfe06ba3d64 | 154 | QSPI_Init_TypeDef initQspi = QSPI_INIT_DEFAULT; |
AnnaBridge | 188:bcfe06ba3d64 | 155 | initQspi.divisor = basediv; |
AnnaBridge | 188:bcfe06ba3d64 | 156 | QSPI_Init(obj->instance, &initQspi); |
AnnaBridge | 188:bcfe06ba3d64 | 157 | |
AnnaBridge | 188:bcfe06ba3d64 | 158 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 159 | } |
AnnaBridge | 188:bcfe06ba3d64 | 160 | |
AnnaBridge | 188:bcfe06ba3d64 | 161 | qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length) |
AnnaBridge | 188:bcfe06ba3d64 | 162 | { |
AnnaBridge | 188:bcfe06ba3d64 | 163 | QSPI_WriteConfig_TypeDef cfg = QSPI_WRITECONFIG_DEFAULT; |
AnnaBridge | 188:bcfe06ba3d64 | 164 | uint32_t to_write = *length; |
AnnaBridge | 188:bcfe06ba3d64 | 165 | |
AnnaBridge | 188:bcfe06ba3d64 | 166 | // Enforce word-sized access |
AnnaBridge | 188:bcfe06ba3d64 | 167 | if ((to_write & 0x3) != 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 168 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 169 | } |
AnnaBridge | 188:bcfe06ba3d64 | 170 | |
AnnaBridge | 188:bcfe06ba3d64 | 171 | cfg.dummyCycles = command->dummy_count; |
AnnaBridge | 188:bcfe06ba3d64 | 172 | |
AnnaBridge | 188:bcfe06ba3d64 | 173 | if (command->instruction.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 174 | cfg.opCode = 0x02; |
AnnaBridge | 188:bcfe06ba3d64 | 175 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 176 | cfg.opCode = command->instruction.value; |
AnnaBridge | 188:bcfe06ba3d64 | 177 | } |
AnnaBridge | 188:bcfe06ba3d64 | 178 | |
AnnaBridge | 188:bcfe06ba3d64 | 179 | if (command->address.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 180 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 181 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 182 | if (command->address.bus_width == QSPI_CFG_BUS_SINGLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 183 | cfg.addrTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 184 | } else if (command->address.bus_width == QSPI_CFG_BUS_DUAL) { |
AnnaBridge | 188:bcfe06ba3d64 | 185 | cfg.addrTransfer = qspiTransferDual; |
AnnaBridge | 188:bcfe06ba3d64 | 186 | } else if (command->address.bus_width == QSPI_CFG_BUS_QUAD) { |
AnnaBridge | 188:bcfe06ba3d64 | 187 | cfg.addrTransfer = qspiTransferQuad; |
AnnaBridge | 188:bcfe06ba3d64 | 188 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 189 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 190 | } |
AnnaBridge | 188:bcfe06ba3d64 | 191 | } |
AnnaBridge | 188:bcfe06ba3d64 | 192 | |
AnnaBridge | 188:bcfe06ba3d64 | 193 | if (command->data.bus_width == QSPI_CFG_BUS_SINGLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 194 | cfg.dataTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 195 | } else if (command->data.bus_width == QSPI_CFG_BUS_DUAL) { |
AnnaBridge | 188:bcfe06ba3d64 | 196 | cfg.dataTransfer = qspiTransferDual; |
AnnaBridge | 188:bcfe06ba3d64 | 197 | } else if (command->data.bus_width == QSPI_CFG_BUS_QUAD) { |
AnnaBridge | 188:bcfe06ba3d64 | 198 | cfg.dataTransfer = qspiTransferQuad; |
AnnaBridge | 188:bcfe06ba3d64 | 199 | } |
AnnaBridge | 188:bcfe06ba3d64 | 200 | |
AnnaBridge | 188:bcfe06ba3d64 | 201 | QSPI_WriteConfig(obj->instance, &cfg); |
AnnaBridge | 188:bcfe06ba3d64 | 202 | |
AnnaBridge | 188:bcfe06ba3d64 | 203 | if (!command->alt.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 204 | // Do not support alt mode in write mode |
AnnaBridge | 188:bcfe06ba3d64 | 205 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 206 | } |
AnnaBridge | 188:bcfe06ba3d64 | 207 | |
AnnaBridge | 188:bcfe06ba3d64 | 208 | // Do an indirect write |
AnnaBridge | 188:bcfe06ba3d64 | 209 | obj->instance->INDAHBADDRTRIGGER = QSPI0_MEM_BASE; |
AnnaBridge | 188:bcfe06ba3d64 | 210 | obj->instance->INDIRECTWRITEXFERSTART = command->address.value; |
AnnaBridge | 188:bcfe06ba3d64 | 211 | obj->instance->INDIRECTWRITEXFERNUMBYTES = to_write; |
AnnaBridge | 188:bcfe06ba3d64 | 212 | obj->instance->INDIRECTWRITEXFERCTRL = QSPI_INDIRECTWRITEXFERCTRL_START; |
AnnaBridge | 188:bcfe06ba3d64 | 213 | |
AnnaBridge | 188:bcfe06ba3d64 | 214 | // For the size of the transfer, poll the SRAM and fetch words from the SRAM |
AnnaBridge | 188:bcfe06ba3d64 | 215 | for (uint32_t i = 0; i < to_write; i+=4) { |
AnnaBridge | 188:bcfe06ba3d64 | 216 | // Wait for the QSPI in case we're writing too fast |
AnnaBridge | 188:bcfe06ba3d64 | 217 | while (((obj->instance->SRAMFILL & _QSPI_SRAMFILL_SRAMFILLINDACWRITE_MASK) >> _QSPI_SRAMFILL_SRAMFILLINDACWRITE_SHIFT) >= 126); |
AnnaBridge | 188:bcfe06ba3d64 | 218 | |
AnnaBridge | 188:bcfe06ba3d64 | 219 | // Unaligned access is fine on CM3/CM4 provided we stick to LDR/STR |
AnnaBridge | 188:bcfe06ba3d64 | 220 | // With the line below, the compiler can't really do anything else anyways |
AnnaBridge | 188:bcfe06ba3d64 | 221 | *((uint32_t*)QSPI0_MEM_BASE) = ((uint32_t*)data)[i/4]; |
AnnaBridge | 188:bcfe06ba3d64 | 222 | } |
AnnaBridge | 188:bcfe06ba3d64 | 223 | |
AnnaBridge | 188:bcfe06ba3d64 | 224 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 225 | } |
AnnaBridge | 188:bcfe06ba3d64 | 226 | |
AnnaBridge | 188:bcfe06ba3d64 | 227 | qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size) |
AnnaBridge | 188:bcfe06ba3d64 | 228 | { |
AnnaBridge | 188:bcfe06ba3d64 | 229 | QSPI_StigCmd_TypeDef cfg; |
AnnaBridge | 188:bcfe06ba3d64 | 230 | |
AnnaBridge | 188:bcfe06ba3d64 | 231 | if (tx_size > 8 || rx_size > 8) { |
AnnaBridge | 188:bcfe06ba3d64 | 232 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 233 | } |
AnnaBridge | 188:bcfe06ba3d64 | 234 | |
AnnaBridge | 188:bcfe06ba3d64 | 235 | cfg.writeDataSize = tx_size; |
AnnaBridge | 188:bcfe06ba3d64 | 236 | cfg.writeBuffer = (void*)tx_data; |
AnnaBridge | 188:bcfe06ba3d64 | 237 | |
AnnaBridge | 188:bcfe06ba3d64 | 238 | cfg.readDataSize = rx_size; |
AnnaBridge | 188:bcfe06ba3d64 | 239 | cfg.readBuffer = rx_data; |
AnnaBridge | 188:bcfe06ba3d64 | 240 | |
AnnaBridge | 188:bcfe06ba3d64 | 241 | if (command->address.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 242 | cfg.addrSize = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 243 | cfg.address = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 244 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 245 | if (command->address.size == QSPI_CFG_ADDR_SIZE_8) { |
AnnaBridge | 188:bcfe06ba3d64 | 246 | cfg.addrSize = 1; |
AnnaBridge | 188:bcfe06ba3d64 | 247 | } else if (command->address.size == QSPI_CFG_ADDR_SIZE_16) { |
AnnaBridge | 188:bcfe06ba3d64 | 248 | cfg.addrSize = 2; |
AnnaBridge | 188:bcfe06ba3d64 | 249 | } else if (command->address.size == QSPI_CFG_ADDR_SIZE_24) { |
AnnaBridge | 188:bcfe06ba3d64 | 250 | cfg.addrSize = 3; |
AnnaBridge | 188:bcfe06ba3d64 | 251 | } else if (command->address.size == QSPI_CFG_ADDR_SIZE_32) { |
AnnaBridge | 188:bcfe06ba3d64 | 252 | cfg.addrSize = 4; |
AnnaBridge | 188:bcfe06ba3d64 | 253 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 254 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 255 | } |
AnnaBridge | 188:bcfe06ba3d64 | 256 | cfg.address = command->address.value; |
AnnaBridge | 188:bcfe06ba3d64 | 257 | } |
AnnaBridge | 188:bcfe06ba3d64 | 258 | |
AnnaBridge | 188:bcfe06ba3d64 | 259 | if (command->instruction.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 260 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 261 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 262 | cfg.cmdOpcode = command->instruction.value; |
AnnaBridge | 188:bcfe06ba3d64 | 263 | } |
AnnaBridge | 188:bcfe06ba3d64 | 264 | |
AnnaBridge | 188:bcfe06ba3d64 | 265 | cfg.dummyCycles = command->dummy_count; |
AnnaBridge | 188:bcfe06ba3d64 | 266 | |
AnnaBridge | 188:bcfe06ba3d64 | 267 | if (!command->alt.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 268 | cfg.modeBitEnable = true; |
AnnaBridge | 188:bcfe06ba3d64 | 269 | obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; |
AnnaBridge | 188:bcfe06ba3d64 | 270 | |
AnnaBridge | 188:bcfe06ba3d64 | 271 | if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { |
AnnaBridge | 188:bcfe06ba3d64 | 272 | //do not support 'alt' bigger than 8 bit |
AnnaBridge | 188:bcfe06ba3d64 | 273 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 274 | } |
AnnaBridge | 188:bcfe06ba3d64 | 275 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 276 | cfg.modeBitEnable = false; |
AnnaBridge | 188:bcfe06ba3d64 | 277 | } |
AnnaBridge | 188:bcfe06ba3d64 | 278 | |
AnnaBridge | 188:bcfe06ba3d64 | 279 | QSPI_ExecStigCmd(obj->instance, &cfg); |
AnnaBridge | 188:bcfe06ba3d64 | 280 | |
AnnaBridge | 188:bcfe06ba3d64 | 281 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 282 | } |
AnnaBridge | 188:bcfe06ba3d64 | 283 | |
AnnaBridge | 188:bcfe06ba3d64 | 284 | qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length) |
AnnaBridge | 188:bcfe06ba3d64 | 285 | { |
AnnaBridge | 188:bcfe06ba3d64 | 286 | QSPI_ReadConfig_TypeDef cfg = QSPI_READCONFIG_DEFAULT; |
AnnaBridge | 188:bcfe06ba3d64 | 287 | uint32_t to_read = *length; |
AnnaBridge | 188:bcfe06ba3d64 | 288 | |
AnnaBridge | 188:bcfe06ba3d64 | 289 | // Enforce word-sized access |
AnnaBridge | 188:bcfe06ba3d64 | 290 | if ((to_read & 0x3) != 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 291 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 292 | } |
AnnaBridge | 188:bcfe06ba3d64 | 293 | |
AnnaBridge | 188:bcfe06ba3d64 | 294 | cfg.dummyCycles = command->dummy_count; |
AnnaBridge | 188:bcfe06ba3d64 | 295 | |
AnnaBridge | 188:bcfe06ba3d64 | 296 | if (command->instruction.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 297 | cfg.opCode = 0x03; |
AnnaBridge | 188:bcfe06ba3d64 | 298 | cfg.instTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 299 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 300 | cfg.opCode = command->instruction.value; |
AnnaBridge | 188:bcfe06ba3d64 | 301 | if (command->instruction.bus_width == QSPI_CFG_BUS_SINGLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 302 | cfg.instTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 303 | } else if (command->instruction.bus_width == QSPI_CFG_BUS_DUAL) { |
AnnaBridge | 188:bcfe06ba3d64 | 304 | cfg.instTransfer = qspiTransferDual; |
AnnaBridge | 188:bcfe06ba3d64 | 305 | } else if (command->instruction.bus_width == QSPI_CFG_BUS_QUAD) { |
AnnaBridge | 188:bcfe06ba3d64 | 306 | cfg.instTransfer = qspiTransferQuad; |
AnnaBridge | 188:bcfe06ba3d64 | 307 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 308 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 309 | } |
AnnaBridge | 188:bcfe06ba3d64 | 310 | } |
AnnaBridge | 188:bcfe06ba3d64 | 311 | |
AnnaBridge | 188:bcfe06ba3d64 | 312 | if (command->address.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 313 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 314 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 315 | if (command->address.bus_width == QSPI_CFG_BUS_SINGLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 316 | cfg.addrTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 317 | } else if (command->address.bus_width == QSPI_CFG_BUS_DUAL) { |
AnnaBridge | 188:bcfe06ba3d64 | 318 | cfg.addrTransfer = qspiTransferDual; |
AnnaBridge | 188:bcfe06ba3d64 | 319 | } else if (command->address.bus_width == QSPI_CFG_BUS_QUAD) { |
AnnaBridge | 188:bcfe06ba3d64 | 320 | cfg.addrTransfer = qspiTransferQuad; |
AnnaBridge | 188:bcfe06ba3d64 | 321 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 322 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 323 | } |
AnnaBridge | 188:bcfe06ba3d64 | 324 | } |
AnnaBridge | 188:bcfe06ba3d64 | 325 | |
AnnaBridge | 188:bcfe06ba3d64 | 326 | if (command->data.bus_width == QSPI_CFG_BUS_SINGLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 327 | cfg.dataTransfer = qspiTransferSingle; |
AnnaBridge | 188:bcfe06ba3d64 | 328 | } else if (command->data.bus_width == QSPI_CFG_BUS_DUAL) { |
AnnaBridge | 188:bcfe06ba3d64 | 329 | cfg.dataTransfer = qspiTransferDual; |
AnnaBridge | 188:bcfe06ba3d64 | 330 | } else if (command->data.bus_width == QSPI_CFG_BUS_QUAD) { |
AnnaBridge | 188:bcfe06ba3d64 | 331 | cfg.dataTransfer = qspiTransferQuad; |
AnnaBridge | 188:bcfe06ba3d64 | 332 | } |
AnnaBridge | 188:bcfe06ba3d64 | 333 | |
AnnaBridge | 188:bcfe06ba3d64 | 334 | QSPI_ReadConfig(obj->instance, &cfg); |
AnnaBridge | 188:bcfe06ba3d64 | 335 | |
AnnaBridge | 188:bcfe06ba3d64 | 336 | if (!command->alt.disabled) { |
AnnaBridge | 188:bcfe06ba3d64 | 337 | // Need to set up alt mode manually, called 'mode bits' in EFM32GG11 refman |
AnnaBridge | 188:bcfe06ba3d64 | 338 | obj->instance->DEVINSTRRDCONFIG |= QSPI_DEVINSTRRDCONFIG_MODEBITENABLE; |
AnnaBridge | 188:bcfe06ba3d64 | 339 | obj->instance->MODEBITCONFIG = command->alt.value & _QSPI_MODEBITCONFIG_MODE_MASK; |
AnnaBridge | 188:bcfe06ba3d64 | 340 | |
AnnaBridge | 188:bcfe06ba3d64 | 341 | if(command->alt.size != QSPI_CFG_ALT_SIZE_8) { |
AnnaBridge | 188:bcfe06ba3d64 | 342 | // Do not support 'alt' bigger than 8 bit |
AnnaBridge | 188:bcfe06ba3d64 | 343 | return QSPI_STATUS_INVALID_PARAMETER; |
AnnaBridge | 188:bcfe06ba3d64 | 344 | } |
AnnaBridge | 188:bcfe06ba3d64 | 345 | } |
AnnaBridge | 188:bcfe06ba3d64 | 346 | |
AnnaBridge | 188:bcfe06ba3d64 | 347 | // Do an indirect read |
AnnaBridge | 188:bcfe06ba3d64 | 348 | obj->instance->INDAHBADDRTRIGGER = QSPI0_MEM_BASE; |
AnnaBridge | 188:bcfe06ba3d64 | 349 | obj->instance->INDIRECTREADXFERSTART = command->address.value; |
AnnaBridge | 188:bcfe06ba3d64 | 350 | obj->instance->INDIRECTREADXFERNUMBYTES = to_read; |
AnnaBridge | 188:bcfe06ba3d64 | 351 | obj->instance->INDIRECTREADXFERCTRL = QSPI_INDIRECTREADXFERCTRL_START; |
AnnaBridge | 188:bcfe06ba3d64 | 352 | |
AnnaBridge | 188:bcfe06ba3d64 | 353 | // For the size of the transfer, poll the SRAM and fetch words from the SRAM |
AnnaBridge | 188:bcfe06ba3d64 | 354 | for (uint32_t i = 0; i < to_read; i+=4) { |
AnnaBridge | 188:bcfe06ba3d64 | 355 | // Wait for the FIFO in case we're reading too fast |
AnnaBridge | 188:bcfe06ba3d64 | 356 | while ((obj->instance->SRAMFILL & _QSPI_SRAMFILL_SRAMFILLINDACREAD_MASK) >> _QSPI_SRAMFILL_SRAMFILLINDACREAD_SHIFT == 0); |
AnnaBridge | 188:bcfe06ba3d64 | 357 | |
AnnaBridge | 188:bcfe06ba3d64 | 358 | // Unaligned access is fine on CM3/CM4 provided we stick to LDR/STR |
AnnaBridge | 188:bcfe06ba3d64 | 359 | // With the line below, the compiler can't really do anything else anyways |
AnnaBridge | 188:bcfe06ba3d64 | 360 | ((uint32_t*)data)[i/4] = *((uint32_t*)QSPI0_MEM_BASE); |
AnnaBridge | 188:bcfe06ba3d64 | 361 | } |
AnnaBridge | 188:bcfe06ba3d64 | 362 | |
AnnaBridge | 188:bcfe06ba3d64 | 363 | return QSPI_STATUS_OK; |
AnnaBridge | 188:bcfe06ba3d64 | 364 | } |
AnnaBridge | 188:bcfe06ba3d64 | 365 | |
AnnaBridge | 188:bcfe06ba3d64 | 366 | #endif /* DEVICE_QSPI && QSPI_PRESENT */ |