495 lines
14 KiB
C
495 lines
14 KiB
C
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
/***************************************************************************//**
|
|
* \file flash_qspi.c
|
|
* \version 1.0
|
|
*
|
|
* \brief
|
|
* This is the source file of external flash driver adaptation layer between PSoC6
|
|
* and standard MCUBoot code.
|
|
*
|
|
********************************************************************************
|
|
* \copyright
|
|
*
|
|
* (c) 2020, Cypress Semiconductor Corporation
|
|
* or a subsidiary of Cypress Semiconductor Corporation. All rights
|
|
* reserved.
|
|
*
|
|
* This software, including source code, documentation and related
|
|
* materials ("Software"), is owned by Cypress Semiconductor
|
|
* Corporation or one of its subsidiaries ("Cypress") and is protected by
|
|
* and subject to worldwide patent protection (United States and foreign),
|
|
* United States copyright laws and international treaty provisions.
|
|
* Therefore, you may use this Software only as provided in the license
|
|
* agreement accompanying the software package from which you
|
|
* obtained this Software ("EULA").
|
|
*
|
|
* If no EULA applies, Cypress hereby grants you a personal, non-
|
|
* exclusive, non-transferable license to copy, modify, and compile the
|
|
* Software source code solely for use in connection with Cypress?s
|
|
* integrated circuit products. Any reproduction, modification, translation,
|
|
* compilation, or representation of this Software except as specified
|
|
* above is prohibited without the express written permission of Cypress.
|
|
*
|
|
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
|
|
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
|
|
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE. Cypress reserves the right to make
|
|
* changes to the Software without notice. Cypress does not assume any
|
|
* liability arising out of the application or use of the Software or any
|
|
* product or circuit described in the Software. Cypress does not
|
|
* authorize its products for use in any products where a malfunction or
|
|
* failure of the Cypress product may reasonably be expected to result in
|
|
* significant property damage, injury or death ("High Risk Product"). By
|
|
* including Cypress's product in a High Risk Product, the manufacturer
|
|
* of such system or application assumes all risk of such use and in doing
|
|
* so agrees to indemnify Cypress against all liability.
|
|
*
|
|
******************************************************************************/
|
|
#include "cy_pdl.h"
|
|
#include <stdio.h>
|
|
#include "flash_qspi.h"
|
|
|
|
#define CY_SMIF_SYSCLK_HFCLK_DIVIDER CY_SYSCLK_CLKHF_DIVIDE_BY_4
|
|
|
|
/* This is the board specific stuff that should align with your board.
|
|
*
|
|
* QSPI resources:
|
|
*
|
|
* SS0 - P11_2
|
|
* SS1 - P11_1
|
|
* SS2 - P11_0
|
|
* SS3 - P12_4
|
|
*
|
|
* D3 - P11_3
|
|
* D2 - P11_4
|
|
* D1 - P11_5
|
|
* D0 - P11_6
|
|
*
|
|
* SCK - P11_7
|
|
*
|
|
* SMIF Block - SMIF0
|
|
*
|
|
*/
|
|
|
|
/* SMIF SlaveSelect Configurations */
|
|
struct qspi_ss_config
|
|
{
|
|
GPIO_PRT_Type* SS_Port;
|
|
int SS_Pin;
|
|
en_hsiom_sel_t SS_Mux;
|
|
};
|
|
|
|
#if (defined(PSOC_064_2M) || \
|
|
defined(PSOC_064_1M) || \
|
|
defined(PSOC_062_2M) || \
|
|
defined(PSOC_062_1M))
|
|
#define CY_BOOTLOADER_SMIF_SS_CFG_NUM 4
|
|
#elif defined(PSOC_064_512K) || defined(PSOC_062_512K)
|
|
#define CY_BOOTLOADER_SMIF_SS_CFG_NUM 3
|
|
#else
|
|
#error "Platform device name is unsupported."
|
|
#endif
|
|
struct qspi_ss_config qspi_SS_Configuration[CY_BOOTLOADER_SMIF_SS_CFG_NUM] =
|
|
{
|
|
{
|
|
.SS_Port = GPIO_PRT11,
|
|
.SS_Pin = 2,
|
|
.SS_Mux = P11_2_SMIF_SPI_SELECT0
|
|
},
|
|
{
|
|
.SS_Port = GPIO_PRT11,
|
|
.SS_Pin = 1,
|
|
.SS_Mux = P11_1_SMIF_SPI_SELECT1
|
|
},
|
|
{
|
|
.SS_Port = GPIO_PRT11,
|
|
.SS_Pin = 0,
|
|
.SS_Mux = P11_0_SMIF_SPI_SELECT2
|
|
},
|
|
#if(CY_BOOTLOADER_SMIF_SS_CFG_NUM > 3)
|
|
{
|
|
.SS_Port = GPIO_PRT12,
|
|
.SS_Pin = 4,
|
|
.SS_Mux = P12_4_SMIF_SPI_SELECT3
|
|
}
|
|
#endif
|
|
};
|
|
|
|
static GPIO_PRT_Type *D3Port = GPIO_PRT11;
|
|
static int D3Pin = 3;
|
|
static en_hsiom_sel_t D3MuxPort = P11_3_SMIF_SPI_DATA3;
|
|
|
|
static GPIO_PRT_Type *D2Port = GPIO_PRT11;
|
|
static int D2Pin = 4;
|
|
static en_hsiom_sel_t D2MuxPort = P11_4_SMIF_SPI_DATA2;
|
|
|
|
static GPIO_PRT_Type *D1Port = GPIO_PRT11;
|
|
static int D1Pin = 5;
|
|
static en_hsiom_sel_t D1MuxPort = P11_5_SMIF_SPI_DATA1;
|
|
|
|
static GPIO_PRT_Type *D0Port = GPIO_PRT11;
|
|
static int D0Pin = 6;
|
|
static en_hsiom_sel_t D0MuxPort = P11_6_SMIF_SPI_DATA0;
|
|
|
|
static GPIO_PRT_Type *SCKPort = GPIO_PRT11;
|
|
static int SCKPin = 7;
|
|
static en_hsiom_sel_t SCKMuxPort = P11_7_SMIF_SPI_CLK;
|
|
|
|
static SMIF_Type *QSPIPort = SMIF0;
|
|
|
|
cy_stc_smif_mem_cmd_t sfdpcmd =
|
|
{
|
|
.command = 0x5A,
|
|
.cmdWidth = CY_SMIF_WIDTH_SINGLE,
|
|
.addrWidth = CY_SMIF_WIDTH_SINGLE,
|
|
.mode = 0xFFFFFFFFU,
|
|
.dummyCycles = 8,
|
|
.dataWidth = CY_SMIF_WIDTH_SINGLE,
|
|
};
|
|
|
|
static cy_stc_smif_mem_cmd_t rdcmd0;
|
|
static cy_stc_smif_mem_cmd_t wrencmd0;
|
|
static cy_stc_smif_mem_cmd_t wrdiscmd0;
|
|
static cy_stc_smif_mem_cmd_t erasecmd0;
|
|
static cy_stc_smif_mem_cmd_t chiperasecmd0;
|
|
static cy_stc_smif_mem_cmd_t pgmcmd0;
|
|
static cy_stc_smif_mem_cmd_t readsts0;
|
|
static cy_stc_smif_mem_cmd_t readstsqecmd0;
|
|
static cy_stc_smif_mem_cmd_t writestseqcmd0;
|
|
|
|
static cy_stc_smif_mem_device_cfg_t dev_sfdp_0 =
|
|
{
|
|
.numOfAddrBytes = 4,
|
|
.readSfdpCmd = &sfdpcmd,
|
|
.readCmd = &rdcmd0,
|
|
.writeEnCmd = &wrencmd0,
|
|
.writeDisCmd = &wrdiscmd0,
|
|
.programCmd = &pgmcmd0,
|
|
.eraseCmd = &erasecmd0,
|
|
.chipEraseCmd = &chiperasecmd0,
|
|
.readStsRegWipCmd = &readsts0,
|
|
.readStsRegQeCmd = &readstsqecmd0,
|
|
.writeStsRegQeCmd = &writestseqcmd0,
|
|
};
|
|
|
|
static cy_stc_smif_mem_config_t mem_sfdp_0 =
|
|
{
|
|
/* The base address the memory slave is mapped to in the PSoC memory map.
|
|
Valid when the memory-mapped mode is enabled. */
|
|
.baseAddress = 0x18000000U,
|
|
/* The size allocated in the PSoC memory map, for the memory slave device.
|
|
The size is allocated from the base address. Valid when the memory mapped mode is enabled. */
|
|
/* .memMappedSize = 0x4000000U, */
|
|
.flags = CY_SMIF_FLAG_DETECT_SFDP,
|
|
.slaveSelect = CY_SMIF_SLAVE_SELECT_0,
|
|
.dataSelect = CY_SMIF_DATA_SEL0,
|
|
.deviceCfg = &dev_sfdp_0
|
|
};
|
|
|
|
cy_stc_smif_mem_config_t *mems_sfdp[1] =
|
|
{
|
|
&mem_sfdp_0
|
|
};
|
|
|
|
/* make it exported if used in TOC (cy_serial_flash_prog.c) */
|
|
/* cy_stc_smif_block_config_t smifBlockConfig_sfdp = */
|
|
static cy_stc_smif_block_config_t smifBlockConfig_sfdp =
|
|
{
|
|
.memCount = 1,
|
|
.memConfig = mems_sfdp,
|
|
};
|
|
|
|
static cy_stc_smif_block_config_t *smif_blk_config;
|
|
|
|
static cy_stc_smif_context_t QSPI_context;
|
|
|
|
cy_stc_smif_config_t const QSPI_config =
|
|
{
|
|
.mode = CY_SMIF_NORMAL,
|
|
.deselectDelay = 1,
|
|
.rxClockSel = CY_SMIF_SEL_INV_INTERNAL_CLK,
|
|
.blockEvent = CY_SMIF_BUS_ERROR
|
|
};
|
|
|
|
cy_stc_sysint_t smifIntConfig =
|
|
{/* ATTENTION: make sure proper Interrupts configured for CM0p or M4 cores */
|
|
.intrSrc = NvicMux7_IRQn,
|
|
.cm0pSrc = smif_interrupt_IRQn,
|
|
.intrPriority = 1
|
|
};
|
|
|
|
/* SMIF pinouts configurations */
|
|
static cy_stc_gpio_pin_config_t QSPI_SS_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG_IN_OFF,
|
|
.hsiom = P11_2_SMIF_SPI_SELECT0, /* lets use SS0 by default */
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
const cy_stc_gpio_pin_config_t QSPI_DATA3_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG,
|
|
.hsiom = P11_3_SMIF_SPI_DATA3,
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
const cy_stc_gpio_pin_config_t QSPI_DATA2_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG,
|
|
.hsiom = P11_4_SMIF_SPI_DATA2,
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
const cy_stc_gpio_pin_config_t QSPI_DATA1_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG,
|
|
.hsiom = P11_5_SMIF_SPI_DATA1,
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
const cy_stc_gpio_pin_config_t QSPI_DATA0_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG,
|
|
.hsiom = P11_6_SMIF_SPI_DATA0,
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
const cy_stc_gpio_pin_config_t QSPI_SCK_config =
|
|
{
|
|
.outVal = 1,
|
|
.driveMode = CY_GPIO_DM_STRONG_IN_OFF,
|
|
.hsiom = P11_7_SMIF_SPI_CLK,
|
|
.intEdge = CY_GPIO_INTR_DISABLE,
|
|
.intMask = 0UL,
|
|
.vtrip = CY_GPIO_VTRIP_CMOS,
|
|
.slewRate = CY_GPIO_SLEW_FAST,
|
|
.driveSel = CY_GPIO_DRIVE_1_2,
|
|
.vregEn = 0UL,
|
|
.ibufMode = 0UL,
|
|
.vtripSel = 0UL,
|
|
.vrefSel = 0UL,
|
|
.vohSel = 0UL,
|
|
};
|
|
|
|
void Isr_SMIF(void)
|
|
{
|
|
Cy_SMIF_Interrupt(QSPIPort, &QSPI_context);
|
|
}
|
|
|
|
cy_en_smif_status_t qspi_init_hardware()
|
|
{
|
|
cy_en_smif_status_t st;
|
|
|
|
|
|
Cy_GPIO_Pin_Init(D3Port, D3Pin, &QSPI_DATA3_config);
|
|
Cy_GPIO_SetHSIOM(D3Port, D3Pin, D3MuxPort);
|
|
|
|
Cy_GPIO_Pin_Init(D2Port, D2Pin, &QSPI_DATA2_config);
|
|
Cy_GPIO_SetHSIOM(D2Port, D2Pin, D2MuxPort);
|
|
|
|
Cy_GPIO_Pin_Init(D1Port, D1Pin, &QSPI_DATA1_config);
|
|
Cy_GPIO_SetHSIOM(D1Port, D1Pin, D1MuxPort);
|
|
|
|
Cy_GPIO_Pin_Init(D0Port, D0Pin, &QSPI_DATA0_config);
|
|
Cy_GPIO_SetHSIOM(D0Port, D0Pin, D0MuxPort);
|
|
|
|
Cy_GPIO_Pin_Init(SCKPort, SCKPin, &QSPI_SCK_config);
|
|
Cy_GPIO_SetHSIOM(SCKPort, SCKPin, SCKMuxPort);
|
|
|
|
Cy_SysClk_ClkHfSetSource(CY_SYSCLK_CLKHF_IN_CLKPATH2, CY_SYSCLK_CLKHF_IN_CLKPATH0);
|
|
Cy_SysClk_ClkHfSetDivider(CY_SYSCLK_CLKHF_IN_CLKPATH2, CY_SMIF_SYSCLK_HFCLK_DIVIDER);
|
|
Cy_SysClk_ClkHfEnable(CY_SYSCLK_CLKHF_IN_CLKPATH2);
|
|
|
|
/*
|
|
* Setup the interrupt for the SMIF block. For the CM0 there
|
|
* is a two stage process to setup the interrupts.
|
|
*/
|
|
Cy_SysInt_Init(&smifIntConfig, Isr_SMIF);
|
|
|
|
st = Cy_SMIF_Init(QSPIPort, &QSPI_config, 1000, &QSPI_context);
|
|
if (st != CY_SMIF_SUCCESS)
|
|
{
|
|
return st;
|
|
}
|
|
NVIC_EnableIRQ(smifIntConfig.intrSrc); /* Finally, Enable the SMIF interrupt */
|
|
|
|
Cy_SMIF_Enable(QSPIPort, &QSPI_context);
|
|
|
|
return CY_SMIF_SUCCESS;
|
|
}
|
|
|
|
cy_stc_smif_mem_config_t *qspi_get_memory_config(int index)
|
|
{
|
|
return smif_blk_config->memConfig[index];
|
|
}
|
|
|
|
SMIF_Type *qspi_get_device()
|
|
{
|
|
return QSPIPort;
|
|
}
|
|
|
|
cy_stc_smif_context_t *qspi_get_context()
|
|
{
|
|
return &QSPI_context;
|
|
}
|
|
|
|
cy_en_smif_status_t qspi_init(cy_stc_smif_block_config_t *blk_config)
|
|
{
|
|
cy_en_smif_status_t st;
|
|
|
|
st = qspi_init_hardware();
|
|
if (st == CY_SMIF_SUCCESS)
|
|
{
|
|
smif_blk_config = blk_config;
|
|
st = Cy_SMIF_MemInit(QSPIPort, smif_blk_config, &QSPI_context);
|
|
}
|
|
return st;
|
|
}
|
|
|
|
cy_en_smif_status_t qspi_init_sfdp(uint32_t smif_id)
|
|
{
|
|
cy_en_smif_status_t stat = CY_SMIF_SUCCESS;
|
|
|
|
cy_stc_smif_mem_config_t **memCfg = smifBlockConfig_sfdp.memConfig;
|
|
|
|
GPIO_PRT_Type *SS_Port;
|
|
int SS_Pin;
|
|
en_hsiom_sel_t SS_MuxPort;
|
|
|
|
switch(smif_id)
|
|
{
|
|
case 1:
|
|
(*memCfg)->slaveSelect = CY_SMIF_SLAVE_SELECT_0;
|
|
break;
|
|
case 2:
|
|
(*memCfg)->slaveSelect = CY_SMIF_SLAVE_SELECT_1;
|
|
break;
|
|
case 3:
|
|
(*memCfg)->slaveSelect = CY_SMIF_SLAVE_SELECT_2;
|
|
break;
|
|
#if(CY_BOOTLOADER_SMIF_SS_CFG_NUM > 3)
|
|
case 4:
|
|
(*memCfg)->slaveSelect = CY_SMIF_SLAVE_SELECT_3;
|
|
break;
|
|
#endif
|
|
default:
|
|
stat = -1;
|
|
break;
|
|
}
|
|
|
|
if(CY_SMIF_SUCCESS == stat)
|
|
{
|
|
SS_Port = qspi_SS_Configuration[smif_id-1].SS_Port;
|
|
SS_Pin = qspi_SS_Configuration[smif_id-1].SS_Pin;
|
|
SS_MuxPort = qspi_SS_Configuration[smif_id-1].SS_Mux;
|
|
|
|
QSPI_SS_config.hsiom = SS_MuxPort;
|
|
|
|
Cy_GPIO_Pin_Init(SS_Port, SS_Pin, &QSPI_SS_config);
|
|
Cy_GPIO_SetHSIOM(SS_Port, SS_Pin, SS_MuxPort);
|
|
|
|
stat = qspi_init(&smifBlockConfig_sfdp);
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
uint32_t qspi_get_prog_size(void)
|
|
{
|
|
cy_stc_smif_mem_config_t **memCfg = smifBlockConfig_sfdp.memConfig;
|
|
return (*memCfg)->deviceCfg->programSize;
|
|
}
|
|
|
|
uint32_t qspi_get_erase_size(void)
|
|
{
|
|
cy_stc_smif_mem_config_t **memCfg = smifBlockConfig_sfdp.memConfig;
|
|
return (*memCfg)->deviceCfg->eraseSize;
|
|
}
|
|
|
|
uint32_t qspi_get_mem_size(void)
|
|
{
|
|
cy_stc_smif_mem_config_t **memCfg = smifBlockConfig_sfdp.memConfig;
|
|
return (*memCfg)->deviceCfg->memSize;
|
|
}
|
|
|
|
void qspi_deinit(uint32_t smif_id)
|
|
{
|
|
Cy_SMIF_MemDeInit(QSPIPort);
|
|
|
|
Cy_SMIF_Disable(QSPIPort);
|
|
|
|
Cy_SysClk_ClkHfDisable(CY_SYSCLK_CLKHF_IN_CLKPATH2);
|
|
|
|
NVIC_DisableIRQ(smifIntConfig.intrSrc);
|
|
Cy_SysInt_DisconnectInterruptSource(smifIntConfig.intrSrc, smifIntConfig.cm0pSrc);
|
|
|
|
Cy_GPIO_Port_Deinit(qspi_SS_Configuration[smif_id-1].SS_Port);
|
|
Cy_GPIO_Port_Deinit(SCKPort);
|
|
Cy_GPIO_Port_Deinit(D0Port);
|
|
Cy_GPIO_Port_Deinit(D1Port);
|
|
Cy_GPIO_Port_Deinit(D2Port);
|
|
Cy_GPIO_Port_Deinit(D3Port);
|
|
}
|