1c916d7c9SKumar Gala /* 2c916d7c9SKumar Gala * Copyright 2009-2011 Freescale Semiconductor, Inc. 3c916d7c9SKumar Gala * Dave Liu <daveliu@freescale.com> 4c916d7c9SKumar Gala * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6c916d7c9SKumar Gala */ 7c916d7c9SKumar Gala #include <common.h> 8c916d7c9SKumar Gala #include <malloc.h> 9c916d7c9SKumar Gala #include <asm/io.h> 10c916d7c9SKumar Gala #include <asm/errno.h> 11c916d7c9SKumar Gala 12c916d7c9SKumar Gala #include "fm.h" 132459afb1SQianyu Gong #include <fsl_qe.h> /* For struct qe_firmware */ 14c916d7c9SKumar Gala 15f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND 16c916d7c9SKumar Gala #include <nand.h> 17c916d7c9SKumar Gala #elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH) 18c916d7c9SKumar Gala #include <spi_flash.h> 19f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC) 20c916d7c9SKumar Gala #include <mmc.h> 21c916d7c9SKumar Gala #endif 22c916d7c9SKumar Gala 23c916d7c9SKumar Gala struct fm_muram muram[CONFIG_SYS_NUM_FMAN]; 24c916d7c9SKumar Gala 259fc29db1SHou Zhiqiang void *fm_muram_base(int fm_idx) 26c916d7c9SKumar Gala { 27c916d7c9SKumar Gala return muram[fm_idx].base; 28c916d7c9SKumar Gala } 29c916d7c9SKumar Gala 309fc29db1SHou Zhiqiang void *fm_muram_alloc(int fm_idx, size_t size, ulong align) 31c916d7c9SKumar Gala { 329fc29db1SHou Zhiqiang void *ret; 339fc29db1SHou Zhiqiang ulong align_mask; 349fc29db1SHou Zhiqiang size_t off; 359fc29db1SHou Zhiqiang void *save; 36c916d7c9SKumar Gala 37c916d7c9SKumar Gala align_mask = align - 1; 38c916d7c9SKumar Gala save = muram[fm_idx].alloc; 39c916d7c9SKumar Gala 409fc29db1SHou Zhiqiang off = (ulong)save & align_mask; 41c916d7c9SKumar Gala if (off != 0) 42c916d7c9SKumar Gala muram[fm_idx].alloc += (align - off); 43c916d7c9SKumar Gala off = size & align_mask; 44c916d7c9SKumar Gala if (off != 0) 45c916d7c9SKumar Gala size += (align - off); 46c916d7c9SKumar Gala if ((muram[fm_idx].alloc + size) >= muram[fm_idx].top) { 47c916d7c9SKumar Gala muram[fm_idx].alloc = save; 48c916d7c9SKumar Gala printf("%s: run out of ram.\n", __func__); 499fc29db1SHou Zhiqiang return NULL; 50c916d7c9SKumar Gala } 51c916d7c9SKumar Gala 52c916d7c9SKumar Gala ret = muram[fm_idx].alloc; 53c916d7c9SKumar Gala muram[fm_idx].alloc += size; 54c916d7c9SKumar Gala memset((void *)ret, 0, size); 55c916d7c9SKumar Gala 56c916d7c9SKumar Gala return ret; 57c916d7c9SKumar Gala } 58c916d7c9SKumar Gala 59c916d7c9SKumar Gala static void fm_init_muram(int fm_idx, void *reg) 60c916d7c9SKumar Gala { 619fc29db1SHou Zhiqiang void *base = reg; 62c916d7c9SKumar Gala 63c916d7c9SKumar Gala muram[fm_idx].base = base; 64c916d7c9SKumar Gala muram[fm_idx].size = CONFIG_SYS_FM_MURAM_SIZE; 65c916d7c9SKumar Gala muram[fm_idx].alloc = base + FM_MURAM_RES_SIZE; 66c916d7c9SKumar Gala muram[fm_idx].top = base + CONFIG_SYS_FM_MURAM_SIZE; 67c916d7c9SKumar Gala } 68c916d7c9SKumar Gala 69c916d7c9SKumar Gala /* 70c916d7c9SKumar Gala * fm_upload_ucode - Fman microcode upload worker function 71c916d7c9SKumar Gala * 72c916d7c9SKumar Gala * This function does the actual uploading of an Fman microcode 73c916d7c9SKumar Gala * to an Fman. 74c916d7c9SKumar Gala */ 75c916d7c9SKumar Gala static void fm_upload_ucode(int fm_idx, struct fm_imem *imem, 76c916d7c9SKumar Gala u32 *ucode, unsigned int size) 77c916d7c9SKumar Gala { 78c916d7c9SKumar Gala unsigned int i; 79c916d7c9SKumar Gala unsigned int timeout = 1000000; 80c916d7c9SKumar Gala 81c916d7c9SKumar Gala /* enable address auto increase */ 82c916d7c9SKumar Gala out_be32(&imem->iadd, IRAM_IADD_AIE); 83c916d7c9SKumar Gala /* write microcode to IRAM */ 84c916d7c9SKumar Gala for (i = 0; i < size / 4; i++) 85648bde6dSHou Zhiqiang out_be32(&imem->idata, (be32_to_cpu(ucode[i]))); 86c916d7c9SKumar Gala 87c916d7c9SKumar Gala /* verify if the writing is over */ 88c916d7c9SKumar Gala out_be32(&imem->iadd, 0); 89648bde6dSHou Zhiqiang while ((in_be32(&imem->idata) != be32_to_cpu(ucode[0])) && --timeout) 90c916d7c9SKumar Gala ; 91c916d7c9SKumar Gala if (!timeout) 92c916d7c9SKumar Gala printf("Fman%u: microcode upload timeout\n", fm_idx + 1); 93c916d7c9SKumar Gala 94c916d7c9SKumar Gala /* enable microcode from IRAM */ 95c916d7c9SKumar Gala out_be32(&imem->iready, IRAM_READY); 96c916d7c9SKumar Gala } 97c916d7c9SKumar Gala 98c916d7c9SKumar Gala /* 99c916d7c9SKumar Gala * Upload an Fman firmware 100c916d7c9SKumar Gala * 101c916d7c9SKumar Gala * This function is similar to qe_upload_firmware(), exception that it uploads 102c916d7c9SKumar Gala * a microcode to the Fman instead of the QE. 103c916d7c9SKumar Gala * 104c916d7c9SKumar Gala * Because the process for uploading a microcode to the Fman is similar for 105c916d7c9SKumar Gala * that of the QE, the QE firmware binary format is used for Fman microcode. 106c916d7c9SKumar Gala * It should be possible to unify these two functions, but for now we keep them 107c916d7c9SKumar Gala * separate. 108c916d7c9SKumar Gala */ 109c916d7c9SKumar Gala static int fman_upload_firmware(int fm_idx, 110c916d7c9SKumar Gala struct fm_imem *fm_imem, 111c916d7c9SKumar Gala const struct qe_firmware *firmware) 112c916d7c9SKumar Gala { 113c916d7c9SKumar Gala unsigned int i; 114c916d7c9SKumar Gala u32 crc; 115c916d7c9SKumar Gala size_t calc_size = sizeof(struct qe_firmware); 116c916d7c9SKumar Gala size_t length; 117c916d7c9SKumar Gala const struct qe_header *hdr; 118c916d7c9SKumar Gala 119c916d7c9SKumar Gala if (!firmware) { 120c916d7c9SKumar Gala printf("Fman%u: Invalid address for firmware\n", fm_idx + 1); 121c916d7c9SKumar Gala return -EINVAL; 122c916d7c9SKumar Gala } 123c916d7c9SKumar Gala 124c916d7c9SKumar Gala hdr = &firmware->header; 125c916d7c9SKumar Gala length = be32_to_cpu(hdr->length); 126c916d7c9SKumar Gala 127c916d7c9SKumar Gala /* Check the magic */ 128c916d7c9SKumar Gala if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 129c916d7c9SKumar Gala (hdr->magic[2] != 'F')) { 130c916d7c9SKumar Gala printf("Fman%u: Data at %p is not a firmware\n", fm_idx + 1, 131c916d7c9SKumar Gala firmware); 132c916d7c9SKumar Gala return -EPERM; 133c916d7c9SKumar Gala } 134c916d7c9SKumar Gala 135c916d7c9SKumar Gala /* Check the version */ 136c916d7c9SKumar Gala if (hdr->version != 1) { 137c916d7c9SKumar Gala printf("Fman%u: Unsupported firmware version %u\n", fm_idx + 1, 138c916d7c9SKumar Gala hdr->version); 139c916d7c9SKumar Gala return -EPERM; 140c916d7c9SKumar Gala } 141c916d7c9SKumar Gala 142c916d7c9SKumar Gala /* Validate some of the fields */ 143c916d7c9SKumar Gala if ((firmware->count != 1)) { 144c916d7c9SKumar Gala printf("Fman%u: Invalid data in firmware header\n", fm_idx + 1); 145c916d7c9SKumar Gala return -EINVAL; 146c916d7c9SKumar Gala } 147c916d7c9SKumar Gala 148c916d7c9SKumar Gala /* Validate the length and check if there's a CRC */ 149c916d7c9SKumar Gala calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 150c916d7c9SKumar Gala 151c916d7c9SKumar Gala for (i = 0; i < firmware->count; i++) 152c916d7c9SKumar Gala /* 153c916d7c9SKumar Gala * For situations where the second RISC uses the same microcode 154c916d7c9SKumar Gala * as the first, the 'code_offset' and 'count' fields will be 155c916d7c9SKumar Gala * zero, so it's okay to add those. 156c916d7c9SKumar Gala */ 157c916d7c9SKumar Gala calc_size += sizeof(u32) * 158c916d7c9SKumar Gala be32_to_cpu(firmware->microcode[i].count); 159c916d7c9SKumar Gala 160c916d7c9SKumar Gala /* Validate the length */ 161c916d7c9SKumar Gala if (length != calc_size + sizeof(u32)) { 162c916d7c9SKumar Gala printf("Fman%u: Invalid length in firmware header\n", 163c916d7c9SKumar Gala fm_idx + 1); 164c916d7c9SKumar Gala return -EPERM; 165c916d7c9SKumar Gala } 166c916d7c9SKumar Gala 167c916d7c9SKumar Gala /* 168c916d7c9SKumar Gala * Validate the CRC. We would normally call crc32_no_comp(), but that 169c916d7c9SKumar Gala * function isn't available unless you turn on JFFS support. 170c916d7c9SKumar Gala */ 171c916d7c9SKumar Gala crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 172c916d7c9SKumar Gala if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { 173c916d7c9SKumar Gala printf("Fman%u: Firmware CRC is invalid\n", fm_idx + 1); 174c916d7c9SKumar Gala return -EIO; 175c916d7c9SKumar Gala } 176c916d7c9SKumar Gala 177c916d7c9SKumar Gala /* Loop through each microcode. */ 178c916d7c9SKumar Gala for (i = 0; i < firmware->count; i++) { 179c916d7c9SKumar Gala const struct qe_microcode *ucode = &firmware->microcode[i]; 180c916d7c9SKumar Gala 181c916d7c9SKumar Gala /* Upload a microcode if it's present */ 182648bde6dSHou Zhiqiang if (be32_to_cpu(ucode->code_offset)) { 183c916d7c9SKumar Gala u32 ucode_size; 184c916d7c9SKumar Gala u32 *code; 185c916d7c9SKumar Gala printf("Fman%u: Uploading microcode version %u.%u.%u\n", 186c916d7c9SKumar Gala fm_idx + 1, ucode->major, ucode->minor, 187c916d7c9SKumar Gala ucode->revision); 188648bde6dSHou Zhiqiang code = (void *)firmware + 189648bde6dSHou Zhiqiang be32_to_cpu(ucode->code_offset); 190648bde6dSHou Zhiqiang ucode_size = sizeof(u32) * be32_to_cpu(ucode->count); 191c916d7c9SKumar Gala fm_upload_ucode(fm_idx, fm_imem, code, ucode_size); 192c916d7c9SKumar Gala } 193c916d7c9SKumar Gala } 194c916d7c9SKumar Gala 195c916d7c9SKumar Gala return 0; 196c916d7c9SKumar Gala } 197c916d7c9SKumar Gala 198c916d7c9SKumar Gala static u32 fm_assign_risc(int port_id) 199c916d7c9SKumar Gala { 200c916d7c9SKumar Gala u32 risc_sel, val; 201c916d7c9SKumar Gala risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1; 202c916d7c9SKumar Gala val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK; 203c916d7c9SKumar Gala val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel); 204c916d7c9SKumar Gala 205c916d7c9SKumar Gala return val; 206c916d7c9SKumar Gala } 207c916d7c9SKumar Gala 208c916d7c9SKumar Gala static void fm_init_fpm(struct fm_fpm *fpm) 209c916d7c9SKumar Gala { 210c916d7c9SKumar Gala int i, port_id; 211c916d7c9SKumar Gala u32 val; 212c916d7c9SKumar Gala 213c916d7c9SKumar Gala setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC | 214c916d7c9SKumar Gala FMFPEE_CER | FMFPEE_DER); 215c916d7c9SKumar Gala 216c916d7c9SKumar Gala /* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */ 217c916d7c9SKumar Gala 218c916d7c9SKumar Gala /* offline/parser port */ 219c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_OH_PORT; i++) { 220c916d7c9SKumar Gala port_id = OH_PORT_ID_BASE + i; 221c916d7c9SKumar Gala val = fm_assign_risc(port_id); 222c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val); 223c916d7c9SKumar Gala } 224c916d7c9SKumar Gala /* Rx 1G port */ 225c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) { 226c916d7c9SKumar Gala port_id = RX_PORT_1G_BASE + i; 227c916d7c9SKumar Gala val = fm_assign_risc(port_id); 228c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val); 229c916d7c9SKumar Gala } 230c916d7c9SKumar Gala /* Tx 1G port */ 231c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) { 232c916d7c9SKumar Gala port_id = TX_PORT_1G_BASE + i; 233c916d7c9SKumar Gala val = fm_assign_risc(port_id); 234c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val); 235c916d7c9SKumar Gala } 236c916d7c9SKumar Gala /* Rx 10G port */ 237c916d7c9SKumar Gala port_id = RX_PORT_10G_BASE; 238c916d7c9SKumar Gala val = fm_assign_risc(port_id); 239c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val); 240c916d7c9SKumar Gala /* Tx 10G port */ 241c916d7c9SKumar Gala port_id = TX_PORT_10G_BASE; 242c916d7c9SKumar Gala val = fm_assign_risc(port_id); 243c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val); 244c916d7c9SKumar Gala 245c916d7c9SKumar Gala /* disable the dispatch limit in IM case */ 246c916d7c9SKumar Gala out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE); 247c916d7c9SKumar Gala /* clear events */ 248c916d7c9SKumar Gala out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT); 249c916d7c9SKumar Gala 250c916d7c9SKumar Gala /* clear risc events */ 251c916d7c9SKumar Gala for (i = 0; i < 4; i++) 252c916d7c9SKumar Gala out_be32(&fpm->fpmcev[i], 0xffffffff); 253c916d7c9SKumar Gala 254c916d7c9SKumar Gala /* clear error */ 255c916d7c9SKumar Gala out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC); 256c916d7c9SKumar Gala } 257c916d7c9SKumar Gala 258c916d7c9SKumar Gala static int fm_init_bmi(int fm_idx, struct fm_bmi_common *bmi) 259c916d7c9SKumar Gala { 260c916d7c9SKumar Gala int blk, i, port_id; 2619fc29db1SHou Zhiqiang u32 val; 2629fc29db1SHou Zhiqiang size_t offset; 2639fc29db1SHou Zhiqiang void *base; 264c916d7c9SKumar Gala 265c916d7c9SKumar Gala /* alloc free buffer pool in MURAM */ 266c916d7c9SKumar Gala base = fm_muram_alloc(fm_idx, FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN); 267c916d7c9SKumar Gala if (!base) { 268c916d7c9SKumar Gala printf("%s: no muram for free buffer pool\n", __func__); 269c916d7c9SKumar Gala return -ENOMEM; 270c916d7c9SKumar Gala } 271c916d7c9SKumar Gala offset = base - fm_muram_base(fm_idx); 272c916d7c9SKumar Gala 273c916d7c9SKumar Gala /* Need 128KB total free buffer pool size */ 274c916d7c9SKumar Gala val = offset / 256; 275c916d7c9SKumar Gala blk = FM_FREE_POOL_SIZE / 256; 276c916d7c9SKumar Gala /* in IM, we must not begin from offset 0 in MURAM */ 277c916d7c9SKumar Gala val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT); 278c916d7c9SKumar Gala out_be32(&bmi->fmbm_cfg1, val); 279c916d7c9SKumar Gala 280c916d7c9SKumar Gala /* disable all BMI interrupt */ 281c916d7c9SKumar Gala out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL); 282c916d7c9SKumar Gala 283c916d7c9SKumar Gala /* clear all events */ 284c916d7c9SKumar Gala out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL); 285c916d7c9SKumar Gala 286c916d7c9SKumar Gala /* 287c916d7c9SKumar Gala * set port parameters - FMBM_PP_x 288c916d7c9SKumar Gala * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1 289c916d7c9SKumar Gala * max dma 10G Rx/Tx=3, others is 1 290c916d7c9SKumar Gala * set port FIFO size - FMBM_PFS_x 291c916d7c9SKumar Gala * 4KB for all Rx and Tx ports 292c916d7c9SKumar Gala */ 293c916d7c9SKumar Gala /* offline/parser port */ 294c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_OH_PORT; i++) { 295c916d7c9SKumar Gala port_id = OH_PORT_ID_BASE + i - 1; 296c916d7c9SKumar Gala /* max tasks=1, max dma=1, no extra */ 297c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], 0); 298c916d7c9SKumar Gala /* port FIFO size - 256 bytes, no extra */ 299c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], 0); 300c916d7c9SKumar Gala } 301c916d7c9SKumar Gala /* Rx 1G port */ 302c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) { 303c916d7c9SKumar Gala port_id = RX_PORT_1G_BASE + i - 1; 304c916d7c9SKumar Gala /* max tasks=4, max dma=1, no extra */ 305c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4)); 306c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */ 307c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf)); 308c916d7c9SKumar Gala } 309c916d7c9SKumar Gala /* Tx 1G port FIFO size - 4KB, no extra */ 310c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) { 311c916d7c9SKumar Gala port_id = TX_PORT_1G_BASE + i - 1; 312c916d7c9SKumar Gala /* max tasks=4, max dma=1, no extra */ 313c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4)); 314c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */ 315c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf)); 316c916d7c9SKumar Gala } 317c916d7c9SKumar Gala /* Rx 10G port */ 318c916d7c9SKumar Gala port_id = RX_PORT_10G_BASE - 1; 319c916d7c9SKumar Gala /* max tasks=12, max dma=3, no extra */ 320c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3)); 321c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */ 322c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf)); 323c916d7c9SKumar Gala 324c916d7c9SKumar Gala /* Tx 10G port */ 325c916d7c9SKumar Gala port_id = TX_PORT_10G_BASE - 1; 326c916d7c9SKumar Gala /* max tasks=12, max dma=3, no extra */ 327c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3)); 328c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */ 329c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf)); 330c916d7c9SKumar Gala 331c916d7c9SKumar Gala /* initialize internal buffers data base (linked list) */ 332c916d7c9SKumar Gala out_be32(&bmi->fmbm_init, FMBM_INIT_START); 333c916d7c9SKumar Gala 334c916d7c9SKumar Gala return 0; 335c916d7c9SKumar Gala } 336c916d7c9SKumar Gala 337c916d7c9SKumar Gala static void fm_init_qmi(struct fm_qmi_common *qmi) 338c916d7c9SKumar Gala { 339c916d7c9SKumar Gala /* disable all error interrupts */ 340c916d7c9SKumar Gala out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL); 341c916d7c9SKumar Gala /* clear all error events */ 342c916d7c9SKumar Gala out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL); 343c916d7c9SKumar Gala 344c916d7c9SKumar Gala /* disable all interrupts */ 345c916d7c9SKumar Gala out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL); 346c916d7c9SKumar Gala /* clear all interrupts */ 347c916d7c9SKumar Gala out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL); 348c916d7c9SKumar Gala } 349c916d7c9SKumar Gala 350c916d7c9SKumar Gala /* Init common part of FM, index is fm num# like fm as above */ 351c916d7c9SKumar Gala int fm_init_common(int index, struct ccsr_fman *reg) 352c916d7c9SKumar Gala { 353c916d7c9SKumar Gala int rc; 354f2717b47STimur Tabi #if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR) 355dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR; 356f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND) 357f2717b47STimur Tabi size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH; 358f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 359c916d7c9SKumar Gala 360b616d9b0SScott Wood rc = nand_read(nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR, 361c916d7c9SKumar Gala &fw_length, (u_char *)addr); 362c916d7c9SKumar Gala if (rc == -EUCLEAN) { 363c916d7c9SKumar Gala printf("NAND read of FMAN firmware at offset 0x%x failed %d\n", 364dcf1d774SZhao Qiang CONFIG_SYS_FMAN_FW_ADDR, rc); 365c916d7c9SKumar Gala } 366c916d7c9SKumar Gala #elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH) 367c916d7c9SKumar Gala struct spi_flash *ucode_flash; 368f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 369c916d7c9SKumar Gala int ret = 0; 370c916d7c9SKumar Gala 371*77b571daSQianyu Gong #ifdef CONFIG_DM_SPI_FLASH 372*77b571daSQianyu Gong struct udevice *new; 373*77b571daSQianyu Gong 374*77b571daSQianyu Gong /* speed and mode will be read from DT */ 375*77b571daSQianyu Gong ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 376*77b571daSQianyu Gong 0, 0, &new); 377*77b571daSQianyu Gong 378*77b571daSQianyu Gong ucode_flash = dev_get_uclass_priv(new); 379*77b571daSQianyu Gong #else 380c916d7c9SKumar Gala ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 381c916d7c9SKumar Gala CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); 382*77b571daSQianyu Gong #endif 383c916d7c9SKumar Gala if (!ucode_flash) 384c916d7c9SKumar Gala printf("SF: probe for ucode failed\n"); 385c916d7c9SKumar Gala else { 386dcf1d774SZhao Qiang ret = spi_flash_read(ucode_flash, CONFIG_SYS_FMAN_FW_ADDR, 387f2717b47STimur Tabi CONFIG_SYS_QE_FMAN_FW_LENGTH, addr); 388c916d7c9SKumar Gala if (ret) 389c916d7c9SKumar Gala printf("SF: read for ucode failed\n"); 390c916d7c9SKumar Gala spi_flash_free(ucode_flash); 391c916d7c9SKumar Gala } 392f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC) 393c916d7c9SKumar Gala int dev = CONFIG_SYS_MMC_ENV_DEV; 394f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 395f2717b47STimur Tabi u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; 396dcf1d774SZhao Qiang u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512; 397c916d7c9SKumar Gala struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); 398c916d7c9SKumar Gala 399c916d7c9SKumar Gala if (!mmc) 400c916d7c9SKumar Gala printf("\nMMC cannot find device for ucode\n"); 401c916d7c9SKumar Gala else { 402c916d7c9SKumar Gala printf("\nMMC read: dev # %u, block # %u, count %u ...\n", 403c916d7c9SKumar Gala dev, blk, cnt); 404c916d7c9SKumar Gala mmc_init(mmc); 4057c4213f6SStephen Warren (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, 4067c4213f6SStephen Warren addr); 407c916d7c9SKumar Gala /* flush cache after read */ 408c916d7c9SKumar Gala flush_cache((ulong)addr, cnt * 512); 409c916d7c9SKumar Gala } 410292dc6c5SLiu Gang #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE) 411dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR; 4127adefb55SYork Sun #else 4137adefb55SYork Sun void *addr = NULL; 414c916d7c9SKumar Gala #endif 415c916d7c9SKumar Gala 416c916d7c9SKumar Gala /* Upload the Fman microcode if it's present */ 417c916d7c9SKumar Gala rc = fman_upload_firmware(index, ®->fm_imem, addr); 418c916d7c9SKumar Gala if (rc) 419c916d7c9SKumar Gala return rc; 420978226daSSimon Glass setenv_addr("fman_ucode", addr); 421c916d7c9SKumar Gala 422c916d7c9SKumar Gala fm_init_muram(index, ®->muram); 423c916d7c9SKumar Gala fm_init_qmi(®->fm_qmi_common); 424c916d7c9SKumar Gala fm_init_fpm(®->fm_fpm); 425c916d7c9SKumar Gala 426c916d7c9SKumar Gala /* clear DMA status */ 427c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL); 428c916d7c9SKumar Gala 429c916d7c9SKumar Gala /* set DMA mode */ 430c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmmr, FMDMMR_SBER); 431c916d7c9SKumar Gala 432c916d7c9SKumar Gala return fm_init_bmi(index, ®->fm_bmi_common); 433c916d7c9SKumar Gala } 434