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 107737d5c6SDave Liu #include "common.h" 11b8ec2385STimur Tabi #include <command.h> 127737d5c6SDave Liu #include "asm/errno.h" 137737d5c6SDave Liu #include "asm/io.h" 1438d67a4eSZhao Qiang #include "linux/immap_qe.h" 152459afb1SQianyu Gong #include <fsl_qe.h> 169c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA 179c7c86f4SZhao Qiang #include <asm/arch/immap_ls102xa.h> 189c7c86f4SZhao Qiang #endif 197737d5c6SDave Liu 20ca721fb2SZhao Qiang #define MPC85xx_DEVDISR_QE_DISABLE 0x1 21ca721fb2SZhao Qiang 227737d5c6SDave Liu qe_map_t *qe_immr = NULL; 233bf46e6aSZhao Qiang #ifdef CONFIG_QE 247737d5c6SDave Liu static qe_snum_t snums[QE_NUM_OF_SNUM]; 253bf46e6aSZhao Qiang #endif 267737d5c6SDave Liu 271218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR; 281218abf1SWolfgang Denk 297737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) 307737d5c6SDave Liu { 317737d5c6SDave Liu u32 cecr; 327737d5c6SDave Liu 337737d5c6SDave Liu if (cmd == QE_RESET) { 347737d5c6SDave Liu out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); 357737d5c6SDave Liu } else { 367737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, cmd_data); 377737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | 387737d5c6SDave Liu ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd)); 397737d5c6SDave Liu } 407737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 417737d5c6SDave Liu do { 427737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 437737d5c6SDave Liu } while (cecr & QE_CR_FLG); 447737d5c6SDave Liu 457737d5c6SDave Liu return; 467737d5c6SDave Liu } 477737d5c6SDave Liu 4893d33204SZhao Qiang #ifdef CONFIG_QE 497737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align) 507737d5c6SDave Liu { 517737d5c6SDave Liu uint retloc; 527737d5c6SDave Liu uint align_mask, off; 537737d5c6SDave Liu uint savebase; 547737d5c6SDave Liu 557737d5c6SDave Liu align_mask = align - 1; 5645bae2e3SSimon Glass savebase = gd->arch.mp_alloc_base; 577737d5c6SDave Liu 5845bae2e3SSimon Glass off = gd->arch.mp_alloc_base & align_mask; 5945bae2e3SSimon Glass if (off != 0) 6045bae2e3SSimon Glass gd->arch.mp_alloc_base += (align - off); 617737d5c6SDave Liu 627737d5c6SDave Liu if ((off = size & align_mask) != 0) 637737d5c6SDave Liu size += (align - off); 647737d5c6SDave Liu 6545bae2e3SSimon Glass if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) { 6645bae2e3SSimon Glass gd->arch.mp_alloc_base = savebase; 677737d5c6SDave Liu printf("%s: ran out of ram.\n", __FUNCTION__); 687737d5c6SDave Liu } 697737d5c6SDave Liu 7045bae2e3SSimon Glass retloc = gd->arch.mp_alloc_base; 7145bae2e3SSimon Glass gd->arch.mp_alloc_base += size; 727737d5c6SDave Liu 737737d5c6SDave Liu memset((void *)&qe_immr->muram[retloc], 0, size); 747737d5c6SDave Liu 757737d5c6SDave Liu __asm__ __volatile__("sync"); 767737d5c6SDave Liu 777737d5c6SDave Liu return retloc; 787737d5c6SDave Liu } 7993d33204SZhao Qiang #endif 807737d5c6SDave Liu 817737d5c6SDave Liu void *qe_muram_addr(uint offset) 827737d5c6SDave Liu { 837737d5c6SDave Liu return (void *)&qe_immr->muram[offset]; 847737d5c6SDave Liu } 857737d5c6SDave Liu 863bf46e6aSZhao Qiang #ifdef CONFIG_QE 877737d5c6SDave Liu static void qe_sdma_init(void) 887737d5c6SDave Liu { 897737d5c6SDave Liu volatile sdma_t *p; 907737d5c6SDave Liu uint sdma_buffer_base; 917737d5c6SDave Liu 927737d5c6SDave Liu p = (volatile sdma_t *)&qe_immr->sdma; 937737d5c6SDave Liu 947737d5c6SDave Liu /* All of DMA transaction in bus 1 */ 957737d5c6SDave Liu out_be32(&p->sdaqr, 0); 967737d5c6SDave Liu out_be32(&p->sdaqmr, 0); 977737d5c6SDave Liu 987737d5c6SDave Liu /* Allocate 2KB temporary buffer for sdma */ 99ff9658d7SDave Liu sdma_buffer_base = qe_muram_alloc(2048, 4096); 1007737d5c6SDave Liu out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); 1017737d5c6SDave Liu 1027737d5c6SDave Liu /* Clear sdma status */ 1037737d5c6SDave Liu out_be32(&p->sdsr, 0x03000000); 1047737d5c6SDave Liu 1057737d5c6SDave Liu /* Enable global mode on bus 1, and 2KB buffer size */ 1067737d5c6SDave Liu out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT)); 1077737d5c6SDave Liu } 1087737d5c6SDave Liu 1094e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the 1104e7b25e4SHaiying Wang * "SNUM Table" chart in the QE Reference Manual. The order is not important, 1114e7b25e4SHaiying Wang * we just need to know what the SNUMs are for the threads. 1124e7b25e4SHaiying Wang */ 1134e7b25e4SHaiying Wang static u8 thread_snum[] = { 114a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */ 115a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309) 1167737d5c6SDave Liu 0x04, 0x05, 0x0c, 0x0d, 1177737d5c6SDave Liu 0x14, 0x15, 0x1c, 0x1d, 1187737d5c6SDave Liu 0x24, 0x25, 0x2c, 0x2d, 119a88731a6SGerlando Falauto 0x34, 0x35, 120a88731a6SGerlando Falauto #endif 121a88731a6SGerlando Falauto 0x88, 0x89, 0x98, 0x99, 122a88731a6SGerlando Falauto 0xa8, 0xa9, 0xb8, 0xb9, 123a88731a6SGerlando Falauto 0xc8, 0xc9, 0xd8, 0xd9, 124a88731a6SGerlando Falauto 0xe8, 0xe9, 0x08, 0x09, 125a88731a6SGerlando Falauto 0x18, 0x19, 0x28, 0x29, 126a88731a6SGerlando Falauto 0x38, 0x39, 0x48, 0x49, 127a88731a6SGerlando Falauto 0x58, 0x59, 0x68, 0x69, 128a88731a6SGerlando Falauto 0x78, 0x79, 0x80, 0x81 1297737d5c6SDave Liu }; 1307737d5c6SDave Liu 1317737d5c6SDave Liu static void qe_snums_init(void) 1327737d5c6SDave Liu { 1337737d5c6SDave Liu int i; 1347737d5c6SDave Liu 1357737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1367737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1377737d5c6SDave Liu snums[i].num = thread_snum[i]; 1387737d5c6SDave Liu } 1397737d5c6SDave Liu } 1407737d5c6SDave Liu 1417737d5c6SDave Liu int qe_get_snum(void) 1427737d5c6SDave Liu { 1437737d5c6SDave Liu int snum = -EBUSY; 1447737d5c6SDave Liu int i; 1457737d5c6SDave Liu 1467737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1477737d5c6SDave Liu if (snums[i].state == QE_SNUM_STATE_FREE) { 1487737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_USED; 1497737d5c6SDave Liu snum = snums[i].num; 1507737d5c6SDave Liu break; 1517737d5c6SDave Liu } 1527737d5c6SDave Liu } 1537737d5c6SDave Liu 1547737d5c6SDave Liu return snum; 1557737d5c6SDave Liu } 1567737d5c6SDave Liu 1577737d5c6SDave Liu void qe_put_snum(u8 snum) 1587737d5c6SDave Liu { 1597737d5c6SDave Liu int i; 1607737d5c6SDave Liu 1617737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1627737d5c6SDave Liu if (snums[i].num == snum) { 1637737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1647737d5c6SDave Liu break; 1657737d5c6SDave Liu } 1667737d5c6SDave Liu } 1677737d5c6SDave Liu } 1687737d5c6SDave Liu 1697737d5c6SDave Liu void qe_init(uint qe_base) 1707737d5c6SDave Liu { 1717737d5c6SDave Liu /* Init the QE IMMR base */ 1727737d5c6SDave Liu qe_immr = (qe_map_t *)qe_base; 1737737d5c6SDave Liu 174f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR 175c0a14aedSWolfgang Denk /* 176c0a14aedSWolfgang Denk * Upload microcode to IRAM for those SOCs which do not have ROM in QE. 1772d4de6aeSHaiying Wang */ 178dcf1d774SZhao Qiang qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); 1792d4de6aeSHaiying Wang 1802d4de6aeSHaiying Wang /* enable the microcode in IRAM */ 1812d4de6aeSHaiying Wang out_be32(&qe_immr->iram.iready,QE_IRAM_READY); 1822d4de6aeSHaiying Wang #endif 1832d4de6aeSHaiying Wang 18445bae2e3SSimon Glass gd->arch.mp_alloc_base = QE_DATAONLY_BASE; 18545bae2e3SSimon Glass gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE; 1867737d5c6SDave Liu 1877737d5c6SDave Liu qe_sdma_init(); 1887737d5c6SDave Liu qe_snums_init(); 1897737d5c6SDave Liu } 1903bf46e6aSZhao Qiang #endif 1917737d5c6SDave Liu 19293d33204SZhao Qiang #ifdef CONFIG_U_QE 19393d33204SZhao Qiang void u_qe_init(void) 19493d33204SZhao Qiang { 195*d3e6d30cSZhao Qiang qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); 19693d33204SZhao Qiang 1975632d15cSZhao Qiang u_qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR); 19893d33204SZhao Qiang out_be32(&qe_immr->iram.iready, QE_IRAM_READY); 19993d33204SZhao Qiang } 20093d33204SZhao Qiang #endif 20193d33204SZhao Qiang 202ae42eb03SZhao Qiang #ifdef CONFIG_U_QE 203ae42eb03SZhao Qiang void u_qe_resume(void) 204ae42eb03SZhao Qiang { 205ae42eb03SZhao Qiang qe_map_t *qe_immrr; 206ae42eb03SZhao Qiang 207*d3e6d30cSZhao Qiang qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET); 208ae42eb03SZhao Qiang u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr); 209ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iready, QE_IRAM_READY); 210ae42eb03SZhao Qiang } 211ae42eb03SZhao Qiang #endif 212ae42eb03SZhao Qiang 2137737d5c6SDave Liu void qe_reset(void) 2147737d5c6SDave Liu { 2157737d5c6SDave Liu qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, 2167737d5c6SDave Liu (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); 2177737d5c6SDave Liu } 2187737d5c6SDave Liu 2193bf46e6aSZhao Qiang #ifdef CONFIG_QE 2207737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base) 2217737d5c6SDave Liu { 2227737d5c6SDave Liu u32 cecr; 2237737d5c6SDave Liu 2247737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, para_ram_base); 2257737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT) 2267737d5c6SDave Liu | QE_CR_FLG | QE_ASSIGN_PAGE); 2277737d5c6SDave Liu 2287737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 2297737d5c6SDave Liu do { 2307737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 2317737d5c6SDave Liu } while (cecr & QE_CR_FLG ); 2327737d5c6SDave Liu 2337737d5c6SDave Liu return; 2347737d5c6SDave Liu } 2353bf46e6aSZhao Qiang #endif 2367737d5c6SDave Liu 2377737d5c6SDave Liu /* 2387737d5c6SDave Liu * brg: 0~15 as BRG1~BRG16 2397737d5c6SDave Liu rate: baud rate 2407737d5c6SDave Liu * BRG input clock comes from the BRGCLK (internal clock generated from 2417737d5c6SDave Liu the QE clock, it is one-half of the QE clock), If need the clock source 2427737d5c6SDave Liu from CLKn pin, we have te change the function. 2437737d5c6SDave Liu */ 2447737d5c6SDave Liu 2451206c184SSimon Glass #define BRG_CLK (gd->arch.brg_clk) 2467737d5c6SDave Liu 24793d33204SZhao Qiang #ifdef CONFIG_QE 2487737d5c6SDave Liu int qe_set_brg(uint brg, uint rate) 2497737d5c6SDave Liu { 2507737d5c6SDave Liu volatile uint *bp; 2517737d5c6SDave Liu u32 divisor; 2527737d5c6SDave Liu int div16 = 0; 2537737d5c6SDave Liu 2547737d5c6SDave Liu if (brg >= QE_NUM_OF_BRGS) 2557737d5c6SDave Liu return -EINVAL; 2567737d5c6SDave Liu bp = (uint *)&qe_immr->brg.brgc1; 2577737d5c6SDave Liu bp += brg; 2587737d5c6SDave Liu 2597737d5c6SDave Liu divisor = (BRG_CLK / rate); 2607737d5c6SDave Liu if (divisor > QE_BRGC_DIVISOR_MAX + 1) { 2617737d5c6SDave Liu div16 = 1; 2627737d5c6SDave Liu divisor /= 16; 2637737d5c6SDave Liu } 2647737d5c6SDave Liu 2657737d5c6SDave Liu *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; 2667737d5c6SDave Liu __asm__ __volatile__("sync"); 2677737d5c6SDave Liu 2687737d5c6SDave Liu if (div16) { 2697737d5c6SDave Liu *bp |= QE_BRGC_DIV16; 2707737d5c6SDave Liu __asm__ __volatile__("sync"); 2717737d5c6SDave Liu } 2727737d5c6SDave Liu 2737737d5c6SDave Liu return 0; 2747737d5c6SDave Liu } 27593d33204SZhao Qiang #endif 2767737d5c6SDave Liu 2777737d5c6SDave Liu /* Set ethernet MII clock master 2787737d5c6SDave Liu */ 2797737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num) 2807737d5c6SDave Liu { 2817737d5c6SDave Liu u32 cmxgcr; 2827737d5c6SDave Liu 2837737d5c6SDave Liu /* check if the UCC number is in range. */ 2847737d5c6SDave Liu if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { 2857737d5c6SDave Liu printf("%s: ucc num not in ranges\n", __FUNCTION__); 2867737d5c6SDave Liu return -EINVAL; 2877737d5c6SDave Liu } 2887737d5c6SDave Liu 2897737d5c6SDave Liu cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); 2907737d5c6SDave Liu cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; 2917737d5c6SDave Liu cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT); 2927737d5c6SDave Liu out_be32(&qe_immr->qmx.cmxgcr, cmxgcr); 2937737d5c6SDave Liu 2947737d5c6SDave Liu return 0; 2957737d5c6SDave Liu } 2967737d5c6SDave Liu 297b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */ 298b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info; 299b8ec2385STimur Tabi 300b8ec2385STimur Tabi /* 301b8ec2385STimur Tabi * Set to 1 if QE firmware has been uploaded, and therefore 302b8ec2385STimur Tabi * qe_firmware_info contains valid data. 303b8ec2385STimur Tabi */ 304b8ec2385STimur Tabi static int qe_firmware_uploaded; 305b8ec2385STimur Tabi 306b8ec2385STimur Tabi /* 307b8ec2385STimur Tabi * Upload a QE microcode 308b8ec2385STimur Tabi * 309b8ec2385STimur Tabi * This function is a worker function for qe_upload_firmware(). It does 310b8ec2385STimur Tabi * the actual uploading of the microcode. 311b8ec2385STimur Tabi */ 312b8ec2385STimur Tabi static void qe_upload_microcode(const void *base, 313b8ec2385STimur Tabi const struct qe_microcode *ucode) 314b8ec2385STimur Tabi { 315b8ec2385STimur Tabi const u32 *code = base + be32_to_cpu(ucode->code_offset); 316b8ec2385STimur Tabi unsigned int i; 317b8ec2385STimur Tabi 318b8ec2385STimur Tabi if (ucode->major || ucode->minor || ucode->revision) 319b8ec2385STimur Tabi printf("QE: uploading microcode '%s' version %u.%u.%u\n", 320e94a8fd3SZhao Qiang (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor, 321e94a8fd3SZhao Qiang (u16)ucode->revision); 322b8ec2385STimur Tabi else 323e94a8fd3SZhao Qiang printf("QE: uploading microcode '%s'\n", (char *)ucode->id); 324b8ec2385STimur Tabi 325b8ec2385STimur Tabi /* Use auto-increment */ 326b8ec2385STimur Tabi out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | 327b8ec2385STimur Tabi QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); 328b8ec2385STimur Tabi 329b8ec2385STimur Tabi for (i = 0; i < be32_to_cpu(ucode->count); i++) 330b8ec2385STimur Tabi out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); 331b8ec2385STimur Tabi } 332b8ec2385STimur Tabi 333b8ec2385STimur Tabi /* 334b8ec2385STimur Tabi * Upload a microcode to the I-RAM at a specific address. 335b8ec2385STimur Tabi * 336b8ec2385STimur Tabi * See docs/README.qe_firmware for information on QE microcode uploading. 337b8ec2385STimur Tabi * 338b8ec2385STimur Tabi * Currently, only version 1 is supported, so the 'version' field must be 339b8ec2385STimur Tabi * set to 1. 340b8ec2385STimur Tabi * 341b8ec2385STimur Tabi * The SOC model and revision are not validated, they are only displayed for 342b8ec2385STimur Tabi * informational purposes. 343b8ec2385STimur Tabi * 344b8ec2385STimur Tabi * 'calc_size' is the calculated size, in bytes, of the firmware structure and 345b8ec2385STimur Tabi * all of the microcode structures, minus the CRC. 346b8ec2385STimur Tabi * 347b8ec2385STimur Tabi * 'length' is the size that the structure says it is, including the CRC. 348b8ec2385STimur Tabi */ 349b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware) 350b8ec2385STimur Tabi { 351b8ec2385STimur Tabi unsigned int i; 352b8ec2385STimur Tabi unsigned int j; 353b8ec2385STimur Tabi u32 crc; 354b8ec2385STimur Tabi size_t calc_size = sizeof(struct qe_firmware); 355b8ec2385STimur Tabi size_t length; 356b8ec2385STimur Tabi const struct qe_header *hdr; 357ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 3589c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA 3599c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 3609c7c86f4SZhao Qiang #else 361ca721fb2SZhao Qiang ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 362ca721fb2SZhao Qiang #endif 3639c7c86f4SZhao Qiang #endif 364b8ec2385STimur Tabi if (!firmware) { 365b8ec2385STimur Tabi printf("Invalid address\n"); 366b8ec2385STimur Tabi return -EINVAL; 367b8ec2385STimur Tabi } 368b8ec2385STimur Tabi 369b8ec2385STimur Tabi hdr = &firmware->header; 370b8ec2385STimur Tabi length = be32_to_cpu(hdr->length); 371b8ec2385STimur Tabi 372b8ec2385STimur Tabi /* Check the magic */ 373b8ec2385STimur Tabi if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 374b8ec2385STimur Tabi (hdr->magic[2] != 'F')) { 37512eeb135SVijay Rai printf("QE microcode not found\n"); 376ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 377ca721fb2SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 378ca721fb2SZhao Qiang #endif 379b8ec2385STimur Tabi return -EPERM; 380b8ec2385STimur Tabi } 381b8ec2385STimur Tabi 382b8ec2385STimur Tabi /* Check the version */ 383b8ec2385STimur Tabi if (hdr->version != 1) { 384b8ec2385STimur Tabi printf("Unsupported version\n"); 385b8ec2385STimur Tabi return -EPERM; 386b8ec2385STimur Tabi } 387b8ec2385STimur Tabi 388b8ec2385STimur Tabi /* Validate some of the fields */ 389491fb6deSTimur Tabi if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 390b8ec2385STimur Tabi printf("Invalid data\n"); 391b8ec2385STimur Tabi return -EINVAL; 392b8ec2385STimur Tabi } 393b8ec2385STimur Tabi 394b8ec2385STimur Tabi /* Validate the length and check if there's a CRC */ 395b8ec2385STimur Tabi calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 396b8ec2385STimur Tabi 397b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) 398b8ec2385STimur Tabi /* 399b8ec2385STimur Tabi * For situations where the second RISC uses the same microcode 400b8ec2385STimur Tabi * as the first, the 'code_offset' and 'count' fields will be 401b8ec2385STimur Tabi * zero, so it's okay to add those. 402b8ec2385STimur Tabi */ 403b8ec2385STimur Tabi calc_size += sizeof(u32) * 404b8ec2385STimur Tabi be32_to_cpu(firmware->microcode[i].count); 405b8ec2385STimur Tabi 406b8ec2385STimur Tabi /* Validate the length */ 407b8ec2385STimur Tabi if (length != calc_size + sizeof(u32)) { 408b8ec2385STimur Tabi printf("Invalid length\n"); 409b8ec2385STimur Tabi return -EPERM; 410b8ec2385STimur Tabi } 411b8ec2385STimur Tabi 412b8ec2385STimur Tabi /* 413b8ec2385STimur Tabi * Validate the CRC. We would normally call crc32_no_comp(), but that 414b8ec2385STimur Tabi * function isn't available unless you turn on JFFS support. 415b8ec2385STimur Tabi */ 416b8ec2385STimur Tabi crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 417b8ec2385STimur Tabi if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) { 418b8ec2385STimur Tabi printf("Firmware CRC is invalid\n"); 419b8ec2385STimur Tabi return -EIO; 420b8ec2385STimur Tabi } 421b8ec2385STimur Tabi 422b8ec2385STimur Tabi /* 423b8ec2385STimur Tabi * If the microcode calls for it, split the I-RAM. 424b8ec2385STimur Tabi */ 425b8ec2385STimur Tabi if (!firmware->split) { 426b8ec2385STimur Tabi out_be16(&qe_immr->cp.cercr, 427b8ec2385STimur Tabi in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); 428b8ec2385STimur Tabi } 429b8ec2385STimur Tabi 430b8ec2385STimur Tabi if (firmware->soc.model) 431b8ec2385STimur Tabi printf("Firmware '%s' for %u V%u.%u\n", 432b8ec2385STimur Tabi firmware->id, be16_to_cpu(firmware->soc.model), 433b8ec2385STimur Tabi firmware->soc.major, firmware->soc.minor); 434b8ec2385STimur Tabi else 435b8ec2385STimur Tabi printf("Firmware '%s'\n", firmware->id); 436b8ec2385STimur Tabi 437b8ec2385STimur Tabi /* 438b8ec2385STimur Tabi * The QE only supports one microcode per RISC, so clear out all the 439b8ec2385STimur Tabi * saved microcode information and put in the new. 440b8ec2385STimur Tabi */ 441b8ec2385STimur Tabi memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); 4420e0224eeSZhao Qiang strncpy(qe_firmware_info.id, (char *)firmware->id, 62); 443b8ec2385STimur Tabi qe_firmware_info.extended_modes = firmware->extended_modes; 444b8ec2385STimur Tabi memcpy(qe_firmware_info.vtraps, firmware->vtraps, 445b8ec2385STimur Tabi sizeof(firmware->vtraps)); 446b8ec2385STimur Tabi qe_firmware_uploaded = 1; 447b8ec2385STimur Tabi 448b8ec2385STimur Tabi /* Loop through each microcode. */ 449b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) { 450b8ec2385STimur Tabi const struct qe_microcode *ucode = &firmware->microcode[i]; 451b8ec2385STimur Tabi 452b8ec2385STimur Tabi /* Upload a microcode if it's present */ 453b8ec2385STimur Tabi if (ucode->code_offset) 454b8ec2385STimur Tabi qe_upload_microcode(firmware, ucode); 455b8ec2385STimur Tabi 456b8ec2385STimur Tabi /* Program the traps for this processor */ 457b8ec2385STimur Tabi for (j = 0; j < 16; j++) { 458b8ec2385STimur Tabi u32 trap = be32_to_cpu(ucode->traps[j]); 459b8ec2385STimur Tabi 460b8ec2385STimur Tabi if (trap) 461b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].tibcr[j], trap); 462b8ec2385STimur Tabi } 463b8ec2385STimur Tabi 464b8ec2385STimur Tabi /* Enable traps */ 465b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 466b8ec2385STimur Tabi } 467b8ec2385STimur Tabi 468b8ec2385STimur Tabi return 0; 469b8ec2385STimur Tabi } 470b8ec2385STimur Tabi 4715632d15cSZhao Qiang #ifdef CONFIG_U_QE 4725632d15cSZhao Qiang /* 4735632d15cSZhao Qiang * Upload a microcode to the I-RAM at a specific address. 4745632d15cSZhao Qiang * 4755632d15cSZhao Qiang * See docs/README.qe_firmware for information on QE microcode uploading. 4765632d15cSZhao Qiang * 4775632d15cSZhao Qiang * Currently, only version 1 is supported, so the 'version' field must be 4785632d15cSZhao Qiang * set to 1. 4795632d15cSZhao Qiang * 4805632d15cSZhao Qiang * The SOC model and revision are not validated, they are only displayed for 4815632d15cSZhao Qiang * informational purposes. 4825632d15cSZhao Qiang * 4835632d15cSZhao Qiang * 'calc_size' is the calculated size, in bytes, of the firmware structure and 4845632d15cSZhao Qiang * all of the microcode structures, minus the CRC. 4855632d15cSZhao Qiang * 4865632d15cSZhao Qiang * 'length' is the size that the structure says it is, including the CRC. 4875632d15cSZhao Qiang */ 4885632d15cSZhao Qiang int u_qe_upload_firmware(const struct qe_firmware *firmware) 4895632d15cSZhao Qiang { 4905632d15cSZhao Qiang unsigned int i; 4915632d15cSZhao Qiang unsigned int j; 4925632d15cSZhao Qiang u32 crc; 4935632d15cSZhao Qiang size_t calc_size = sizeof(struct qe_firmware); 4945632d15cSZhao Qiang size_t length; 4955632d15cSZhao Qiang const struct qe_header *hdr; 4965632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP 4979c7c86f4SZhao Qiang #ifdef CONFIG_LS102XA 4989c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 4999c7c86f4SZhao Qiang #else 5005632d15cSZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 5015632d15cSZhao Qiang #endif 5029c7c86f4SZhao Qiang #endif 5035632d15cSZhao Qiang if (!firmware) { 5045632d15cSZhao Qiang printf("Invalid address\n"); 5055632d15cSZhao Qiang return -EINVAL; 5065632d15cSZhao Qiang } 5075632d15cSZhao Qiang 5085632d15cSZhao Qiang hdr = &firmware->header; 5095632d15cSZhao Qiang length = be32_to_cpu(hdr->length); 5105632d15cSZhao Qiang 5115632d15cSZhao Qiang /* Check the magic */ 5125632d15cSZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 5135632d15cSZhao Qiang (hdr->magic[2] != 'F')) { 5145632d15cSZhao Qiang printf("Not a microcode\n"); 5155632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP 5165632d15cSZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 5175632d15cSZhao Qiang #endif 5185632d15cSZhao Qiang return -EPERM; 5195632d15cSZhao Qiang } 5205632d15cSZhao Qiang 5215632d15cSZhao Qiang /* Check the version */ 5225632d15cSZhao Qiang if (hdr->version != 1) { 5235632d15cSZhao Qiang printf("Unsupported version\n"); 5245632d15cSZhao Qiang return -EPERM; 5255632d15cSZhao Qiang } 5265632d15cSZhao Qiang 5275632d15cSZhao Qiang /* Validate some of the fields */ 5285632d15cSZhao Qiang if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 5295632d15cSZhao Qiang printf("Invalid data\n"); 5305632d15cSZhao Qiang return -EINVAL; 5315632d15cSZhao Qiang } 5325632d15cSZhao Qiang 5335632d15cSZhao Qiang /* Validate the length and check if there's a CRC */ 5345632d15cSZhao Qiang calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 5355632d15cSZhao Qiang 5365632d15cSZhao Qiang for (i = 0; i < firmware->count; i++) 5375632d15cSZhao Qiang /* 5385632d15cSZhao Qiang * For situations where the second RISC uses the same microcode 5395632d15cSZhao Qiang * as the first, the 'code_offset' and 'count' fields will be 5405632d15cSZhao Qiang * zero, so it's okay to add those. 5415632d15cSZhao Qiang */ 5425632d15cSZhao Qiang calc_size += sizeof(u32) * 5435632d15cSZhao Qiang be32_to_cpu(firmware->microcode[i].count); 5445632d15cSZhao Qiang 5455632d15cSZhao Qiang /* Validate the length */ 5465632d15cSZhao Qiang if (length != calc_size + sizeof(u32)) { 5475632d15cSZhao Qiang printf("Invalid length\n"); 5485632d15cSZhao Qiang return -EPERM; 5495632d15cSZhao Qiang } 5505632d15cSZhao Qiang 5515632d15cSZhao Qiang /* 5525632d15cSZhao Qiang * Validate the CRC. We would normally call crc32_no_comp(), but that 5535632d15cSZhao Qiang * function isn't available unless you turn on JFFS support. 5545632d15cSZhao Qiang */ 5555632d15cSZhao Qiang crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 5565632d15cSZhao Qiang if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) { 5575632d15cSZhao Qiang printf("Firmware CRC is invalid\n"); 5585632d15cSZhao Qiang return -EIO; 5595632d15cSZhao Qiang } 5605632d15cSZhao Qiang 5615632d15cSZhao Qiang /* 5625632d15cSZhao Qiang * If the microcode calls for it, split the I-RAM. 5635632d15cSZhao Qiang */ 5645632d15cSZhao Qiang if (!firmware->split) { 5655632d15cSZhao Qiang out_be16(&qe_immr->cp.cercr, 5665632d15cSZhao Qiang in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); 5675632d15cSZhao Qiang } 5685632d15cSZhao Qiang 5695632d15cSZhao Qiang if (firmware->soc.model) 5705632d15cSZhao Qiang printf("Firmware '%s' for %u V%u.%u\n", 5715632d15cSZhao Qiang firmware->id, be16_to_cpu(firmware->soc.model), 5725632d15cSZhao Qiang firmware->soc.major, firmware->soc.minor); 5735632d15cSZhao Qiang else 5745632d15cSZhao Qiang printf("Firmware '%s'\n", firmware->id); 5755632d15cSZhao Qiang 5765632d15cSZhao Qiang /* Loop through each microcode. */ 5775632d15cSZhao Qiang for (i = 0; i < firmware->count; i++) { 5785632d15cSZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i]; 5795632d15cSZhao Qiang 5805632d15cSZhao Qiang /* Upload a microcode if it's present */ 5815632d15cSZhao Qiang if (ucode->code_offset) 5825632d15cSZhao Qiang qe_upload_microcode(firmware, ucode); 5835632d15cSZhao Qiang 5845632d15cSZhao Qiang /* Program the traps for this processor */ 5855632d15cSZhao Qiang for (j = 0; j < 16; j++) { 5865632d15cSZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]); 5875632d15cSZhao Qiang 5885632d15cSZhao Qiang if (trap) 5895632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].tibcr[j], trap); 5905632d15cSZhao Qiang } 5915632d15cSZhao Qiang 5925632d15cSZhao Qiang /* Enable traps */ 5935632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 5945632d15cSZhao Qiang } 5955632d15cSZhao Qiang 5965632d15cSZhao Qiang return 0; 5975632d15cSZhao Qiang } 5985632d15cSZhao Qiang #endif 5995632d15cSZhao Qiang 600ae42eb03SZhao Qiang #ifdef CONFIG_U_QE 601ae42eb03SZhao Qiang int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr) 602ae42eb03SZhao Qiang { 603ae42eb03SZhao Qiang unsigned int i; 604ae42eb03SZhao Qiang unsigned int j; 605ae42eb03SZhao Qiang const struct qe_header *hdr; 606ae42eb03SZhao Qiang const u32 *code; 607ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 608ae42eb03SZhao Qiang #ifdef CONFIG_PPC 609ae42eb03SZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 610ae42eb03SZhao Qiang #else 611ae42eb03SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; 612ae42eb03SZhao Qiang #endif 613ae42eb03SZhao Qiang #endif 614ae42eb03SZhao Qiang 615ae42eb03SZhao Qiang if (!firmware) 616ae42eb03SZhao Qiang return -EINVAL; 617ae42eb03SZhao Qiang 618ae42eb03SZhao Qiang hdr = &firmware->header; 619ae42eb03SZhao Qiang 620ae42eb03SZhao Qiang /* Check the magic */ 621ae42eb03SZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 622ae42eb03SZhao Qiang (hdr->magic[2] != 'F')) { 623ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP 624ae42eb03SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE); 625ae42eb03SZhao Qiang #endif 626ae42eb03SZhao Qiang return -EPERM; 627ae42eb03SZhao Qiang } 628ae42eb03SZhao Qiang 629ae42eb03SZhao Qiang /* 630ae42eb03SZhao Qiang * If the microcode calls for it, split the I-RAM. 631ae42eb03SZhao Qiang */ 632ae42eb03SZhao Qiang if (!firmware->split) { 633ae42eb03SZhao Qiang out_be16(&qe_immrr->cp.cercr, 634ae42eb03SZhao Qiang in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR); 635ae42eb03SZhao Qiang } 636ae42eb03SZhao Qiang 637ae42eb03SZhao Qiang /* Loop through each microcode. */ 638ae42eb03SZhao Qiang for (i = 0; i < firmware->count; i++) { 639ae42eb03SZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i]; 640ae42eb03SZhao Qiang 641ae42eb03SZhao Qiang /* Upload a microcode if it's present */ 642ae42eb03SZhao Qiang if (!ucode->code_offset) 643ae42eb03SZhao Qiang return 0; 644ae42eb03SZhao Qiang 645ae42eb03SZhao Qiang code = (const void *)firmware + be32_to_cpu(ucode->code_offset); 646ae42eb03SZhao Qiang 647ae42eb03SZhao Qiang /* Use auto-increment */ 648ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) | 649ae42eb03SZhao Qiang QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); 650ae42eb03SZhao Qiang 651ae42eb03SZhao Qiang for (i = 0; i < be32_to_cpu(ucode->count); i++) 652ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i])); 653ae42eb03SZhao Qiang 654ae42eb03SZhao Qiang /* Program the traps for this processor */ 655ae42eb03SZhao Qiang for (j = 0; j < 16; j++) { 656ae42eb03SZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]); 657ae42eb03SZhao Qiang 658ae42eb03SZhao Qiang if (trap) 659ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].tibcr[j], trap); 660ae42eb03SZhao Qiang } 661ae42eb03SZhao Qiang 662ae42eb03SZhao Qiang /* Enable traps */ 663ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 664ae42eb03SZhao Qiang } 665ae42eb03SZhao Qiang 666ae42eb03SZhao Qiang return 0; 667ae42eb03SZhao Qiang } 668ae42eb03SZhao Qiang #endif 669ae42eb03SZhao Qiang 670b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void) 671b8ec2385STimur Tabi { 672b8ec2385STimur Tabi return qe_firmware_uploaded ? &qe_firmware_info : NULL; 673b8ec2385STimur Tabi } 674b8ec2385STimur Tabi 67554841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 676b8ec2385STimur Tabi { 677b8ec2385STimur Tabi ulong addr; 678b8ec2385STimur Tabi 67947e26b1bSWolfgang Denk if (argc < 3) 68047e26b1bSWolfgang Denk return cmd_usage(cmdtp); 681b8ec2385STimur Tabi 682b8ec2385STimur Tabi if (strcmp(argv[1], "fw") == 0) { 683b8ec2385STimur Tabi addr = simple_strtoul(argv[2], NULL, 16); 684b8ec2385STimur Tabi 685b8ec2385STimur Tabi if (!addr) { 686b8ec2385STimur Tabi printf("Invalid address\n"); 687b8ec2385STimur Tabi return -EINVAL; 688b8ec2385STimur Tabi } 689b8ec2385STimur Tabi 690b8ec2385STimur Tabi /* 691b8ec2385STimur Tabi * If a length was supplied, compare that with the 'length' 692b8ec2385STimur Tabi * field. 693b8ec2385STimur Tabi */ 694b8ec2385STimur Tabi 695b8ec2385STimur Tabi if (argc > 3) { 696b8ec2385STimur Tabi ulong length = simple_strtoul(argv[3], NULL, 16); 697b8ec2385STimur Tabi struct qe_firmware *firmware = (void *) addr; 698b8ec2385STimur Tabi 699b8ec2385STimur Tabi if (length != be32_to_cpu(firmware->header.length)) { 700b8ec2385STimur Tabi printf("Length mismatch\n"); 701b8ec2385STimur Tabi return -EINVAL; 702b8ec2385STimur Tabi } 703b8ec2385STimur Tabi } 704b8ec2385STimur Tabi 705b8ec2385STimur Tabi return qe_upload_firmware((const struct qe_firmware *) addr); 706b8ec2385STimur Tabi } 707b8ec2385STimur Tabi 70847e26b1bSWolfgang Denk return cmd_usage(cmdtp); 709b8ec2385STimur Tabi } 710b8ec2385STimur Tabi 711b8ec2385STimur Tabi U_BOOT_CMD( 712b8ec2385STimur Tabi qe, 4, 0, qe_cmd, 7132fb2604dSPeter Tyser "QUICC Engine commands", 714b8ec2385STimur Tabi "fw <addr> [<length>] - Upload firmware binary at address <addr> to " 715a89c33dbSWolfgang Denk "the QE,\n" 716a89c33dbSWolfgang Denk "\twith optional length <length> verification." 717b8ec2385STimur Tabi ); 718