17737d5c6SDave Liu /* 24e7b25e4SHaiying Wang * Copyright (C) 2006-2009 Freescale Semiconductor, Inc. 37737d5c6SDave Liu * 47737d5c6SDave Liu * Dave Liu <daveliu@freescale.com> 57737d5c6SDave Liu * based on source code of Shlomi Gridish 67737d5c6SDave Liu * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 87737d5c6SDave Liu */ 97737d5c6SDave Liu 10b5bf5cb3SMasahiro Yamada #include <common.h> 11*5aa03dddSZhao Qiang #include <malloc.h> 12b8ec2385STimur Tabi #include <command.h> 131221ce45SMasahiro Yamada #include <linux/errno.h> 14b5bf5cb3SMasahiro Yamada #include <asm/io.h> 15b5bf5cb3SMasahiro Yamada #include <linux/immap_qe.h> 162459afb1SQianyu Gong #include <fsl_qe.h> 1773fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A 189c7c86f4SZhao Qiang #include <asm/arch/immap_ls102xa.h> 199c7c86f4SZhao Qiang #endif 207737d5c6SDave Liu 21*5aa03dddSZhao Qiang #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC 22*5aa03dddSZhao Qiang #include <mmc.h> 23*5aa03dddSZhao Qiang #endif 24*5aa03dddSZhao Qiang 25ca721fb2SZhao Qiang #define MPC85xx_DEVDISR_QE_DISABLE 0x1 26ca721fb2SZhao Qiang 277737d5c6SDave Liu qe_map_t *qe_immr = NULL; 283bf46e6aSZhao Qiang #ifdef CONFIG_QE 297737d5c6SDave Liu static qe_snum_t snums[QE_NUM_OF_SNUM]; 303bf46e6aSZhao Qiang #endif 317737d5c6SDave Liu 321218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR; 331218abf1SWolfgang Denk 347737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) 357737d5c6SDave Liu { 367737d5c6SDave Liu u32 cecr; 377737d5c6SDave Liu 387737d5c6SDave Liu if (cmd == QE_RESET) { 397737d5c6SDave Liu out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); 407737d5c6SDave Liu } else { 417737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, cmd_data); 427737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | 437737d5c6SDave Liu ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd)); 447737d5c6SDave Liu } 457737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 467737d5c6SDave Liu do { 477737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 487737d5c6SDave Liu } while (cecr & QE_CR_FLG); 497737d5c6SDave Liu 507737d5c6SDave Liu return; 517737d5c6SDave Liu } 527737d5c6SDave Liu 5393d33204SZhao Qiang #ifdef CONFIG_QE 547737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align) 557737d5c6SDave Liu { 567737d5c6SDave Liu uint retloc; 577737d5c6SDave Liu uint align_mask, off; 587737d5c6SDave Liu uint savebase; 597737d5c6SDave Liu 607737d5c6SDave Liu align_mask = align - 1; 6145bae2e3SSimon Glass savebase = gd->arch.mp_alloc_base; 627737d5c6SDave Liu 6345bae2e3SSimon Glass off = gd->arch.mp_alloc_base & align_mask; 6445bae2e3SSimon Glass if (off != 0) 6545bae2e3SSimon Glass gd->arch.mp_alloc_base += (align - off); 667737d5c6SDave Liu 677737d5c6SDave Liu if ((off = size & align_mask) != 0) 687737d5c6SDave Liu size += (align - off); 697737d5c6SDave Liu 7045bae2e3SSimon Glass if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) { 7145bae2e3SSimon Glass gd->arch.mp_alloc_base = savebase; 727737d5c6SDave Liu printf("%s: ran out of ram.\n", __FUNCTION__); 737737d5c6SDave Liu } 747737d5c6SDave Liu 7545bae2e3SSimon Glass retloc = gd->arch.mp_alloc_base; 7645bae2e3SSimon Glass gd->arch.mp_alloc_base += size; 777737d5c6SDave Liu 787737d5c6SDave Liu memset((void *)&qe_immr->muram[retloc], 0, size); 797737d5c6SDave Liu 807737d5c6SDave Liu __asm__ __volatile__("sync"); 817737d5c6SDave Liu 827737d5c6SDave Liu return retloc; 837737d5c6SDave Liu } 8493d33204SZhao Qiang #endif 857737d5c6SDave Liu 867737d5c6SDave Liu void *qe_muram_addr(uint offset) 877737d5c6SDave Liu { 887737d5c6SDave Liu return (void *)&qe_immr->muram[offset]; 897737d5c6SDave Liu } 907737d5c6SDave Liu 913bf46e6aSZhao Qiang #ifdef CONFIG_QE 927737d5c6SDave Liu static void qe_sdma_init(void) 937737d5c6SDave Liu { 947737d5c6SDave Liu volatile sdma_t *p; 957737d5c6SDave Liu uint sdma_buffer_base; 967737d5c6SDave Liu 977737d5c6SDave Liu p = (volatile sdma_t *)&qe_immr->sdma; 987737d5c6SDave Liu 997737d5c6SDave Liu /* All of DMA transaction in bus 1 */ 1007737d5c6SDave Liu out_be32(&p->sdaqr, 0); 1017737d5c6SDave Liu out_be32(&p->sdaqmr, 0); 1027737d5c6SDave Liu 1037737d5c6SDave Liu /* Allocate 2KB temporary buffer for sdma */ 104ff9658d7SDave Liu sdma_buffer_base = qe_muram_alloc(2048, 4096); 1057737d5c6SDave Liu out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); 1067737d5c6SDave Liu 1077737d5c6SDave Liu /* Clear sdma status */ 1087737d5c6SDave Liu out_be32(&p->sdsr, 0x03000000); 1097737d5c6SDave Liu 1107737d5c6SDave Liu /* Enable global mode on bus 1, and 2KB buffer size */ 1117737d5c6SDave Liu out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT)); 1127737d5c6SDave Liu } 1137737d5c6SDave Liu 1144e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the 1154e7b25e4SHaiying Wang * "SNUM Table" chart in the QE Reference Manual. The order is not important, 1164e7b25e4SHaiying Wang * we just need to know what the SNUMs are for the threads. 1174e7b25e4SHaiying Wang */ 1184e7b25e4SHaiying Wang static u8 thread_snum[] = { 119a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */ 120a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309) 1217737d5c6SDave Liu 0x04, 0x05, 0x0c, 0x0d, 1227737d5c6SDave Liu 0x14, 0x15, 0x1c, 0x1d, 1237737d5c6SDave Liu 0x24, 0x25, 0x2c, 0x2d, 124a88731a6SGerlando Falauto 0x34, 0x35, 125a88731a6SGerlando Falauto #endif 126a88731a6SGerlando Falauto 0x88, 0x89, 0x98, 0x99, 127a88731a6SGerlando Falauto 0xa8, 0xa9, 0xb8, 0xb9, 128a88731a6SGerlando Falauto 0xc8, 0xc9, 0xd8, 0xd9, 129a88731a6SGerlando Falauto 0xe8, 0xe9, 0x08, 0x09, 130a88731a6SGerlando Falauto 0x18, 0x19, 0x28, 0x29, 131a88731a6SGerlando Falauto 0x38, 0x39, 0x48, 0x49, 132a88731a6SGerlando Falauto 0x58, 0x59, 0x68, 0x69, 133a88731a6SGerlando Falauto 0x78, 0x79, 0x80, 0x81 1347737d5c6SDave Liu }; 1357737d5c6SDave Liu 1367737d5c6SDave Liu static void qe_snums_init(void) 1377737d5c6SDave Liu { 1387737d5c6SDave Liu int i; 1397737d5c6SDave Liu 1407737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1417737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1427737d5c6SDave Liu snums[i].num = thread_snum[i]; 1437737d5c6SDave Liu } 1447737d5c6SDave Liu } 1457737d5c6SDave Liu 1467737d5c6SDave Liu int qe_get_snum(void) 1477737d5c6SDave Liu { 1487737d5c6SDave Liu int snum = -EBUSY; 1497737d5c6SDave Liu int i; 1507737d5c6SDave Liu 1517737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1527737d5c6SDave Liu if (snums[i].state == QE_SNUM_STATE_FREE) { 1537737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_USED; 1547737d5c6SDave Liu snum = snums[i].num; 1557737d5c6SDave Liu break; 1567737d5c6SDave Liu } 1577737d5c6SDave Liu } 1587737d5c6SDave Liu 1597737d5c6SDave Liu return snum; 1607737d5c6SDave Liu } 1617737d5c6SDave Liu 1627737d5c6SDave Liu void qe_put_snum(u8 snum) 1637737d5c6SDave Liu { 1647737d5c6SDave Liu int i; 1657737d5c6SDave Liu 1667737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1677737d5c6SDave Liu if (snums[i].num == snum) { 1687737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1697737d5c6SDave Liu break; 1707737d5c6SDave Liu } 1717737d5c6SDave Liu } 1727737d5c6SDave Liu } 1737737d5c6SDave Liu 1747737d5c6SDave Liu void qe_init(uint qe_base) 1757737d5c6SDave Liu { 1767737d5c6SDave Liu /* Init the QE IMMR base */ 1777737d5c6SDave Liu qe_immr = (qe_map_t *)qe_base; 1787737d5c6SDave Liu 179f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR 180c0a14aedSWolfgang Denk /* 181c0a14aedSWolfgang Denk * Upload microcode to IRAM for those SOCs which do not have ROM in QE. 1822d4de6aeSHaiying Wang */ 183dcf1d774SZhao Qiang qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); 1842d4de6aeSHaiying Wang 1852d4de6aeSHaiying Wang /* enable the microcode in IRAM */ 1862d4de6aeSHaiying Wang out_be32(&qe_immr->iram.iready,QE_IRAM_READY); 1872d4de6aeSHaiying Wang #endif 1882d4de6aeSHaiying Wang 18945bae2e3SSimon Glass gd->arch.mp_alloc_base = QE_DATAONLY_BASE; 19045bae2e3SSimon Glass gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE; 1917737d5c6SDave Liu 1927737d5c6SDave Liu qe_sdma_init(); 1937737d5c6SDave Liu qe_snums_init(); 1947737d5c6SDave Liu } 1953bf46e6aSZhao Qiang #endif 1967737d5c6SDave Liu 19793d33204SZhao Qiang #ifdef CONFIG_U_QE 19893d33204SZhao Qiang void u_qe_init(void) 19993d33204SZhao Qiang { 200d3e6d30cSZhao Qiang qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); 20193d33204SZhao Qiang 202*5aa03dddSZhao Qiang void *addr = (void *)CONFIG_SYS_QE_FW_ADDR; 203*5aa03dddSZhao Qiang #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC 204*5aa03dddSZhao Qiang int dev = CONFIG_SYS_MMC_ENV_DEV; 205*5aa03dddSZhao Qiang u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; 206*5aa03dddSZhao Qiang u32 blk = CONFIG_SYS_QE_FW_ADDR / 512; 207*5aa03dddSZhao Qiang 208*5aa03dddSZhao Qiang if (mmc_initialize(gd->bd)) { 209*5aa03dddSZhao Qiang printf("%s: mmc_initialize() failed\n", __func__); 210*5aa03dddSZhao Qiang return; 211*5aa03dddSZhao Qiang } 212*5aa03dddSZhao Qiang addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); 213*5aa03dddSZhao Qiang struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); 214*5aa03dddSZhao Qiang 215*5aa03dddSZhao Qiang if (!mmc) { 216*5aa03dddSZhao Qiang free(addr); 217*5aa03dddSZhao Qiang printf("\nMMC cannot find device for ucode\n"); 218*5aa03dddSZhao Qiang } else { 219*5aa03dddSZhao Qiang printf("\nMMC read: dev # %u, block # %u, count %u ...\n", 220*5aa03dddSZhao Qiang dev, blk, cnt); 221*5aa03dddSZhao Qiang mmc_init(mmc); 222*5aa03dddSZhao Qiang (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, 223*5aa03dddSZhao Qiang addr); 224*5aa03dddSZhao Qiang /* flush cache after read */ 225*5aa03dddSZhao Qiang flush_cache((ulong)addr, cnt * 512); 226*5aa03dddSZhao Qiang } 227*5aa03dddSZhao Qiang #endif 228*5aa03dddSZhao Qiang u_qe_upload_firmware(addr); 22993d33204SZhao Qiang out_be32(&qe_immr->iram.iready, QE_IRAM_READY); 230*5aa03dddSZhao Qiang #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC 231*5aa03dddSZhao Qiang free(addr); 232*5aa03dddSZhao Qiang #endif 23393d33204SZhao Qiang } 23493d33204SZhao Qiang #endif 23593d33204SZhao Qiang 236ae42eb03SZhao Qiang #ifdef CONFIG_U_QE 237ae42eb03SZhao Qiang void u_qe_resume(void) 238ae42eb03SZhao Qiang { 239ae42eb03SZhao Qiang qe_map_t *qe_immrr; 240ae42eb03SZhao Qiang 241d3e6d30cSZhao Qiang qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); 242ae42eb03SZhao Qiang u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr); 243ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iready, QE_IRAM_READY); 244ae42eb03SZhao Qiang } 245ae42eb03SZhao Qiang #endif 246ae42eb03SZhao Qiang 2477737d5c6SDave Liu void qe_reset(void) 2487737d5c6SDave Liu { 2497737d5c6SDave Liu qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, 2507737d5c6SDave Liu (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); 2517737d5c6SDave Liu } 2527737d5c6SDave Liu 2533bf46e6aSZhao Qiang #ifdef CONFIG_QE 2547737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base) 2557737d5c6SDave Liu { 2567737d5c6SDave Liu u32 cecr; 2577737d5c6SDave Liu 2587737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, para_ram_base); 2597737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT) 2607737d5c6SDave Liu | QE_CR_FLG | QE_ASSIGN_PAGE); 2617737d5c6SDave Liu 2627737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 2637737d5c6SDave Liu do { 2647737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 2657737d5c6SDave Liu } while (cecr & QE_CR_FLG ); 2667737d5c6SDave Liu 2677737d5c6SDave Liu return; 2687737d5c6SDave Liu } 2693bf46e6aSZhao Qiang #endif 2707737d5c6SDave Liu 2717737d5c6SDave Liu /* 2727737d5c6SDave Liu * brg: 0~15 as BRG1~BRG16 2737737d5c6SDave Liu rate: baud rate 2747737d5c6SDave Liu * BRG input clock comes from the BRGCLK (internal clock generated from 2757737d5c6SDave Liu the QE clock, it is one-half of the QE clock), If need the clock source 2767737d5c6SDave Liu from CLKn pin, we have te change the function. 2777737d5c6SDave Liu */ 2787737d5c6SDave Liu 2791206c184SSimon Glass #define BRG_CLK (gd->arch.brg_clk) 2807737d5c6SDave Liu 28193d33204SZhao Qiang #ifdef CONFIG_QE 2827737d5c6SDave Liu int qe_set_brg(uint brg, uint rate) 2837737d5c6SDave Liu { 2847737d5c6SDave Liu volatile uint *bp; 2857737d5c6SDave Liu u32 divisor; 2867737d5c6SDave Liu int div16 = 0; 2877737d5c6SDave Liu 2887737d5c6SDave Liu if (brg >= QE_NUM_OF_BRGS) 2897737d5c6SDave Liu return -EINVAL; 2907737d5c6SDave Liu bp = (uint *)&qe_immr->brg.brgc1; 2917737d5c6SDave Liu bp += brg; 2927737d5c6SDave Liu 2937737d5c6SDave Liu divisor = (BRG_CLK / rate); 2947737d5c6SDave Liu if (divisor > QE_BRGC_DIVISOR_MAX + 1) { 2957737d5c6SDave Liu div16 = 1; 2967737d5c6SDave Liu divisor /= 16; 2977737d5c6SDave Liu } 2987737d5c6SDave Liu 2997737d5c6SDave Liu *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; 3007737d5c6SDave Liu __asm__ __volatile__("sync"); 3017737d5c6SDave Liu 3027737d5c6SDave Liu if (div16) { 3037737d5c6SDave Liu *bp |= QE_BRGC_DIV16; 3047737d5c6SDave Liu __asm__ __volatile__("sync"); 3057737d5c6SDave Liu } 3067737d5c6SDave Liu 3077737d5c6SDave Liu return 0; 3087737d5c6SDave Liu } 30993d33204SZhao Qiang #endif 3107737d5c6SDave Liu 3117737d5c6SDave Liu /* Set ethernet MII clock master 3127737d5c6SDave Liu */ 3137737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num) 3147737d5c6SDave Liu { 3157737d5c6SDave Liu u32 cmxgcr; 3167737d5c6SDave Liu 3177737d5c6SDave Liu /* check if the UCC number is in range. */ 3187737d5c6SDave Liu if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { 3197737d5c6SDave Liu printf("%s: ucc num not in ranges\n", __FUNCTION__); 3207737d5c6SDave Liu return -EINVAL; 3217737d5c6SDave Liu } 3227737d5c6SDave Liu 3237737d5c6SDave Liu cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); 3247737d5c6SDave Liu cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; 3257737d5c6SDave Liu cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT); 3267737d5c6SDave Liu out_be32(&qe_immr->qmx.cmxgcr, cmxgcr); 3277737d5c6SDave Liu 3287737d5c6SDave Liu return 0; 3297737d5c6SDave Liu } 3307737d5c6SDave Liu 331b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */ 332b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info; 333b8ec2385STimur Tabi 334b8ec2385STimur Tabi /* 335b8ec2385STimur Tabi * Set to 1 if QE firmware has been uploaded, and therefore 336b8ec2385STimur Tabi * qe_firmware_info contains valid data. 337b8ec2385STimur Tabi */ 338b8ec2385STimur Tabi static int qe_firmware_uploaded; 339b8ec2385STimur Tabi 340b8ec2385STimur Tabi /* 341b8ec2385STimur Tabi * Upload a QE microcode 342b8ec2385STimur Tabi * 343b8ec2385STimur Tabi * This function is a worker function for qe_upload_firmware(). It does 344b8ec2385STimur Tabi * the actual uploading of the microcode. 345b8ec2385STimur Tabi */ 346b8ec2385STimur Tabi static void qe_upload_microcode(const void *base, 347b8ec2385STimur Tabi const struct qe_microcode *ucode) 348b8ec2385STimur Tabi { 349b8ec2385STimur Tabi const u32 *code = base + be32_to_cpu(ucode->code_offset); 350b8ec2385STimur Tabi unsigned int i; 351b8ec2385STimur Tabi 352b8ec2385STimur Tabi if (ucode->major || ucode->minor || ucode->revision) 353b8ec2385STimur Tabi printf("QE: uploading microcode '%s' version %u.%u.%u\n", 354e94a8fd3SZhao Qiang (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor, 355e94a8fd3SZhao Qiang (u16)ucode->revision); 356b8ec2385STimur Tabi else 357e94a8fd3SZhao Qiang printf("QE: uploading microcode '%s'\n", (char *)ucode->id); 358b8ec2385STimur Tabi 359b8ec2385STimur Tabi /* Use auto-increment */ 360b8ec2385STimur Tabi out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | 361b8ec2385STimur Tabi QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); 362b8ec2385STimur Tabi 363b8ec2385STimur Tabi for (i = 0; i < be32_to_cpu(ucode->count); i++) 364b8ec2385STimur Tabi out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); 365b8ec2385STimur Tabi } 366b8ec2385STimur Tabi 367b8ec2385STimur Tabi /* 368b8ec2385STimur Tabi * Upload a microcode to the I-RAM at a specific address. 369b8ec2385STimur Tabi * 370b8ec2385STimur Tabi * See docs/README.qe_firmware for information on QE microcode uploading. 371b8ec2385STimur Tabi * 372b8ec2385STimur Tabi * Currently, only version 1 is supported, so the 'version' field must be 373b8ec2385STimur Tabi * set to 1. 374b8ec2385STimur Tabi * 375b8ec2385STimur Tabi * The SOC model and revision are not validated, they are only displayed for 376b8ec2385STimur Tabi * informational purposes. 377b8ec2385STimur Tabi * 378b8ec2385STimur Tabi * 'calc_size' is the calculated size, in bytes, of the firmware structure and 379b8ec2385STimur Tabi * all of the microcode structures, minus the CRC. 380b8ec2385STimur Tabi * 381b8ec2385STimur Tabi * 'length' is the size that the structure says it is, including the CRC. 382b8ec2385STimur Tabi */ 383b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware) 384b8ec2385STimur Tabi { 385b8ec2385STimur Tabi unsigned int i; 386b8ec2385STimur Tabi unsigned int j; 387b8ec2385STimur Tabi u32 crc; 388b8ec2385STimur Tabi size_t calc_size = sizeof(struct qe_firmware); 389b8ec2385STimur Tabi size_t length; 390b8ec2385STimur Tabi const struct qe_header *hdr; 391ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 39273fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A 3939c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 3949c7c86f4SZhao Qiang #else 395ca721fb2SZhao Qiang ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 396ca721fb2SZhao Qiang #endif 3979c7c86f4SZhao Qiang #endif 398b8ec2385STimur Tabi if (!firmware) { 399b8ec2385STimur Tabi printf("Invalid address\n"); 400b8ec2385STimur Tabi return -EINVAL; 401b8ec2385STimur Tabi } 402b8ec2385STimur Tabi 403b8ec2385STimur Tabi hdr = &firmware->header; 404b8ec2385STimur Tabi length = be32_to_cpu(hdr->length); 405b8ec2385STimur Tabi 406b8ec2385STimur Tabi /* Check the magic */ 407b8ec2385STimur Tabi if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 408b8ec2385STimur Tabi (hdr->magic[2] != 'F')) { 40912eeb135SVijay Rai printf("QE microcode not found\n"); 410ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 411ca721fb2SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 412ca721fb2SZhao Qiang #endif 413b8ec2385STimur Tabi return -EPERM; 414b8ec2385STimur Tabi } 415b8ec2385STimur Tabi 416b8ec2385STimur Tabi /* Check the version */ 417b8ec2385STimur Tabi if (hdr->version != 1) { 418b8ec2385STimur Tabi printf("Unsupported version\n"); 419b8ec2385STimur Tabi return -EPERM; 420b8ec2385STimur Tabi } 421b8ec2385STimur Tabi 422b8ec2385STimur Tabi /* Validate some of the fields */ 423491fb6deSTimur Tabi if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 424b8ec2385STimur Tabi printf("Invalid data\n"); 425b8ec2385STimur Tabi return -EINVAL; 426b8ec2385STimur Tabi } 427b8ec2385STimur Tabi 428b8ec2385STimur Tabi /* Validate the length and check if there's a CRC */ 429b8ec2385STimur Tabi calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 430b8ec2385STimur Tabi 431b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) 432b8ec2385STimur Tabi /* 433b8ec2385STimur Tabi * For situations where the second RISC uses the same microcode 434b8ec2385STimur Tabi * as the first, the 'code_offset' and 'count' fields will be 435b8ec2385STimur Tabi * zero, so it's okay to add those. 436b8ec2385STimur Tabi */ 437b8ec2385STimur Tabi calc_size += sizeof(u32) * 438b8ec2385STimur Tabi be32_to_cpu(firmware->microcode[i].count); 439b8ec2385STimur Tabi 440b8ec2385STimur Tabi /* Validate the length */ 441b8ec2385STimur Tabi if (length != calc_size + sizeof(u32)) { 442b8ec2385STimur Tabi printf("Invalid length\n"); 443b8ec2385STimur Tabi return -EPERM; 444b8ec2385STimur Tabi } 445b8ec2385STimur Tabi 446b8ec2385STimur Tabi /* 447b8ec2385STimur Tabi * Validate the CRC. We would normally call crc32_no_comp(), but that 448b8ec2385STimur Tabi * function isn't available unless you turn on JFFS support. 449b8ec2385STimur Tabi */ 450b8ec2385STimur Tabi crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 451b8ec2385STimur Tabi if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) { 452b8ec2385STimur Tabi printf("Firmware CRC is invalid\n"); 453b8ec2385STimur Tabi return -EIO; 454b8ec2385STimur Tabi } 455b8ec2385STimur Tabi 456b8ec2385STimur Tabi /* 457b8ec2385STimur Tabi * If the microcode calls for it, split the I-RAM. 458b8ec2385STimur Tabi */ 459b8ec2385STimur Tabi if (!firmware->split) { 460b8ec2385STimur Tabi out_be16(&qe_immr->cp.cercr, 461b8ec2385STimur Tabi in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); 462b8ec2385STimur Tabi } 463b8ec2385STimur Tabi 464b8ec2385STimur Tabi if (firmware->soc.model) 465b8ec2385STimur Tabi printf("Firmware '%s' for %u V%u.%u\n", 466b8ec2385STimur Tabi firmware->id, be16_to_cpu(firmware->soc.model), 467b8ec2385STimur Tabi firmware->soc.major, firmware->soc.minor); 468b8ec2385STimur Tabi else 469b8ec2385STimur Tabi printf("Firmware '%s'\n", firmware->id); 470b8ec2385STimur Tabi 471b8ec2385STimur Tabi /* 472b8ec2385STimur Tabi * The QE only supports one microcode per RISC, so clear out all the 473b8ec2385STimur Tabi * saved microcode information and put in the new. 474b8ec2385STimur Tabi */ 475b8ec2385STimur Tabi memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); 4760e0224eeSZhao Qiang strncpy(qe_firmware_info.id, (char *)firmware->id, 62); 477b8ec2385STimur Tabi qe_firmware_info.extended_modes = firmware->extended_modes; 478b8ec2385STimur Tabi memcpy(qe_firmware_info.vtraps, firmware->vtraps, 479b8ec2385STimur Tabi sizeof(firmware->vtraps)); 480b8ec2385STimur Tabi qe_firmware_uploaded = 1; 481b8ec2385STimur Tabi 482b8ec2385STimur Tabi /* Loop through each microcode. */ 483b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) { 484b8ec2385STimur Tabi const struct qe_microcode *ucode = &firmware->microcode[i]; 485b8ec2385STimur Tabi 486b8ec2385STimur Tabi /* Upload a microcode if it's present */ 487b8ec2385STimur Tabi if (ucode->code_offset) 488b8ec2385STimur Tabi qe_upload_microcode(firmware, ucode); 489b8ec2385STimur Tabi 490b8ec2385STimur Tabi /* Program the traps for this processor */ 491b8ec2385STimur Tabi for (j = 0; j < 16; j++) { 492b8ec2385STimur Tabi u32 trap = be32_to_cpu(ucode->traps[j]); 493b8ec2385STimur Tabi 494b8ec2385STimur Tabi if (trap) 495b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].tibcr[j], trap); 496b8ec2385STimur Tabi } 497b8ec2385STimur Tabi 498b8ec2385STimur Tabi /* Enable traps */ 499b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 500b8ec2385STimur Tabi } 501b8ec2385STimur Tabi 502b8ec2385STimur Tabi return 0; 503b8ec2385STimur Tabi } 504b8ec2385STimur Tabi 5055632d15cSZhao Qiang #ifdef CONFIG_U_QE 5065632d15cSZhao Qiang /* 5075632d15cSZhao Qiang * Upload a microcode to the I-RAM at a specific address. 5085632d15cSZhao Qiang * 5095632d15cSZhao Qiang * See docs/README.qe_firmware for information on QE microcode uploading. 5105632d15cSZhao Qiang * 5115632d15cSZhao Qiang * Currently, only version 1 is supported, so the 'version' field must be 5125632d15cSZhao Qiang * set to 1. 5135632d15cSZhao Qiang * 5145632d15cSZhao Qiang * The SOC model and revision are not validated, they are only displayed for 5155632d15cSZhao Qiang * informational purposes. 5165632d15cSZhao Qiang * 5175632d15cSZhao Qiang * 'calc_size' is the calculated size, in bytes, of the firmware structure and 5185632d15cSZhao Qiang * all of the microcode structures, minus the CRC. 5195632d15cSZhao Qiang * 5205632d15cSZhao Qiang * 'length' is the size that the structure says it is, including the CRC. 5215632d15cSZhao Qiang */ 5225632d15cSZhao Qiang int u_qe_upload_firmware(const struct qe_firmware *firmware) 5235632d15cSZhao Qiang { 5245632d15cSZhao Qiang unsigned int i; 5255632d15cSZhao Qiang unsigned int j; 5265632d15cSZhao Qiang u32 crc; 5275632d15cSZhao Qiang size_t calc_size = sizeof(struct qe_firmware); 5285632d15cSZhao Qiang size_t length; 5295632d15cSZhao Qiang const struct qe_header *hdr; 5305632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP 53173fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A 5329c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 5339c7c86f4SZhao Qiang #else 5345632d15cSZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 5355632d15cSZhao Qiang #endif 5369c7c86f4SZhao Qiang #endif 5375632d15cSZhao Qiang if (!firmware) { 5385632d15cSZhao Qiang printf("Invalid address\n"); 5395632d15cSZhao Qiang return -EINVAL; 5405632d15cSZhao Qiang } 5415632d15cSZhao Qiang 5425632d15cSZhao Qiang hdr = &firmware->header; 5435632d15cSZhao Qiang length = be32_to_cpu(hdr->length); 5445632d15cSZhao Qiang 5455632d15cSZhao Qiang /* Check the magic */ 5465632d15cSZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 5475632d15cSZhao Qiang (hdr->magic[2] != 'F')) { 5485632d15cSZhao Qiang printf("Not a microcode\n"); 5495632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP 5505632d15cSZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 5515632d15cSZhao Qiang #endif 5525632d15cSZhao Qiang return -EPERM; 5535632d15cSZhao Qiang } 5545632d15cSZhao Qiang 5555632d15cSZhao Qiang /* Check the version */ 5565632d15cSZhao Qiang if (hdr->version != 1) { 5575632d15cSZhao Qiang printf("Unsupported version\n"); 5585632d15cSZhao Qiang return -EPERM; 5595632d15cSZhao Qiang } 5605632d15cSZhao Qiang 5615632d15cSZhao Qiang /* Validate some of the fields */ 5625632d15cSZhao Qiang if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 5635632d15cSZhao Qiang printf("Invalid data\n"); 5645632d15cSZhao Qiang return -EINVAL; 5655632d15cSZhao Qiang } 5665632d15cSZhao Qiang 5675632d15cSZhao Qiang /* Validate the length and check if there's a CRC */ 5685632d15cSZhao Qiang calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 5695632d15cSZhao Qiang 5705632d15cSZhao Qiang for (i = 0; i < firmware->count; i++) 5715632d15cSZhao Qiang /* 5725632d15cSZhao Qiang * For situations where the second RISC uses the same microcode 5735632d15cSZhao Qiang * as the first, the 'code_offset' and 'count' fields will be 5745632d15cSZhao Qiang * zero, so it's okay to add those. 5755632d15cSZhao Qiang */ 5765632d15cSZhao Qiang calc_size += sizeof(u32) * 5775632d15cSZhao Qiang be32_to_cpu(firmware->microcode[i].count); 5785632d15cSZhao Qiang 5795632d15cSZhao Qiang /* Validate the length */ 5805632d15cSZhao Qiang if (length != calc_size + sizeof(u32)) { 5815632d15cSZhao Qiang printf("Invalid length\n"); 5825632d15cSZhao Qiang return -EPERM; 5835632d15cSZhao Qiang } 5845632d15cSZhao Qiang 5855632d15cSZhao Qiang /* 5865632d15cSZhao Qiang * Validate the CRC. We would normally call crc32_no_comp(), but that 5875632d15cSZhao Qiang * function isn't available unless you turn on JFFS support. 5885632d15cSZhao Qiang */ 5895632d15cSZhao Qiang crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 5905632d15cSZhao Qiang if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { 5915632d15cSZhao Qiang printf("Firmware CRC is invalid\n"); 5925632d15cSZhao Qiang return -EIO; 5935632d15cSZhao Qiang } 5945632d15cSZhao Qiang 5955632d15cSZhao Qiang /* 5965632d15cSZhao Qiang * If the microcode calls for it, split the I-RAM. 5975632d15cSZhao Qiang */ 5985632d15cSZhao Qiang if (!firmware->split) { 5995632d15cSZhao Qiang out_be16(&qe_immr->cp.cercr, 6005632d15cSZhao Qiang in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); 6015632d15cSZhao Qiang } 6025632d15cSZhao Qiang 6035632d15cSZhao Qiang if (firmware->soc.model) 6045632d15cSZhao Qiang printf("Firmware '%s' for %u V%u.%u\n", 6055632d15cSZhao Qiang firmware->id, be16_to_cpu(firmware->soc.model), 6065632d15cSZhao Qiang firmware->soc.major, firmware->soc.minor); 6075632d15cSZhao Qiang else 6085632d15cSZhao Qiang printf("Firmware '%s'\n", firmware->id); 6095632d15cSZhao Qiang 6105632d15cSZhao Qiang /* Loop through each microcode. */ 6115632d15cSZhao Qiang for (i = 0; i < firmware->count; i++) { 6125632d15cSZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i]; 6135632d15cSZhao Qiang 6145632d15cSZhao Qiang /* Upload a microcode if it's present */ 6155632d15cSZhao Qiang if (ucode->code_offset) 6165632d15cSZhao Qiang qe_upload_microcode(firmware, ucode); 6175632d15cSZhao Qiang 6185632d15cSZhao Qiang /* Program the traps for this processor */ 6195632d15cSZhao Qiang for (j = 0; j < 16; j++) { 6205632d15cSZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]); 6215632d15cSZhao Qiang 6225632d15cSZhao Qiang if (trap) 6235632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].tibcr[j], trap); 6245632d15cSZhao Qiang } 6255632d15cSZhao Qiang 6265632d15cSZhao Qiang /* Enable traps */ 6275632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 6285632d15cSZhao Qiang } 6295632d15cSZhao Qiang 6305632d15cSZhao Qiang return 0; 6315632d15cSZhao Qiang } 6325632d15cSZhao Qiang #endif 6335632d15cSZhao Qiang 634ae42eb03SZhao Qiang #ifdef CONFIG_U_QE 635ae42eb03SZhao Qiang int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr) 636ae42eb03SZhao Qiang { 637ae42eb03SZhao Qiang unsigned int i; 638ae42eb03SZhao Qiang unsigned int j; 639ae42eb03SZhao Qiang const struct qe_header *hdr; 640ae42eb03SZhao Qiang const u32 *code; 641ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 642ae42eb03SZhao Qiang #ifdef CONFIG_PPC 643ae42eb03SZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 644ae42eb03SZhao Qiang #else 645ae42eb03SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 646ae42eb03SZhao Qiang #endif 647ae42eb03SZhao Qiang #endif 648ae42eb03SZhao Qiang 649ae42eb03SZhao Qiang if (!firmware) 650ae42eb03SZhao Qiang return -EINVAL; 651ae42eb03SZhao Qiang 652ae42eb03SZhao Qiang hdr = &firmware->header; 653ae42eb03SZhao Qiang 654ae42eb03SZhao Qiang /* Check the magic */ 655ae42eb03SZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 656ae42eb03SZhao Qiang (hdr->magic[2] != 'F')) { 657ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 658ae42eb03SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 659ae42eb03SZhao Qiang #endif 660ae42eb03SZhao Qiang return -EPERM; 661ae42eb03SZhao Qiang } 662ae42eb03SZhao Qiang 663ae42eb03SZhao Qiang /* 664ae42eb03SZhao Qiang * If the microcode calls for it, split the I-RAM. 665ae42eb03SZhao Qiang */ 666ae42eb03SZhao Qiang if (!firmware->split) { 667ae42eb03SZhao Qiang out_be16(&qe_immrr->cp.cercr, 668ae42eb03SZhao Qiang in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR); 669ae42eb03SZhao Qiang } 670ae42eb03SZhao Qiang 671ae42eb03SZhao Qiang /* Loop through each microcode. */ 672ae42eb03SZhao Qiang for (i = 0; i < firmware->count; i++) { 673ae42eb03SZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i]; 674ae42eb03SZhao Qiang 675ae42eb03SZhao Qiang /* Upload a microcode if it's present */ 676ae42eb03SZhao Qiang if (!ucode->code_offset) 677ae42eb03SZhao Qiang return 0; 678ae42eb03SZhao Qiang 679ae42eb03SZhao Qiang code = (const void *)firmware + be32_to_cpu(ucode->code_offset); 680ae42eb03SZhao Qiang 681ae42eb03SZhao Qiang /* Use auto-increment */ 682ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) | 683ae42eb03SZhao Qiang QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); 684ae42eb03SZhao Qiang 685ae42eb03SZhao Qiang for (i = 0; i < be32_to_cpu(ucode->count); i++) 686ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i])); 687ae42eb03SZhao Qiang 688ae42eb03SZhao Qiang /* Program the traps for this processor */ 689ae42eb03SZhao Qiang for (j = 0; j < 16; j++) { 690ae42eb03SZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]); 691ae42eb03SZhao Qiang 692ae42eb03SZhao Qiang if (trap) 693ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].tibcr[j], trap); 694ae42eb03SZhao Qiang } 695ae42eb03SZhao Qiang 696ae42eb03SZhao Qiang /* Enable traps */ 697ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 698ae42eb03SZhao Qiang } 699ae42eb03SZhao Qiang 700ae42eb03SZhao Qiang return 0; 701ae42eb03SZhao Qiang } 702ae42eb03SZhao Qiang #endif 703ae42eb03SZhao Qiang 704b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void) 705b8ec2385STimur Tabi { 706b8ec2385STimur Tabi return qe_firmware_uploaded ? &qe_firmware_info : NULL; 707b8ec2385STimur Tabi } 708b8ec2385STimur Tabi 70954841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 710b8ec2385STimur Tabi { 711b8ec2385STimur Tabi ulong addr; 712b8ec2385STimur Tabi 71347e26b1bSWolfgang Denk if (argc < 3) 71447e26b1bSWolfgang Denk return cmd_usage(cmdtp); 715b8ec2385STimur Tabi 716b8ec2385STimur Tabi if (strcmp(argv[1], "fw") == 0) { 717b8ec2385STimur Tabi addr = simple_strtoul(argv[2], NULL, 16); 718b8ec2385STimur Tabi 719b8ec2385STimur Tabi if (!addr) { 720b8ec2385STimur Tabi printf("Invalid address\n"); 721b8ec2385STimur Tabi return -EINVAL; 722b8ec2385STimur Tabi } 723b8ec2385STimur Tabi 724b8ec2385STimur Tabi /* 725b8ec2385STimur Tabi * If a length was supplied, compare that with the 'length' 726b8ec2385STimur Tabi * field. 727b8ec2385STimur Tabi */ 728b8ec2385STimur Tabi 729b8ec2385STimur Tabi if (argc > 3) { 730b8ec2385STimur Tabi ulong length = simple_strtoul(argv[3], NULL, 16); 731b8ec2385STimur Tabi struct qe_firmware *firmware = (void *) addr; 732b8ec2385STimur Tabi 733b8ec2385STimur Tabi if (length != be32_to_cpu(firmware->header.length)) { 734b8ec2385STimur Tabi printf("Length mismatch\n"); 735b8ec2385STimur Tabi return -EINVAL; 736b8ec2385STimur Tabi } 737b8ec2385STimur Tabi } 738b8ec2385STimur Tabi 739b8ec2385STimur Tabi return qe_upload_firmware((const struct qe_firmware *) addr); 740b8ec2385STimur Tabi } 741b8ec2385STimur Tabi 74247e26b1bSWolfgang Denk return cmd_usage(cmdtp); 743b8ec2385STimur Tabi } 744b8ec2385STimur Tabi 745b8ec2385STimur Tabi U_BOOT_CMD( 746b8ec2385STimur Tabi qe, 4, 0, qe_cmd, 7472fb2604dSPeter Tyser "QUICC Engine commands", 748b8ec2385STimur Tabi "fw <addr> [<length>] - Upload firmware binary at address <addr> to " 749a89c33dbSWolfgang Denk "the QE,\n" 750a89c33dbSWolfgang Denk "\twith optional length <length> verification." 751b8ec2385STimur Tabi ); 752