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" 13c916d7c9SKumar Gala #include "../../qe/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 enqueue and dequeue of QMI */ 340c916d7c9SKumar Gala clrbits_be32(&qmi->fmqm_gc, FMQM_GC_ENQ_EN | FMQM_GC_DEQ_EN); 341c916d7c9SKumar Gala 342c916d7c9SKumar Gala /* disable all error interrupts */ 343c916d7c9SKumar Gala out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL); 344c916d7c9SKumar Gala /* clear all error events */ 345c916d7c9SKumar Gala out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL); 346c916d7c9SKumar Gala 347c916d7c9SKumar Gala /* disable all interrupts */ 348c916d7c9SKumar Gala out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL); 349c916d7c9SKumar Gala /* clear all interrupts */ 350c916d7c9SKumar Gala out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL); 351c916d7c9SKumar Gala } 352c916d7c9SKumar Gala 353c916d7c9SKumar Gala /* Init common part of FM, index is fm num# like fm as above */ 354c916d7c9SKumar Gala int fm_init_common(int index, struct ccsr_fman *reg) 355c916d7c9SKumar Gala { 356c916d7c9SKumar Gala int rc; 357f2717b47STimur Tabi #if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR) 358dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR; 359f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND) 360f2717b47STimur Tabi size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH; 361f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 362c916d7c9SKumar Gala 363dcf1d774SZhao Qiang rc = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR, 364c916d7c9SKumar Gala &fw_length, (u_char *)addr); 365c916d7c9SKumar Gala if (rc == -EUCLEAN) { 366c916d7c9SKumar Gala printf("NAND read of FMAN firmware at offset 0x%x failed %d\n", 367dcf1d774SZhao Qiang CONFIG_SYS_FMAN_FW_ADDR, rc); 368c916d7c9SKumar Gala } 369c916d7c9SKumar Gala #elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH) 370c916d7c9SKumar Gala struct spi_flash *ucode_flash; 371f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 372c916d7c9SKumar Gala int ret = 0; 373c916d7c9SKumar Gala 374c916d7c9SKumar Gala ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 375c916d7c9SKumar Gala CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); 376c916d7c9SKumar Gala if (!ucode_flash) 377c916d7c9SKumar Gala printf("SF: probe for ucode failed\n"); 378c916d7c9SKumar Gala else { 379dcf1d774SZhao Qiang ret = spi_flash_read(ucode_flash, CONFIG_SYS_FMAN_FW_ADDR, 380f2717b47STimur Tabi CONFIG_SYS_QE_FMAN_FW_LENGTH, addr); 381c916d7c9SKumar Gala if (ret) 382c916d7c9SKumar Gala printf("SF: read for ucode failed\n"); 383c916d7c9SKumar Gala spi_flash_free(ucode_flash); 384c916d7c9SKumar Gala } 385f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC) 386c916d7c9SKumar Gala int dev = CONFIG_SYS_MMC_ENV_DEV; 387f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 388f2717b47STimur Tabi u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; 389dcf1d774SZhao Qiang u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512; 390c916d7c9SKumar Gala struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); 391c916d7c9SKumar Gala 392c916d7c9SKumar Gala if (!mmc) 393c916d7c9SKumar Gala printf("\nMMC cannot find device for ucode\n"); 394c916d7c9SKumar Gala else { 395c916d7c9SKumar Gala printf("\nMMC read: dev # %u, block # %u, count %u ...\n", 396c916d7c9SKumar Gala dev, blk, cnt); 397c916d7c9SKumar Gala mmc_init(mmc); 398*7c4213f6SStephen Warren (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, 399*7c4213f6SStephen Warren addr); 400c916d7c9SKumar Gala /* flush cache after read */ 401c916d7c9SKumar Gala flush_cache((ulong)addr, cnt * 512); 402c916d7c9SKumar Gala } 403292dc6c5SLiu Gang #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE) 404dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR; 4057adefb55SYork Sun #else 4067adefb55SYork Sun void *addr = NULL; 407c916d7c9SKumar Gala #endif 408c916d7c9SKumar Gala 409c916d7c9SKumar Gala /* Upload the Fman microcode if it's present */ 410c916d7c9SKumar Gala rc = fman_upload_firmware(index, ®->fm_imem, addr); 411c916d7c9SKumar Gala if (rc) 412c916d7c9SKumar Gala return rc; 413978226daSSimon Glass setenv_addr("fman_ucode", addr); 414c916d7c9SKumar Gala 415c916d7c9SKumar Gala fm_init_muram(index, ®->muram); 416c916d7c9SKumar Gala fm_init_qmi(®->fm_qmi_common); 417c916d7c9SKumar Gala fm_init_fpm(®->fm_fpm); 418c916d7c9SKumar Gala 419c916d7c9SKumar Gala /* clear DMA status */ 420c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL); 421c916d7c9SKumar Gala 422c916d7c9SKumar Gala /* set DMA mode */ 423c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmmr, FMDMMR_SBER); 424c916d7c9SKumar Gala 425c916d7c9SKumar Gala return fm_init_bmi(index, ®->fm_bmi_common); 426c916d7c9SKumar Gala } 427