1*b525a8f0SKuldeep Singh // SPDX-License-Identifier: BSD-3-Clause 2*b525a8f0SKuldeep Singh /* 3*b525a8f0SKuldeep Singh * NXP FlexSpi Controller Driver. 4*b525a8f0SKuldeep Singh * Copyright 2021 NXP 5*b525a8f0SKuldeep Singh * 6*b525a8f0SKuldeep Singh */ 7*b525a8f0SKuldeep Singh #include <endian.h> 8*b525a8f0SKuldeep Singh #include <stdint.h> 9*b525a8f0SKuldeep Singh #include <stdio.h> 10*b525a8f0SKuldeep Singh #include <string.h> 11*b525a8f0SKuldeep Singh 12*b525a8f0SKuldeep Singh #include <common/debug.h> 13*b525a8f0SKuldeep Singh #include <flash_info.h> 14*b525a8f0SKuldeep Singh #include "fspi.h" 15*b525a8f0SKuldeep Singh #include <fspi_api.h> 16*b525a8f0SKuldeep Singh #include <xspi_error_codes.h> 17*b525a8f0SKuldeep Singh 18*b525a8f0SKuldeep Singh #ifdef DEBUG_FLEXSPI 19*b525a8f0SKuldeep Singh #define PR printf("In [%s][%d]\n", __func__, __LINE__) 20*b525a8f0SKuldeep Singh #define PRA(a, b) printf("In [%s][%d] %s="a"\n", __func__, __LINE__, #b, b) 21*b525a8f0SKuldeep Singh #else 22*b525a8f0SKuldeep Singh #define PR 23*b525a8f0SKuldeep Singh #define PRA(a, b) 24*b525a8f0SKuldeep Singh #endif 25*b525a8f0SKuldeep Singh 26*b525a8f0SKuldeep Singh /* 27*b525a8f0SKuldeep Singh * This errata is valid for all NXP SoC. 28*b525a8f0SKuldeep Singh */ 29*b525a8f0SKuldeep Singh #define ERRATA_FLASH_A050272 1 30*b525a8f0SKuldeep Singh 31*b525a8f0SKuldeep Singh static uintptr_t fspi_base_reg_addr; 32*b525a8f0SKuldeep Singh static uintptr_t fspi_flash_base_addr; 33*b525a8f0SKuldeep Singh 34*b525a8f0SKuldeep Singh static void fspi_RDSR(uint32_t *, const void *, uint32_t); 35*b525a8f0SKuldeep Singh 36*b525a8f0SKuldeep Singh static void fspi_writel(uint32_t x_addr, uint32_t x_val) 37*b525a8f0SKuldeep Singh { 38*b525a8f0SKuldeep Singh fspi_out32((uint32_t *)(fspi_base_reg_addr + x_addr), 39*b525a8f0SKuldeep Singh (uint32_t) x_val); 40*b525a8f0SKuldeep Singh } 41*b525a8f0SKuldeep Singh 42*b525a8f0SKuldeep Singh static uint32_t fspi_readl(uint32_t x_addr) 43*b525a8f0SKuldeep Singh { 44*b525a8f0SKuldeep Singh return fspi_in32((uint32_t *)(fspi_base_reg_addr + x_addr)); 45*b525a8f0SKuldeep Singh } 46*b525a8f0SKuldeep Singh 47*b525a8f0SKuldeep Singh static void fspi_MDIS(uint8_t x_disable) 48*b525a8f0SKuldeep Singh { 49*b525a8f0SKuldeep Singh uint32_t ui_reg; 50*b525a8f0SKuldeep Singh 51*b525a8f0SKuldeep Singh ui_reg = fspi_readl(FSPI_MCR0); 52*b525a8f0SKuldeep Singh if (x_disable != 0U) { 53*b525a8f0SKuldeep Singh ui_reg |= FSPI_MCR0_MDIS; 54*b525a8f0SKuldeep Singh } else { 55*b525a8f0SKuldeep Singh ui_reg &= (uint32_t) (~FSPI_MCR0_MDIS); 56*b525a8f0SKuldeep Singh } 57*b525a8f0SKuldeep Singh 58*b525a8f0SKuldeep Singh fspi_writel(FSPI_MCR0, ui_reg); 59*b525a8f0SKuldeep Singh } 60*b525a8f0SKuldeep Singh 61*b525a8f0SKuldeep Singh static void fspi_lock_LUT(void) 62*b525a8f0SKuldeep Singh { 63*b525a8f0SKuldeep Singh fspi_writel(FSPI_LUTKEY, FSPI_LUTKEY_VALUE); 64*b525a8f0SKuldeep Singh VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR)); 65*b525a8f0SKuldeep Singh fspi_writel(FSPI_LCKCR, FSPI_LCKER_LOCK); 66*b525a8f0SKuldeep Singh VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR)); 67*b525a8f0SKuldeep Singh } 68*b525a8f0SKuldeep Singh 69*b525a8f0SKuldeep Singh static void fspi_unlock_LUT(void) 70*b525a8f0SKuldeep Singh { 71*b525a8f0SKuldeep Singh fspi_writel(FSPI_LUTKEY, FSPI_LUTKEY_VALUE); 72*b525a8f0SKuldeep Singh VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR)); 73*b525a8f0SKuldeep Singh fspi_writel(FSPI_LCKCR, FSPI_LCKER_UNLOCK); 74*b525a8f0SKuldeep Singh VERBOSE("%s 0x%x\n", __func__, fspi_readl(FSPI_LCKCR)); 75*b525a8f0SKuldeep Singh } 76*b525a8f0SKuldeep Singh 77*b525a8f0SKuldeep Singh static void fspi_op_setup(uint32_t fspi_op_seq_id, bool ignore_flash_sz) 78*b525a8f0SKuldeep Singh { 79*b525a8f0SKuldeep Singh uint32_t x_addr, x_instr0 = 0, x_instr1 = 0, x_instr2 = 0; 80*b525a8f0SKuldeep Singh uint32_t cmd_id1, cmd_id2; 81*b525a8f0SKuldeep Singh 82*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 83*b525a8f0SKuldeep Singh 84*b525a8f0SKuldeep Singh switch (fspi_op_seq_id) { 85*b525a8f0SKuldeep Singh case FSPI_READ_SEQ_ID: 86*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_READ; 87*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_READ_4B; 88*b525a8f0SKuldeep Singh x_instr2 = FSPI_INSTR_OPRND0(0) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1) 89*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE0(FSPI_LUT_READ); 90*b525a8f0SKuldeep Singh break; 91*b525a8f0SKuldeep Singh case FSPI_FASTREAD_SEQ_ID: 92*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_FASTREAD; 93*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_FASTREAD_4B; 94*b525a8f0SKuldeep Singh x_instr2 = FSPI_INSTR_OPRND0(8) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1) 95*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE0(FSPI_DUMMY_SDR) 96*b525a8f0SKuldeep Singh | FSPI_INSTR_OPRND1(0) 97*b525a8f0SKuldeep Singh | FSPI_INSTR_PAD1(FSPI_LUT_PAD1) 98*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE1(FSPI_LUT_READ); 99*b525a8f0SKuldeep Singh break; 100*b525a8f0SKuldeep Singh case FSPI_WRITE_SEQ_ID: 101*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_PP; 102*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_PP_4B; 103*b525a8f0SKuldeep Singh x_instr2 = FSPI_INSTR_OPRND0(0) | FSPI_INSTR_PAD0(FSPI_LUT_PAD1) 104*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE0(FSPI_LUT_WRITE); 105*b525a8f0SKuldeep Singh break; 106*b525a8f0SKuldeep Singh case FSPI_WREN_SEQ_ID: 107*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_WREN; 108*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_WREN; 109*b525a8f0SKuldeep Singh break; 110*b525a8f0SKuldeep Singh case FSPI_SE_SEQ_ID: 111*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_SE_64K; 112*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_SE_64K_4B; 113*b525a8f0SKuldeep Singh break; 114*b525a8f0SKuldeep Singh case FSPI_4K_SEQ_ID: 115*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_SE_4K; 116*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_SE_4K_4B; 117*b525a8f0SKuldeep Singh break; 118*b525a8f0SKuldeep Singh case FSPI_BE_SEQ_ID: 119*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_BE; 120*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_BE; 121*b525a8f0SKuldeep Singh break; 122*b525a8f0SKuldeep Singh case FSPI_RDSR_SEQ_ID: 123*b525a8f0SKuldeep Singh cmd_id1 = FSPI_NOR_CMD_RDSR; 124*b525a8f0SKuldeep Singh cmd_id2 = FSPI_NOR_CMD_RDSR; 125*b525a8f0SKuldeep Singh break; 126*b525a8f0SKuldeep Singh } 127*b525a8f0SKuldeep Singh 128*b525a8f0SKuldeep Singh x_addr = FSPI_LUTREG_OFFSET + (uint32_t)(0x10 * fspi_op_seq_id); 129*b525a8f0SKuldeep Singh if ((F_FLASH_SIZE_BYTES <= SZ_16M_BYTES) || (ignore_flash_sz)) { 130*b525a8f0SKuldeep Singh x_instr0 = FSPI_INSTR_OPRND0(cmd_id1); 131*b525a8f0SKuldeep Singh x_instr1 = FSPI_INSTR_OPRND1(FSPI_LUT_ADDR24BIT); 132*b525a8f0SKuldeep Singh VERBOSE("CMD_ID = %x offset = 0x%x\n", cmd_id1, x_addr); 133*b525a8f0SKuldeep Singh } else { 134*b525a8f0SKuldeep Singh x_instr0 = FSPI_INSTR_OPRND0(cmd_id2); 135*b525a8f0SKuldeep Singh x_instr1 = FSPI_INSTR_OPRND1(FSPI_LUT_ADDR32BIT); 136*b525a8f0SKuldeep Singh VERBOSE("CMD_ID = %x offset = 0x%x\n", cmd_id2, x_addr); 137*b525a8f0SKuldeep Singh } 138*b525a8f0SKuldeep Singh x_instr0 |= FSPI_INSTR_PAD0(FSPI_LUT_PAD1) 139*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE0(FSPI_LUT_CMD); 140*b525a8f0SKuldeep Singh 141*b525a8f0SKuldeep Singh x_instr1 |= FSPI_INSTR_PAD1(FSPI_LUT_PAD1) 142*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE1(FSPI_LUT_ADDR); 143*b525a8f0SKuldeep Singh 144*b525a8f0SKuldeep Singh if (fspi_op_seq_id == FSPI_RDSR_SEQ_ID) { 145*b525a8f0SKuldeep Singh x_instr0 |= FSPI_INSTR_OPRND1(1) | FSPI_INSTR_PAD1(FSPI_LUT_PAD1) 146*b525a8f0SKuldeep Singh | FSPI_INSTR_OPCODE1(FSPI_LUT_READ); 147*b525a8f0SKuldeep Singh } else if ((fspi_op_seq_id != FSPI_BE_SEQ_ID) 148*b525a8f0SKuldeep Singh && (fspi_op_seq_id != FSPI_WREN_SEQ_ID)) { 149*b525a8f0SKuldeep Singh x_instr0 |= x_instr1; 150*b525a8f0SKuldeep Singh } 151*b525a8f0SKuldeep Singh 152*b525a8f0SKuldeep Singh fspi_writel((x_addr), x_instr0); 153*b525a8f0SKuldeep Singh fspi_writel((x_addr + U(0x4)), x_instr2); 154*b525a8f0SKuldeep Singh fspi_writel((x_addr + U(0x8)), (uint32_t) 0x0); /* STOP command */ 155*b525a8f0SKuldeep Singh fspi_writel((x_addr + U(0xc)), (uint32_t) 0x0); /* STOP command */ 156*b525a8f0SKuldeep Singh } 157*b525a8f0SKuldeep Singh 158*b525a8f0SKuldeep Singh static void fspi_setup_LUT(void) 159*b525a8f0SKuldeep Singh { 160*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 161*b525a8f0SKuldeep Singh fspi_unlock_LUT(); 162*b525a8f0SKuldeep Singh 163*b525a8f0SKuldeep Singh /* LUT Setup for READ Command 3-Byte low Frequency */ 164*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_READ_SEQ_ID, false); 165*b525a8f0SKuldeep Singh 166*b525a8f0SKuldeep Singh /* LUT Setup for FAST READ Command 3-Byte/4-Byte high Frequency */ 167*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_FASTREAD_SEQ_ID, false); 168*b525a8f0SKuldeep Singh 169*b525a8f0SKuldeep Singh /* LUT Setup for Page Program */ 170*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_WRITE_SEQ_ID, false); 171*b525a8f0SKuldeep Singh 172*b525a8f0SKuldeep Singh /* LUT Setup for WREN */ 173*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_WREN_SEQ_ID, true); 174*b525a8f0SKuldeep Singh 175*b525a8f0SKuldeep Singh /* LUT Setup for Sector_Erase */ 176*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_SE_SEQ_ID, false); 177*b525a8f0SKuldeep Singh 178*b525a8f0SKuldeep Singh /* LUT Setup for Sub Sector 4K Erase */ 179*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_4K_SEQ_ID, false); 180*b525a8f0SKuldeep Singh 181*b525a8f0SKuldeep Singh /* LUT Setup for Bulk_Erase */ 182*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_BE_SEQ_ID, true); 183*b525a8f0SKuldeep Singh 184*b525a8f0SKuldeep Singh /* Read Status */ 185*b525a8f0SKuldeep Singh fspi_op_setup(FSPI_RDSR_SEQ_ID, true); 186*b525a8f0SKuldeep Singh 187*b525a8f0SKuldeep Singh fspi_lock_LUT(); 188*b525a8f0SKuldeep Singh } 189*b525a8f0SKuldeep Singh 190*b525a8f0SKuldeep Singh static inline void fspi_ahb_invalidate(void) 191*b525a8f0SKuldeep Singh { 192*b525a8f0SKuldeep Singh uint32_t reg; 193*b525a8f0SKuldeep Singh 194*b525a8f0SKuldeep Singh VERBOSE("In func %s %d\n", __func__, __LINE__); 195*b525a8f0SKuldeep Singh reg = fspi_readl(FSPI_MCR0); 196*b525a8f0SKuldeep Singh reg |= FSPI_MCR0_SWRST; 197*b525a8f0SKuldeep Singh fspi_writel(FSPI_MCR0, reg); 198*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_MCR0) & FSPI_MCR0_SWRST) != 0) 199*b525a8f0SKuldeep Singh ; /* FSPI_MCR0_SWRESET_MASK */ 200*b525a8f0SKuldeep Singh VERBOSE("In func %s %d\n", __func__, __LINE__); 201*b525a8f0SKuldeep Singh } 202*b525a8f0SKuldeep Singh 203*b525a8f0SKuldeep Singh #if defined(CONFIG_FSPI_AHB) 204*b525a8f0SKuldeep Singh static void fspi_init_ahb(void) 205*b525a8f0SKuldeep Singh { 206*b525a8f0SKuldeep Singh uint32_t i, x_flash_cr2, seq_id; 207*b525a8f0SKuldeep Singh 208*b525a8f0SKuldeep Singh x_flash_cr2 = 0; 209*b525a8f0SKuldeep Singh /* Reset AHB RX buffer CR configuration */ 210*b525a8f0SKuldeep Singh for (i = 0; i < 8; i++) { 211*b525a8f0SKuldeep Singh fspi_writel((FSPI_AHBRX_BUF0CR0 + 4 * i), 0U); 212*b525a8f0SKuldeep Singh } 213*b525a8f0SKuldeep Singh 214*b525a8f0SKuldeep Singh /* Set ADATSZ with the maximum AHB buffer size */ 215*b525a8f0SKuldeep Singh fspi_writel(FSPI_AHBRX_BUF7CR0, 216*b525a8f0SKuldeep Singh ((uint32_t) ((FSPI_RX_MAX_AHBBUF_SIZE / 8U) | 217*b525a8f0SKuldeep Singh FSPI_AHBRXBUF0CR7_PREF))); 218*b525a8f0SKuldeep Singh 219*b525a8f0SKuldeep Singh /* Known limitation handling: prefetch and 220*b525a8f0SKuldeep Singh * no start address alignment.*/ 221*b525a8f0SKuldeep Singh fspi_writel(FSPI_AHBCR, FSPI_AHBCR_PREF_EN); 222*b525a8f0SKuldeep Singh INFO("xAhbcr=0x%x\n", fspi_readl(FSPI_AHBCR)); 223*b525a8f0SKuldeep Singh 224*b525a8f0SKuldeep Singh // Setup AHB READ sequenceID for all flashes. 225*b525a8f0SKuldeep Singh x_flash_cr2 = fspi_readl(FSPI_FLSHA1CR2); 226*b525a8f0SKuldeep Singh INFO("x_flash_cr2=0x%x\n", x_flash_cr2); 227*b525a8f0SKuldeep Singh 228*b525a8f0SKuldeep Singh seq_id = CONFIG_FSPI_FASTREAD ? 229*b525a8f0SKuldeep Singh FSPI_FASTREAD_SEQ_ID : FSPI_READ_SEQ_ID; 230*b525a8f0SKuldeep Singh x_flash_cr2 |= ((seq_id << FSPI_FLSHXCR2_ARDSEQI_SHIFT) & 0x1f); 231*b525a8f0SKuldeep Singh 232*b525a8f0SKuldeep Singh INFO("x_flash_cr2=0x%x\n", x_flash_cr2); 233*b525a8f0SKuldeep Singh 234*b525a8f0SKuldeep Singh fspi_writel(FSPI_FLSHA1CR2, x_flash_cr2); 235*b525a8f0SKuldeep Singh x_flash_cr2 = fspi_readl(FSPI_FLSHA1CR2); 236*b525a8f0SKuldeep Singh INFO("x_flash_cr2=0x%x\n", x_flash_cr2); 237*b525a8f0SKuldeep Singh } 238*b525a8f0SKuldeep Singh #endif 239*b525a8f0SKuldeep Singh 240*b525a8f0SKuldeep Singh int xspi_read(uint32_t pc_rx_addr, uint32_t *pc_rx_buf, uint32_t x_size_bytes) 241*b525a8f0SKuldeep Singh { 242*b525a8f0SKuldeep Singh if (x_size_bytes == 0) { 243*b525a8f0SKuldeep Singh ERROR("Zero length reads are not allowed\n"); 244*b525a8f0SKuldeep Singh return XSPI_READ_FAIL; 245*b525a8f0SKuldeep Singh } 246*b525a8f0SKuldeep Singh 247*b525a8f0SKuldeep Singh #if defined(CONFIG_FSPI_AHB) 248*b525a8f0SKuldeep Singh return xspi_ahb_read(pc_rx_addr, pc_rx_buf, x_size_bytes); 249*b525a8f0SKuldeep Singh #else 250*b525a8f0SKuldeep Singh return xspi_ip_read(pc_rx_addr, pc_rx_buf, x_size_bytes); 251*b525a8f0SKuldeep Singh #endif 252*b525a8f0SKuldeep Singh } 253*b525a8f0SKuldeep Singh #if defined(CONFIG_FSPI_AHB) 254*b525a8f0SKuldeep Singh int xspi_ahb_read(uint32_t pc_rx_addr, uint32_t *pc_rx_buf, uint32_t x_size_bytes) 255*b525a8f0SKuldeep Singh { 256*b525a8f0SKuldeep Singh VERBOSE("In func %s 0x%x\n", __func__, (pc_rx_addr)); 257*b525a8f0SKuldeep Singh 258*b525a8f0SKuldeep Singh if (F_FLASH_SIZE_BYTES <= SZ_16M_BYTES) { 259*b525a8f0SKuldeep Singh pc_rx_addr = ((uint32_t)(pcRxAddr & MASK_24BIT_ADDRESS)); 260*b525a8f0SKuldeep Singh } else { 261*b525a8f0SKuldeep Singh pc_rx_addr = ((uint32_t)(pcRxAddr & MASK_32BIT_ADDRESS)); 262*b525a8f0SKuldeep Singh } 263*b525a8f0SKuldeep Singh 264*b525a8f0SKuldeep Singh pc_rx_addr = ((uint32_t)(pcRxAddr + fspi_flash_base_addr)); 265*b525a8f0SKuldeep Singh 266*b525a8f0SKuldeep Singh if (((pc_rx_addr % 4) != 0) || (((uintptr_t)pc_rx_buf % 4) != 0)) { 267*b525a8f0SKuldeep Singh WARN("%s: unaligned Start Address src=%ld dst=0x%p\n", 268*b525a8f0SKuldeep Singh __func__, (pc_rx_addr - fspi_flash_base_addr), pc_rx_buf); 269*b525a8f0SKuldeep Singh } 270*b525a8f0SKuldeep Singh 271*b525a8f0SKuldeep Singh /* Directly copy from AHB Buffer */ 272*b525a8f0SKuldeep Singh memcpy(pc_rx_buf, (void *)(uintptr_t)pc_rx_addr, x_size_bytes); 273*b525a8f0SKuldeep Singh 274*b525a8f0SKuldeep Singh fspi_ahb_invalidate(); 275*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 276*b525a8f0SKuldeep Singh } 277*b525a8f0SKuldeep Singh #endif 278*b525a8f0SKuldeep Singh 279*b525a8f0SKuldeep Singh int xspi_ip_read(uint32_t pc_rx_addr, uint32_t *pv_rx_buf, uint32_t ui_len) 280*b525a8f0SKuldeep Singh { 281*b525a8f0SKuldeep Singh 282*b525a8f0SKuldeep Singh uint32_t i = 0U, j = 0U, x_rem = 0U; 283*b525a8f0SKuldeep Singh uint32_t x_iteration = 0U, x_size_rx = 0U, x_size_wm, temp_size; 284*b525a8f0SKuldeep Singh uint32_t data = 0U; 285*b525a8f0SKuldeep Singh uint32_t x_len_bytes; 286*b525a8f0SKuldeep Singh uint32_t x_addr, sts0, intr, seq_id; 287*b525a8f0SKuldeep Singh 288*b525a8f0SKuldeep Singh x_addr = (uint32_t) pc_rx_addr; 289*b525a8f0SKuldeep Singh x_len_bytes = ui_len; 290*b525a8f0SKuldeep Singh 291*b525a8f0SKuldeep Singh /* Watermark level : 8 bytes. (BY DEFAULT) */ 292*b525a8f0SKuldeep Singh x_size_wm = 8U; 293*b525a8f0SKuldeep Singh 294*b525a8f0SKuldeep Singh /* Clear RX Watermark interrupt in INT register, if any existing. */ 295*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA); 296*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_INTR)); 297*b525a8f0SKuldeep Singh /* Invalid the RXFIFO, to run next IP Command */ 298*b525a8f0SKuldeep Singh /* Clears data entries in IP Rx FIFOs, Also reset R/W pointers */ 299*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR); 300*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTEN_IPCMDDONE); 301*b525a8f0SKuldeep Singh 302*b525a8f0SKuldeep Singh while (x_len_bytes) { 303*b525a8f0SKuldeep Singh 304*b525a8f0SKuldeep Singh /* FlexSPI can store no more than FSPI_RX_IPBUF_SIZE */ 305*b525a8f0SKuldeep Singh x_size_rx = (x_len_bytes > FSPI_RX_IPBUF_SIZE) ? 306*b525a8f0SKuldeep Singh FSPI_RX_IPBUF_SIZE : x_len_bytes; 307*b525a8f0SKuldeep Singh 308*b525a8f0SKuldeep Singh /* IP Control Register0 - SF Address to be read */ 309*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, x_addr); 310*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_IPCR0)); 311*b525a8f0SKuldeep Singh /* IP Control Register1 - SEQID_READ operation, Size */ 312*b525a8f0SKuldeep Singh 313*b525a8f0SKuldeep Singh seq_id = CONFIG_FSPI_FASTREAD ? 314*b525a8f0SKuldeep Singh FSPI_FASTREAD_SEQ_ID : FSPI_READ_SEQ_ID; 315*b525a8f0SKuldeep Singh 316*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, 317*b525a8f0SKuldeep Singh (uint32_t)(seq_id << FSPI_IPCR1_ISEQID_SHIFT) | 318*b525a8f0SKuldeep Singh (uint16_t) x_size_rx); 319*b525a8f0SKuldeep Singh 320*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_IPCR1)); 321*b525a8f0SKuldeep Singh 322*b525a8f0SKuldeep Singh do { 323*b525a8f0SKuldeep Singh sts0 = fspi_readl(FSPI_STS0); 324*b525a8f0SKuldeep Singh } while (((sts0 & FSPI_STS0_ARB_IDLE) == 0) && 325*b525a8f0SKuldeep Singh ((sts0 & FSPI_STS0_SEQ_IDLE) == 0)); 326*b525a8f0SKuldeep Singh 327*b525a8f0SKuldeep Singh /* Trigger IP Read Command */ 328*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 329*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_IPCMD)); 330*b525a8f0SKuldeep Singh 331*b525a8f0SKuldeep Singh intr = fspi_readl(FSPI_INTR); 332*b525a8f0SKuldeep Singh if (((intr & FSPI_INTR_IPCMDGE) != 0) || 333*b525a8f0SKuldeep Singh ((intr & FSPI_INTR_IPCMDERR) != 0)) { 334*b525a8f0SKuldeep Singh ERROR("Error in IP READ INTR=0x%x\n", intr); 335*b525a8f0SKuldeep Singh return -XSPI_IP_READ_FAIL; 336*b525a8f0SKuldeep Singh } 337*b525a8f0SKuldeep Singh /* Will read in n iterations of each 8 FIFO's(WM level) */ 338*b525a8f0SKuldeep Singh x_iteration = x_size_rx / x_size_wm; 339*b525a8f0SKuldeep Singh for (i = 0U; i < x_iteration; i++) { 340*b525a8f0SKuldeep Singh if ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPRXWA_MASK) == 0) { 341*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_INTR)); 342*b525a8f0SKuldeep Singh } 343*b525a8f0SKuldeep Singh /* Wait for IP Rx Watermark Fill event */ 344*b525a8f0SKuldeep Singh while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPRXWA_MASK)) { 345*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_INTR)); 346*b525a8f0SKuldeep Singh } 347*b525a8f0SKuldeep Singh 348*b525a8f0SKuldeep Singh /* Read RX FIFO's(upto WM level) & copy to rxbuffer */ 349*b525a8f0SKuldeep Singh for (j = 0U; j < x_size_wm; j += 4U) { 350*b525a8f0SKuldeep Singh /* Read FIFO Data Register */ 351*b525a8f0SKuldeep Singh data = fspi_readl(FSPI_RFDR + j); 352*b525a8f0SKuldeep Singh #if FSPI_IPDATA_SWAP /* Just In case you want swap */ 353*b525a8f0SKuldeep Singh data = bswap32(data); 354*b525a8f0SKuldeep Singh #endif 355*b525a8f0SKuldeep Singh memcpy(pv_rx_buf++, &data, 4); 356*b525a8f0SKuldeep Singh } 357*b525a8f0SKuldeep Singh 358*b525a8f0SKuldeep Singh /* Clear IP_RX_WATERMARK Event in INTR register */ 359*b525a8f0SKuldeep Singh /* Reset FIFO Read pointer for next iteration.*/ 360*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA); 361*b525a8f0SKuldeep Singh } 362*b525a8f0SKuldeep Singh 363*b525a8f0SKuldeep Singh x_rem = x_size_rx % x_size_wm; 364*b525a8f0SKuldeep Singh 365*b525a8f0SKuldeep Singh if (x_rem != 0U) { 366*b525a8f0SKuldeep Singh /* Wait for data filled */ 367*b525a8f0SKuldeep Singh while (!(fspi_readl(FSPI_IPRXFSTS) & FSPI_IPRXFSTS_FILL_MASK)) { 368*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_IPRXFSTS)); 369*b525a8f0SKuldeep Singh } 370*b525a8f0SKuldeep Singh 371*b525a8f0SKuldeep Singh temp_size = 0; 372*b525a8f0SKuldeep Singh j = 0U; 373*b525a8f0SKuldeep Singh while (x_rem > 0U) { 374*b525a8f0SKuldeep Singh data = 0U; 375*b525a8f0SKuldeep Singh data = fspi_readl(FSPI_RFDR + j); 376*b525a8f0SKuldeep Singh #if FSPI_IPDATA_SWAP /* Just In case you want swap */ 377*b525a8f0SKuldeep Singh data = bswap32(data); 378*b525a8f0SKuldeep Singh #endif 379*b525a8f0SKuldeep Singh temp_size = (x_rem < 4) ? x_rem : 4; 380*b525a8f0SKuldeep Singh memcpy(pv_rx_buf++, &data, temp_size); 381*b525a8f0SKuldeep Singh x_rem -= temp_size; 382*b525a8f0SKuldeep Singh } 383*b525a8f0SKuldeep Singh } 384*b525a8f0SKuldeep Singh 385*b525a8f0SKuldeep Singh 386*b525a8f0SKuldeep Singh while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK)) { 387*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_INTR)); 388*b525a8f0SKuldeep Singh } 389*b525a8f0SKuldeep Singh 390*b525a8f0SKuldeep Singh /* Invalid the RX FIFO, to run next IP Command */ 391*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR); 392*b525a8f0SKuldeep Singh /* Clear IP Command Done flag in interrupt register*/ 393*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 394*b525a8f0SKuldeep Singh 395*b525a8f0SKuldeep Singh /* Update remaining len, Increment x_addr read pointer. */ 396*b525a8f0SKuldeep Singh x_len_bytes -= x_size_rx; 397*b525a8f0SKuldeep Singh x_addr += x_size_rx; 398*b525a8f0SKuldeep Singh } 399*b525a8f0SKuldeep Singh PR; 400*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 401*b525a8f0SKuldeep Singh } 402*b525a8f0SKuldeep Singh 403*b525a8f0SKuldeep Singh void xspi_ip_write(uint32_t pc_wr_addr, uint32_t *pv_wr_buf, uint32_t ui_len) 404*b525a8f0SKuldeep Singh { 405*b525a8f0SKuldeep Singh 406*b525a8f0SKuldeep Singh uint32_t x_iteration = 0U, x_rem = 0U; 407*b525a8f0SKuldeep Singh uint32_t x_size_tx = 0U, x_size_wm, temp_size; 408*b525a8f0SKuldeep Singh uint32_t i = 0U, j = 0U; 409*b525a8f0SKuldeep Singh uint32_t ui_data = 0U; 410*b525a8f0SKuldeep Singh uint32_t x_addr, x_len_bytes; 411*b525a8f0SKuldeep Singh 412*b525a8f0SKuldeep Singh 413*b525a8f0SKuldeep Singh x_size_wm = 8U; /* Default TX WaterMark level: 8 Bytes. */ 414*b525a8f0SKuldeep Singh x_addr = (uint32_t)pc_wr_addr; 415*b525a8f0SKuldeep Singh x_len_bytes = ui_len; 416*b525a8f0SKuldeep Singh VERBOSE("In func %s[%d] x_addr =0x%x xLen_bytes=%d\n", 417*b525a8f0SKuldeep Singh __func__, __LINE__, x_addr, x_len_bytes); 418*b525a8f0SKuldeep Singh 419*b525a8f0SKuldeep Singh while (x_len_bytes != 0U) { 420*b525a8f0SKuldeep Singh 421*b525a8f0SKuldeep Singh x_size_tx = (x_len_bytes > FSPI_TX_IPBUF_SIZE) ? 422*b525a8f0SKuldeep Singh FSPI_TX_IPBUF_SIZE : x_len_bytes; 423*b525a8f0SKuldeep Singh 424*b525a8f0SKuldeep Singh /* IP Control Register0 - SF Address to be read */ 425*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, x_addr); 426*b525a8f0SKuldeep Singh INFO("In func %s[%d] x_addr =0x%x xLen_bytes=%d\n", 427*b525a8f0SKuldeep Singh __func__, __LINE__, x_addr, x_len_bytes); 428*b525a8f0SKuldeep Singh 429*b525a8f0SKuldeep Singh /* 430*b525a8f0SKuldeep Singh * Fill TX FIFO's.. 431*b525a8f0SKuldeep Singh * 432*b525a8f0SKuldeep Singh */ 433*b525a8f0SKuldeep Singh 434*b525a8f0SKuldeep Singh x_iteration = x_size_tx / x_size_wm; 435*b525a8f0SKuldeep Singh for (i = 0U; i < x_iteration; i++) { 436*b525a8f0SKuldeep Singh 437*b525a8f0SKuldeep Singh /* Ensure TX FIFO Watermark Available */ 438*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPTXWE_MASK) == 0) 439*b525a8f0SKuldeep Singh ; 440*b525a8f0SKuldeep Singh 441*b525a8f0SKuldeep Singh 442*b525a8f0SKuldeep Singh /* Fill TxFIFO's ( upto watermark level) */ 443*b525a8f0SKuldeep Singh for (j = 0U; j < x_size_wm; j += 4U) { 444*b525a8f0SKuldeep Singh memcpy(&ui_data, pv_wr_buf++, 4); 445*b525a8f0SKuldeep Singh /* Write TX FIFO Data Register */ 446*b525a8f0SKuldeep Singh fspi_writel((FSPI_TFDR + j), ui_data); 447*b525a8f0SKuldeep Singh 448*b525a8f0SKuldeep Singh } 449*b525a8f0SKuldeep Singh 450*b525a8f0SKuldeep Singh /* Clear IP_TX_WATERMARK Event in INTR register */ 451*b525a8f0SKuldeep Singh /* Reset the FIFO Write pointer for next iteration */ 452*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPTXWE); 453*b525a8f0SKuldeep Singh } 454*b525a8f0SKuldeep Singh 455*b525a8f0SKuldeep Singh x_rem = x_size_tx % x_size_wm; 456*b525a8f0SKuldeep Singh 457*b525a8f0SKuldeep Singh if (x_rem != 0U) { 458*b525a8f0SKuldeep Singh /* Wait for TXFIFO empty */ 459*b525a8f0SKuldeep Singh while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPTXWE)) 460*b525a8f0SKuldeep Singh ; 461*b525a8f0SKuldeep Singh 462*b525a8f0SKuldeep Singh temp_size = 0U; 463*b525a8f0SKuldeep Singh j = 0U; 464*b525a8f0SKuldeep Singh while (x_rem > 0U) { 465*b525a8f0SKuldeep Singh ui_data = 0U; 466*b525a8f0SKuldeep Singh temp_size = (x_rem < 4U) ? x_rem : 4U; 467*b525a8f0SKuldeep Singh memcpy(&ui_data, pv_wr_buf++, temp_size); 468*b525a8f0SKuldeep Singh INFO("%d ---> pv_wr_buf=0x%p\n", __LINE__, pv_wr_buf); 469*b525a8f0SKuldeep Singh fspi_writel((FSPI_TFDR + j), ui_data); 470*b525a8f0SKuldeep Singh x_rem -= temp_size; 471*b525a8f0SKuldeep Singh j += 4U ; /* TODO: May not be needed*/ 472*b525a8f0SKuldeep Singh } 473*b525a8f0SKuldeep Singh /* Clear IP_TX_WATERMARK Event in INTR register */ 474*b525a8f0SKuldeep Singh /* Reset FIFO's Write pointer for next iteration.*/ 475*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPTXWE); 476*b525a8f0SKuldeep Singh } 477*b525a8f0SKuldeep Singh 478*b525a8f0SKuldeep Singh /* IP Control Register1 - SEQID_WRITE operation, Size */ 479*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, (uint32_t)(FSPI_WRITE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | (uint16_t) x_size_tx); 480*b525a8f0SKuldeep Singh /* Trigger IP Write Command */ 481*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 482*b525a8f0SKuldeep Singh 483*b525a8f0SKuldeep Singh /* Wait for IP Write command done */ 484*b525a8f0SKuldeep Singh while (!(fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK)) 485*b525a8f0SKuldeep Singh ; 486*b525a8f0SKuldeep Singh 487*b525a8f0SKuldeep Singh /* Invalidate TX FIFOs & acknowledge IP_CMD_DONE event */ 488*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPTXFCR, FSPI_IPTXFCR_CLR); 489*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 490*b525a8f0SKuldeep Singh 491*b525a8f0SKuldeep Singh /* for next iteration */ 492*b525a8f0SKuldeep Singh x_len_bytes -= x_size_tx; 493*b525a8f0SKuldeep Singh x_addr += x_size_tx; 494*b525a8f0SKuldeep Singh } 495*b525a8f0SKuldeep Singh 496*b525a8f0SKuldeep Singh } 497*b525a8f0SKuldeep Singh 498*b525a8f0SKuldeep Singh int xspi_write(uint32_t pc_wr_addr, void *pv_wr_buf, uint32_t ui_len) 499*b525a8f0SKuldeep Singh { 500*b525a8f0SKuldeep Singh 501*b525a8f0SKuldeep Singh uint32_t x_addr; 502*b525a8f0SKuldeep Singh uint32_t x_page1_len = 0U, x_page_l_len = 0U; 503*b525a8f0SKuldeep Singh uint32_t i, j = 0U; 504*b525a8f0SKuldeep Singh void *buf = pv_wr_buf; 505*b525a8f0SKuldeep Singh 506*b525a8f0SKuldeep Singh VERBOSE("\nIn func %s\n", __func__); 507*b525a8f0SKuldeep Singh 508*b525a8f0SKuldeep Singh x_addr = (uint32_t)(pc_wr_addr); 509*b525a8f0SKuldeep Singh if ((ui_len <= F_PAGE_256) && ((x_addr % F_PAGE_256) == 0)) { 510*b525a8f0SKuldeep Singh x_page1_len = ui_len; 511*b525a8f0SKuldeep Singh INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j); 512*b525a8f0SKuldeep Singh } else if ((ui_len <= F_PAGE_256) && ((x_addr % F_PAGE_256) != 0)) { 513*b525a8f0SKuldeep Singh x_page1_len = (F_PAGE_256 - (x_addr % F_PAGE_256)); 514*b525a8f0SKuldeep Singh if (ui_len > x_page1_len) { 515*b525a8f0SKuldeep Singh x_page_l_len = (ui_len - x_page1_len) % F_PAGE_256; 516*b525a8f0SKuldeep Singh } else { 517*b525a8f0SKuldeep Singh x_page1_len = ui_len; 518*b525a8f0SKuldeep Singh x_page_l_len = 0; 519*b525a8f0SKuldeep Singh } 520*b525a8f0SKuldeep Singh j = 0U; 521*b525a8f0SKuldeep Singh INFO("%d 0x%x 0x%x\n", x_addr % F_PAGE_256, x_addr % F_PAGE_256, F_PAGE_256); 522*b525a8f0SKuldeep Singh INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j); 523*b525a8f0SKuldeep Singh } else if ((ui_len > F_PAGE_256) && ((x_addr % F_PAGE_256) == 0)) { 524*b525a8f0SKuldeep Singh j = ui_len / F_PAGE_256; 525*b525a8f0SKuldeep Singh x_page_l_len = ui_len % F_PAGE_256; 526*b525a8f0SKuldeep Singh INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j); 527*b525a8f0SKuldeep Singh } else if ((ui_len > F_PAGE_256) && ((x_addr % F_PAGE_256) != 0)) { 528*b525a8f0SKuldeep Singh x_page1_len = (F_PAGE_256 - (x_addr % F_PAGE_256)); 529*b525a8f0SKuldeep Singh j = (ui_len - x_page1_len) / F_PAGE_256; 530*b525a8f0SKuldeep Singh x_page_l_len = (ui_len - x_page1_len) % F_PAGE_256; 531*b525a8f0SKuldeep Singh INFO("%d ---> x_page1_len=0x%x x_page_l_len =0x%x j=0x%x\n", __LINE__, x_page1_len, x_page_l_len, j); 532*b525a8f0SKuldeep Singh } 533*b525a8f0SKuldeep Singh 534*b525a8f0SKuldeep Singh if (x_page1_len != 0U) { 535*b525a8f0SKuldeep Singh xspi_wren(x_addr); 536*b525a8f0SKuldeep Singh xspi_ip_write(x_addr, (uint32_t *)buf, x_page1_len); 537*b525a8f0SKuldeep Singh while (is_flash_busy()) 538*b525a8f0SKuldeep Singh ; 539*b525a8f0SKuldeep Singh INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n", 540*b525a8f0SKuldeep Singh __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr)); 541*b525a8f0SKuldeep Singh INFO("Initial Buf pv_wr_buf=%p, final Buf=%p\n", pv_wr_buf, buf); 542*b525a8f0SKuldeep Singh x_addr += x_page1_len; 543*b525a8f0SKuldeep Singh /* TODO What is buf start is not 4 aligned */ 544*b525a8f0SKuldeep Singh buf = buf + x_page1_len; 545*b525a8f0SKuldeep Singh } 546*b525a8f0SKuldeep Singh 547*b525a8f0SKuldeep Singh for (i = 0U; i < j; i++) { 548*b525a8f0SKuldeep Singh INFO("In for loop Buf pv_wr_buf=%p, final Buf=%p x_addr=0x%x offset_buf %d.\n", 549*b525a8f0SKuldeep Singh pv_wr_buf, buf, x_addr, x_page1_len/4); 550*b525a8f0SKuldeep Singh xspi_wren(x_addr); 551*b525a8f0SKuldeep Singh xspi_ip_write(x_addr, (uint32_t *)buf, F_PAGE_256); 552*b525a8f0SKuldeep Singh while (is_flash_busy()) 553*b525a8f0SKuldeep Singh ; 554*b525a8f0SKuldeep Singh INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n", 555*b525a8f0SKuldeep Singh __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr)); 556*b525a8f0SKuldeep Singh x_addr += F_PAGE_256; 557*b525a8f0SKuldeep Singh /* TODO What is buf start is not 4 aligned */ 558*b525a8f0SKuldeep Singh buf = buf + F_PAGE_256; 559*b525a8f0SKuldeep Singh INFO("Initial Buf pv_wr_buf=%p, final Buf=%p\n", pv_wr_buf, buf); 560*b525a8f0SKuldeep Singh } 561*b525a8f0SKuldeep Singh 562*b525a8f0SKuldeep Singh if (x_page_l_len != 0U) { 563*b525a8f0SKuldeep Singh INFO("%d Initial Buf pv_wr_buf=%p, final Buf=%p x_page_l_len=0x%x\n", __LINE__, pv_wr_buf, buf, x_page_l_len); 564*b525a8f0SKuldeep Singh xspi_wren(x_addr); 565*b525a8f0SKuldeep Singh xspi_ip_write(x_addr, (uint32_t *)buf, x_page_l_len); 566*b525a8f0SKuldeep Singh while (is_flash_busy()) 567*b525a8f0SKuldeep Singh ; 568*b525a8f0SKuldeep Singh INFO("%d Initial pc_wr_addr=0x%x, Final x_addr=0x%x, Initial ui_len=0x%x Final ui_len=0x%x\n", 569*b525a8f0SKuldeep Singh __LINE__, pc_wr_addr, x_addr, ui_len, (x_addr-pc_wr_addr)); 570*b525a8f0SKuldeep Singh } 571*b525a8f0SKuldeep Singh 572*b525a8f0SKuldeep Singh VERBOSE("Now calling func call Invalidate%s\n", __func__); 573*b525a8f0SKuldeep Singh fspi_ahb_invalidate(); 574*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 575*b525a8f0SKuldeep Singh } 576*b525a8f0SKuldeep Singh 577*b525a8f0SKuldeep Singh int xspi_wren(uint32_t pc_wr_addr) 578*b525a8f0SKuldeep Singh { 579*b525a8f0SKuldeep Singh VERBOSE("In func %s Addr=0x%x\n", __func__, pc_wr_addr); 580*b525a8f0SKuldeep Singh 581*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPTXFCR, FSPI_IPTXFCR_CLR); 582*b525a8f0SKuldeep Singh 583*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, (uint32_t)pc_wr_addr); 584*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, ((FSPI_WREN_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0)); 585*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 586*b525a8f0SKuldeep Singh 587*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0) 588*b525a8f0SKuldeep Singh ; 589*b525a8f0SKuldeep Singh 590*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 591*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 592*b525a8f0SKuldeep Singh } 593*b525a8f0SKuldeep Singh 594*b525a8f0SKuldeep Singh static void fspi_bbluk_er(void) 595*b525a8f0SKuldeep Singh { 596*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 597*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, 0x0); 598*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, ((FSPI_BE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 20)); 599*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 600*b525a8f0SKuldeep Singh 601*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0) 602*b525a8f0SKuldeep Singh ; 603*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 604*b525a8f0SKuldeep Singh 605*b525a8f0SKuldeep Singh } 606*b525a8f0SKuldeep Singh 607*b525a8f0SKuldeep Singh static void fspi_RDSR(uint32_t *rxbuf, const void *p_addr, uint32_t size) 608*b525a8f0SKuldeep Singh { 609*b525a8f0SKuldeep Singh uint32_t iprxfcr = 0U; 610*b525a8f0SKuldeep Singh uint32_t data = 0U; 611*b525a8f0SKuldeep Singh 612*b525a8f0SKuldeep Singh iprxfcr = fspi_readl(FSPI_IPRXFCR); 613*b525a8f0SKuldeep Singh /* IP RX FIFO would be read by processor */ 614*b525a8f0SKuldeep Singh iprxfcr = iprxfcr & (uint32_t)~FSPI_IPRXFCR_CLR; 615*b525a8f0SKuldeep Singh /* Invalid data entries in IP RX FIFO */ 616*b525a8f0SKuldeep Singh iprxfcr = iprxfcr | FSPI_IPRXFCR_CLR; 617*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPRXFCR, iprxfcr); 618*b525a8f0SKuldeep Singh 619*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, (uintptr_t) p_addr); 620*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, 621*b525a8f0SKuldeep Singh (uint32_t) ((FSPI_RDSR_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) 622*b525a8f0SKuldeep Singh | (uint16_t) size)); 623*b525a8f0SKuldeep Singh /* Trigger the command */ 624*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 625*b525a8f0SKuldeep Singh /* Wait for command done */ 626*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0) 627*b525a8f0SKuldeep Singh ; 628*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 629*b525a8f0SKuldeep Singh 630*b525a8f0SKuldeep Singh data = fspi_readl(FSPI_RFDR); 631*b525a8f0SKuldeep Singh memcpy(rxbuf, &data, size); 632*b525a8f0SKuldeep Singh 633*b525a8f0SKuldeep Singh /* Rx FIFO invalidation needs to be done prior w1c of INTR.IPRXWA bit */ 634*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPRXFCR, FSPI_IPRXFCR_CLR); 635*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPRXWA_MASK); 636*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 637*b525a8f0SKuldeep Singh 638*b525a8f0SKuldeep Singh } 639*b525a8f0SKuldeep Singh 640*b525a8f0SKuldeep Singh bool is_flash_busy(void) 641*b525a8f0SKuldeep Singh { 642*b525a8f0SKuldeep Singh #define FSPI_ONE_BYTE 1 643*b525a8f0SKuldeep Singh uint8_t data[4]; 644*b525a8f0SKuldeep Singh 645*b525a8f0SKuldeep Singh VERBOSE("In func %s\n\n", __func__); 646*b525a8f0SKuldeep Singh fspi_RDSR((uint32_t *) data, 0, FSPI_ONE_BYTE); 647*b525a8f0SKuldeep Singh 648*b525a8f0SKuldeep Singh return !!((uint32_t) data[0] & FSPI_NOR_SR_WIP_MASK); 649*b525a8f0SKuldeep Singh } 650*b525a8f0SKuldeep Singh 651*b525a8f0SKuldeep Singh int xspi_bulk_erase(void) 652*b525a8f0SKuldeep Singh { 653*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 654*b525a8f0SKuldeep Singh xspi_wren((uint32_t) 0x0); 655*b525a8f0SKuldeep Singh fspi_bbluk_er(); 656*b525a8f0SKuldeep Singh while (is_flash_busy()) 657*b525a8f0SKuldeep Singh ; 658*b525a8f0SKuldeep Singh fspi_ahb_invalidate(); 659*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 660*b525a8f0SKuldeep Singh } 661*b525a8f0SKuldeep Singh 662*b525a8f0SKuldeep Singh static void fspi_sec_er(uint32_t pc_wr_addr) 663*b525a8f0SKuldeep Singh { 664*b525a8f0SKuldeep Singh uint32_t x_addr; 665*b525a8f0SKuldeep Singh 666*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 667*b525a8f0SKuldeep Singh x_addr = (uint32_t)(pc_wr_addr); 668*b525a8f0SKuldeep Singh 669*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR0, x_addr); 670*b525a8f0SKuldeep Singh INFO("In [%s][%d] Erase address 0x%x\n", __func__, __LINE__, (x_addr)); 671*b525a8f0SKuldeep Singh #if CONFIG_FSPI_ERASE_4K 672*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, ((FSPI_4K_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0)); 673*b525a8f0SKuldeep Singh #else 674*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCR1, ((FSPI_SE_SEQ_ID << FSPI_IPCR1_ISEQID_SHIFT) | 0)); 675*b525a8f0SKuldeep Singh #endif 676*b525a8f0SKuldeep Singh fspi_writel(FSPI_IPCMD, FSPI_IPCMD_TRG_MASK); 677*b525a8f0SKuldeep Singh 678*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_INTR) & FSPI_INTR_IPCMDDONE_MASK) == 0) { 679*b525a8f0SKuldeep Singh PRA("0x%x", fspi_readl(FSPI_INTR)); 680*b525a8f0SKuldeep Singh } 681*b525a8f0SKuldeep Singh fspi_writel(FSPI_INTR, FSPI_INTR_IPCMDDONE_MASK); 682*b525a8f0SKuldeep Singh } 683*b525a8f0SKuldeep Singh 684*b525a8f0SKuldeep Singh int xspi_sector_erase(uint32_t pc_wr_addr, uint32_t ui_len) 685*b525a8f0SKuldeep Singh { 686*b525a8f0SKuldeep Singh uint32_t x_addr, x_len_bytes, i, num_sector = 0U; 687*b525a8f0SKuldeep Singh 688*b525a8f0SKuldeep Singh VERBOSE("In func %s\n", __func__); 689*b525a8f0SKuldeep Singh x_addr = (uint32_t)(pc_wr_addr); 690*b525a8f0SKuldeep Singh if ((x_addr % F_SECTOR_ERASE_SZ) != 0) { 691*b525a8f0SKuldeep Singh ERROR("!!! In func %s, unalinged start address can only be in multiples of 0x%x\n", 692*b525a8f0SKuldeep Singh __func__, F_SECTOR_ERASE_SZ); 693*b525a8f0SKuldeep Singh return -XSPI_ERASE_FAIL; 694*b525a8f0SKuldeep Singh } 695*b525a8f0SKuldeep Singh 696*b525a8f0SKuldeep Singh x_len_bytes = ui_len * 1; 697*b525a8f0SKuldeep Singh if (x_len_bytes < F_SECTOR_ERASE_SZ) { 698*b525a8f0SKuldeep Singh ERROR("!!! In func %s, Less than 1 sector can only be in multiples of 0x%x\n", 699*b525a8f0SKuldeep Singh __func__, F_SECTOR_ERASE_SZ); 700*b525a8f0SKuldeep Singh return -XSPI_ERASE_FAIL; 701*b525a8f0SKuldeep Singh } 702*b525a8f0SKuldeep Singh 703*b525a8f0SKuldeep Singh num_sector = x_len_bytes/F_SECTOR_ERASE_SZ; 704*b525a8f0SKuldeep Singh num_sector += x_len_bytes % F_SECTOR_ERASE_SZ ? 1U : 0U; 705*b525a8f0SKuldeep Singh INFO("F_SECTOR_ERASE_SZ: 0x%08x, num_sector: %d\n", F_SECTOR_ERASE_SZ, num_sector); 706*b525a8f0SKuldeep Singh 707*b525a8f0SKuldeep Singh for (i = 0U; i < num_sector ; i++) { 708*b525a8f0SKuldeep Singh xspi_wren(x_addr + (F_SECTOR_ERASE_SZ * i)); 709*b525a8f0SKuldeep Singh fspi_sec_er(x_addr + (F_SECTOR_ERASE_SZ * i)); 710*b525a8f0SKuldeep Singh while (is_flash_busy()) 711*b525a8f0SKuldeep Singh ; 712*b525a8f0SKuldeep Singh } 713*b525a8f0SKuldeep Singh fspi_ahb_invalidate(); 714*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 715*b525a8f0SKuldeep Singh } 716*b525a8f0SKuldeep Singh 717*b525a8f0SKuldeep Singh 718*b525a8f0SKuldeep Singh __attribute__((unused)) static void fspi_delay_ms(uint32_t x) 719*b525a8f0SKuldeep Singh { 720*b525a8f0SKuldeep Singh volatile unsigned long ul_count; 721*b525a8f0SKuldeep Singh 722*b525a8f0SKuldeep Singh for (ul_count = 0U; ul_count < (30U * x); ul_count++) 723*b525a8f0SKuldeep Singh ; 724*b525a8f0SKuldeep Singh 725*b525a8f0SKuldeep Singh } 726*b525a8f0SKuldeep Singh 727*b525a8f0SKuldeep Singh 728*b525a8f0SKuldeep Singh #if defined(DEBUG_FLEXSPI) 729*b525a8f0SKuldeep Singh static void fspi_dump_regs(void) 730*b525a8f0SKuldeep Singh { 731*b525a8f0SKuldeep Singh uint32_t i; 732*b525a8f0SKuldeep Singh 733*b525a8f0SKuldeep Singh VERBOSE("\nRegisters Dump:\n"); 734*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_MCR0(0x%x) = 0x%08x\n", FSPI_MCR0, fspi_readl(FSPI_MCR0)); 735*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_MCR2(0x%x) = 0x%08x\n", FSPI_MCR2, fspi_readl(FSPI_MCR2)); 736*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_DLL_A_CR(0x%x) = 0x%08x\n", FSPI_DLLACR, fspi_readl(FSPI_DLLACR)); 737*b525a8f0SKuldeep Singh VERBOSE("\n"); 738*b525a8f0SKuldeep Singh 739*b525a8f0SKuldeep Singh for (i = 0U; i < 8U; i++) { 740*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_AHBRX_BUF0CR0(0x%x) = 0x%08x\n", FSPI_AHBRX_BUF0CR0 + i * 4, fspi_readl((FSPI_AHBRX_BUF0CR0 + i * 4))); 741*b525a8f0SKuldeep Singh } 742*b525a8f0SKuldeep Singh VERBOSE("\n"); 743*b525a8f0SKuldeep Singh 744*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_AHBRX_BUF7CR0(0x%x) = 0x%08x\n", FSPI_AHBRX_BUF7CR0, fspi_readl(FSPI_AHBRX_BUF7CR0)); 745*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_AHB_CR(0x%x) \t = 0x%08x\n", FSPI_AHBCR, fspi_readl(FSPI_AHBCR)); 746*b525a8f0SKuldeep Singh VERBOSE("\n"); 747*b525a8f0SKuldeep Singh 748*b525a8f0SKuldeep Singh for (i = 0U; i < 4U; i++) { 749*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Register FSPI_FLSH_A1_CR2,(0x%x) = 0x%08x\n", FSPI_FLSHA1CR2 + i * 4, fspi_readl(FSPI_FLSHA1CR2 + i * 4)); 750*b525a8f0SKuldeep Singh } 751*b525a8f0SKuldeep Singh } 752*b525a8f0SKuldeep Singh #endif 753*b525a8f0SKuldeep Singh 754*b525a8f0SKuldeep Singh int fspi_init(uint32_t base_reg_addr, uint32_t flash_start_addr) 755*b525a8f0SKuldeep Singh { 756*b525a8f0SKuldeep Singh uint32_t mcrx; 757*b525a8f0SKuldeep Singh uint32_t flash_size; 758*b525a8f0SKuldeep Singh 759*b525a8f0SKuldeep Singh if (fspi_base_reg_addr != 0U) { 760*b525a8f0SKuldeep Singh INFO("FSPI is already initialized.\n"); 761*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 762*b525a8f0SKuldeep Singh } 763*b525a8f0SKuldeep Singh 764*b525a8f0SKuldeep Singh fspi_base_reg_addr = base_reg_addr; 765*b525a8f0SKuldeep Singh fspi_flash_base_addr = flash_start_addr; 766*b525a8f0SKuldeep Singh 767*b525a8f0SKuldeep Singh INFO("Flexspi driver: Version v1.0\n"); 768*b525a8f0SKuldeep Singh INFO("Flexspi: Default MCR0 = 0x%08x, before reset\n", fspi_readl(FSPI_MCR0)); 769*b525a8f0SKuldeep Singh VERBOSE("Flexspi: Resetting controller...\n"); 770*b525a8f0SKuldeep Singh 771*b525a8f0SKuldeep Singh /* Reset FlexSpi Controller */ 772*b525a8f0SKuldeep Singh fspi_writel(FSPI_MCR0, FSPI_MCR0_SWRST); 773*b525a8f0SKuldeep Singh while ((fspi_readl(FSPI_MCR0) & FSPI_MCR0_SWRST)) 774*b525a8f0SKuldeep Singh ; /* FSPI_MCR0_SWRESET_MASK */ 775*b525a8f0SKuldeep Singh 776*b525a8f0SKuldeep Singh 777*b525a8f0SKuldeep Singh /* Disable Controller Module before programming its registersi, especially MCR0 (Master Control Register0) */ 778*b525a8f0SKuldeep Singh fspi_MDIS(1); 779*b525a8f0SKuldeep Singh /* 780*b525a8f0SKuldeep Singh * Program MCR0 with default values, AHB Timeout(0xff), IP Timeout(0xff). {FSPI_MCR0- 0xFFFF0000} 781*b525a8f0SKuldeep Singh */ 782*b525a8f0SKuldeep Singh 783*b525a8f0SKuldeep Singh /* Timeout wait cycle for AHB command grant */ 784*b525a8f0SKuldeep Singh mcrx = fspi_readl(FSPI_MCR0); 785*b525a8f0SKuldeep Singh mcrx |= (uint32_t)((FSPI_MAX_TIMEOUT_AHBCMD << FSPI_MCR0_AHBGRANTWAIT_SHIFT) & (FSPI_MCR0_AHBGRANTWAIT_MASK)); 786*b525a8f0SKuldeep Singh 787*b525a8f0SKuldeep Singh /* Time out wait cycle for IP command grant*/ 788*b525a8f0SKuldeep Singh mcrx |= (uint32_t) (FSPI_MAX_TIMEOUT_IPCMD << FSPI_MCR0_IPGRANTWAIT_SHIFT) & (FSPI_MCR0_IPGRANTWAIT_MASK); 789*b525a8f0SKuldeep Singh 790*b525a8f0SKuldeep Singh /* TODO why BE64 set BE32*/ 791*b525a8f0SKuldeep Singh mcrx |= (uint32_t) (FSPI_ENDCFG_LE64 << FSPI_MCR0_ENDCFG_SHIFT) & FSPI_MCR0_ENDCFG_MASK; 792*b525a8f0SKuldeep Singh 793*b525a8f0SKuldeep Singh fspi_writel(FSPI_MCR0, mcrx); 794*b525a8f0SKuldeep Singh 795*b525a8f0SKuldeep Singh /* Reset the DLL register to default value */ 796*b525a8f0SKuldeep Singh fspi_writel(FSPI_DLLACR, FSPI_DLLACR_OVRDEN); 797*b525a8f0SKuldeep Singh fspi_writel(FSPI_DLLBCR, FSPI_DLLBCR_OVRDEN); 798*b525a8f0SKuldeep Singh 799*b525a8f0SKuldeep Singh #if ERRATA_FLASH_A050272 /* ERRATA DLL */ 800*b525a8f0SKuldeep Singh for (uint8_t delay = 100U; delay > 0U; delay--) { 801*b525a8f0SKuldeep Singh __asm__ volatile ("nop"); 802*b525a8f0SKuldeep Singh } 803*b525a8f0SKuldeep Singh #endif 804*b525a8f0SKuldeep Singh 805*b525a8f0SKuldeep Singh /* Configure flash control registers for different chip select */ 806*b525a8f0SKuldeep Singh flash_size = (F_FLASH_SIZE_BYTES * FLASH_NUM) / FSPI_BYTES_PER_KBYTES; 807*b525a8f0SKuldeep Singh fspi_writel(FSPI_FLSHA1CR0, flash_size); 808*b525a8f0SKuldeep Singh fspi_writel(FSPI_FLSHA2CR0, 0U); 809*b525a8f0SKuldeep Singh fspi_writel(FSPI_FLSHB1CR0, 0U); 810*b525a8f0SKuldeep Singh fspi_writel(FSPI_FLSHB2CR0, 0U); 811*b525a8f0SKuldeep Singh 812*b525a8f0SKuldeep Singh #if defined(CONFIG_FSPI_AHB) 813*b525a8f0SKuldeep Singh fspi_init_ahb(); 814*b525a8f0SKuldeep Singh #endif 815*b525a8f0SKuldeep Singh /* RE-Enable Controller Module */ 816*b525a8f0SKuldeep Singh fspi_MDIS(0); 817*b525a8f0SKuldeep Singh INFO("Flexspi: After MCR0 = 0x%08x,\n", fspi_readl(FSPI_MCR0)); 818*b525a8f0SKuldeep Singh fspi_setup_LUT(); 819*b525a8f0SKuldeep Singh 820*b525a8f0SKuldeep Singh /* Dump of all registers, ensure controller not disabled anymore*/ 821*b525a8f0SKuldeep Singh #if defined(DEBUG_FLEXSPI) 822*b525a8f0SKuldeep Singh fspi_dump_regs(); 823*b525a8f0SKuldeep Singh #endif 824*b525a8f0SKuldeep Singh 825*b525a8f0SKuldeep Singh INFO("Flexspi: Init done!!\n"); 826*b525a8f0SKuldeep Singh 827*b525a8f0SKuldeep Singh #if DEBUG_FLEXSPI 828*b525a8f0SKuldeep Singh 829*b525a8f0SKuldeep Singh uint32_t xspi_addr = SZ_57M; 830*b525a8f0SKuldeep Singh 831*b525a8f0SKuldeep Singh /* 832*b525a8f0SKuldeep Singh * Second argument of fspi_test is the size of buffer(s) passed 833*b525a8f0SKuldeep Singh * to the function. 834*b525a8f0SKuldeep Singh * SIZE_BUFFER defined in test_fspi.c is kept large enough to 835*b525a8f0SKuldeep Singh * accommodate variety of sizes for regressive tests. 836*b525a8f0SKuldeep Singh */ 837*b525a8f0SKuldeep Singh fspi_test(xspi_addr, 0x40, 0); 838*b525a8f0SKuldeep Singh fspi_test(xspi_addr, 0x15, 2); 839*b525a8f0SKuldeep Singh fspi_test(xspi_addr, 0x80, 0); 840*b525a8f0SKuldeep Singh fspi_test(xspi_addr, 0x81, 0); 841*b525a8f0SKuldeep Singh fspi_test(xspi_addr, 0x79, 3); 842*b525a8f0SKuldeep Singh 843*b525a8f0SKuldeep Singh fspi_test(xspi_addr + 0x11, 0x15, 0); 844*b525a8f0SKuldeep Singh fspi_test(xspi_addr + 0x11, 0x40, 0); 845*b525a8f0SKuldeep Singh fspi_test(xspi_addr + 0xff, 0x40, 1); 846*b525a8f0SKuldeep Singh fspi_test(xspi_addr + 0x25, 0x81, 2); 847*b525a8f0SKuldeep Singh fspi_test(xspi_addr + 0xef, 0x6f, 3); 848*b525a8f0SKuldeep Singh 849*b525a8f0SKuldeep Singh fspi_test((xspi_addr - F_SECTOR_ERASE_SZ), 0x229, 0); 850*b525a8f0SKuldeep Singh #endif 851*b525a8f0SKuldeep Singh 852*b525a8f0SKuldeep Singh return XSPI_SUCCESS; 853*b525a8f0SKuldeep Singh } 854