mcuboot/boot/cypress/cy_flash_pal/flash_qspi/flash_qspi.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);
}