17737d5c6SDave Liu /* 27737d5c6SDave Liu * Copyright (C) 2006 Freescale Semiconductor, Inc. 37737d5c6SDave Liu * 47737d5c6SDave Liu * Dave Liu <daveliu@freescale.com> 57737d5c6SDave Liu * based on source code of Shlomi Gridish 67737d5c6SDave Liu * 77737d5c6SDave Liu * This program is free software; you can redistribute it and/or 87737d5c6SDave Liu * modify it under the terms of the GNU General Public License as 97737d5c6SDave Liu * published by the Free Software Foundation; either version 2 of 107737d5c6SDave Liu * the License, or (at your option) any later version. 117737d5c6SDave Liu * 127737d5c6SDave Liu * This program is distributed in the hope that it will be useful, 137737d5c6SDave Liu * but WITHOUT ANY WARRANTY; without even the implied warranty of 147737d5c6SDave Liu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157737d5c6SDave Liu * GNU General Public License for more details. 167737d5c6SDave Liu * 177737d5c6SDave Liu * You should have received a copy of the GNU General Public License 187737d5c6SDave Liu * along with this program; if not, write to the Free Software 197737d5c6SDave Liu * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 207737d5c6SDave Liu * MA 02111-1307 USA 217737d5c6SDave Liu */ 227737d5c6SDave Liu 237737d5c6SDave Liu #include "common.h" 24b8ec2385STimur Tabi #include <command.h> 257737d5c6SDave Liu #include "asm/errno.h" 267737d5c6SDave Liu #include "asm/io.h" 277737d5c6SDave Liu #include "asm/immap_qe.h" 287737d5c6SDave Liu #include "qe.h" 297737d5c6SDave Liu 307737d5c6SDave Liu #if defined(CONFIG_QE) 317737d5c6SDave Liu qe_map_t *qe_immr = NULL; 327737d5c6SDave Liu static qe_snum_t snums[QE_NUM_OF_SNUM]; 337737d5c6SDave Liu 341218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR; 351218abf1SWolfgang Denk 367737d5c6SDave Liu void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) 377737d5c6SDave Liu { 387737d5c6SDave Liu u32 cecr; 397737d5c6SDave Liu 407737d5c6SDave Liu if (cmd == QE_RESET) { 417737d5c6SDave Liu out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); 427737d5c6SDave Liu } else { 437737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, cmd_data); 447737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | 457737d5c6SDave Liu ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd)); 467737d5c6SDave Liu } 477737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 487737d5c6SDave Liu do { 497737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 507737d5c6SDave Liu } while (cecr & QE_CR_FLG); 517737d5c6SDave Liu 527737d5c6SDave Liu return; 537737d5c6SDave Liu } 547737d5c6SDave Liu 557737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align) 567737d5c6SDave Liu { 577737d5c6SDave Liu uint retloc; 587737d5c6SDave Liu uint align_mask, off; 597737d5c6SDave Liu uint savebase; 607737d5c6SDave Liu 617737d5c6SDave Liu align_mask = align - 1; 627737d5c6SDave Liu savebase = gd->mp_alloc_base; 637737d5c6SDave Liu 647737d5c6SDave Liu if ((off = (gd->mp_alloc_base & align_mask)) != 0) 657737d5c6SDave Liu gd->mp_alloc_base += (align - off); 667737d5c6SDave Liu 677737d5c6SDave Liu if ((off = size & align_mask) != 0) 687737d5c6SDave Liu size += (align - off); 697737d5c6SDave Liu 707737d5c6SDave Liu if ((gd->mp_alloc_base + size) >= gd->mp_alloc_top) { 717737d5c6SDave Liu gd->mp_alloc_base = savebase; 727737d5c6SDave Liu printf("%s: ran out of ram.\n", __FUNCTION__); 737737d5c6SDave Liu } 747737d5c6SDave Liu 757737d5c6SDave Liu retloc = gd->mp_alloc_base; 767737d5c6SDave Liu gd->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 } 847737d5c6SDave Liu 857737d5c6SDave Liu void *qe_muram_addr(uint offset) 867737d5c6SDave Liu { 877737d5c6SDave Liu return (void *)&qe_immr->muram[offset]; 887737d5c6SDave Liu } 897737d5c6SDave Liu 907737d5c6SDave Liu static void qe_sdma_init(void) 917737d5c6SDave Liu { 927737d5c6SDave Liu volatile sdma_t *p; 937737d5c6SDave Liu uint sdma_buffer_base; 947737d5c6SDave Liu 957737d5c6SDave Liu p = (volatile sdma_t *)&qe_immr->sdma; 967737d5c6SDave Liu 977737d5c6SDave Liu /* All of DMA transaction in bus 1 */ 987737d5c6SDave Liu out_be32(&p->sdaqr, 0); 997737d5c6SDave Liu out_be32(&p->sdaqmr, 0); 1007737d5c6SDave Liu 1017737d5c6SDave Liu /* Allocate 2KB temporary buffer for sdma */ 102ff9658d7SDave Liu sdma_buffer_base = qe_muram_alloc(2048, 4096); 1037737d5c6SDave Liu out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); 1047737d5c6SDave Liu 1057737d5c6SDave Liu /* Clear sdma status */ 1067737d5c6SDave Liu out_be32(&p->sdsr, 0x03000000); 1077737d5c6SDave Liu 1087737d5c6SDave Liu /* Enable global mode on bus 1, and 2KB buffer size */ 1097737d5c6SDave Liu out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT)); 1107737d5c6SDave Liu } 1117737d5c6SDave Liu 1127737d5c6SDave Liu static u8 thread_snum[QE_NUM_OF_SNUM] = { 1137737d5c6SDave Liu 0x04, 0x05, 0x0c, 0x0d, 1147737d5c6SDave Liu 0x14, 0x15, 0x1c, 0x1d, 1157737d5c6SDave Liu 0x24, 0x25, 0x2c, 0x2d, 1167737d5c6SDave Liu 0x34, 0x35, 0x88, 0x89, 1177737d5c6SDave Liu 0x98, 0x99, 0xa8, 0xa9, 1187737d5c6SDave Liu 0xb8, 0xb9, 0xc8, 0xc9, 1197737d5c6SDave Liu 0xd8, 0xd9, 0xe8, 0xe9 1207737d5c6SDave Liu }; 1217737d5c6SDave Liu 1227737d5c6SDave Liu static void qe_snums_init(void) 1237737d5c6SDave Liu { 1247737d5c6SDave Liu int i; 1257737d5c6SDave Liu 1267737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1277737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1287737d5c6SDave Liu snums[i].num = thread_snum[i]; 1297737d5c6SDave Liu } 1307737d5c6SDave Liu } 1317737d5c6SDave Liu 1327737d5c6SDave Liu int qe_get_snum(void) 1337737d5c6SDave Liu { 1347737d5c6SDave Liu int snum = -EBUSY; 1357737d5c6SDave Liu int i; 1367737d5c6SDave Liu 1377737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1387737d5c6SDave Liu if (snums[i].state == QE_SNUM_STATE_FREE) { 1397737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_USED; 1407737d5c6SDave Liu snum = snums[i].num; 1417737d5c6SDave Liu break; 1427737d5c6SDave Liu } 1437737d5c6SDave Liu } 1447737d5c6SDave Liu 1457737d5c6SDave Liu return snum; 1467737d5c6SDave Liu } 1477737d5c6SDave Liu 1487737d5c6SDave Liu void qe_put_snum(u8 snum) 1497737d5c6SDave Liu { 1507737d5c6SDave Liu int i; 1517737d5c6SDave Liu 1527737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) { 1537737d5c6SDave Liu if (snums[i].num == snum) { 1547737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE; 1557737d5c6SDave Liu break; 1567737d5c6SDave Liu } 1577737d5c6SDave Liu } 1587737d5c6SDave Liu } 1597737d5c6SDave Liu 1607737d5c6SDave Liu void qe_init(uint qe_base) 1617737d5c6SDave Liu { 1627737d5c6SDave Liu /* Init the QE IMMR base */ 1637737d5c6SDave Liu qe_immr = (qe_map_t *)qe_base; 1647737d5c6SDave Liu 1657737d5c6SDave Liu gd->mp_alloc_base = QE_DATAONLY_BASE; 1667737d5c6SDave Liu gd->mp_alloc_top = gd->mp_alloc_base + QE_DATAONLY_SIZE; 1677737d5c6SDave Liu 1687737d5c6SDave Liu qe_sdma_init(); 1697737d5c6SDave Liu qe_snums_init(); 1707737d5c6SDave Liu } 1717737d5c6SDave Liu 1727737d5c6SDave Liu void qe_reset(void) 1737737d5c6SDave Liu { 1747737d5c6SDave Liu qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, 1757737d5c6SDave Liu (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); 1767737d5c6SDave Liu } 1777737d5c6SDave Liu 1787737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base) 1797737d5c6SDave Liu { 1807737d5c6SDave Liu u32 cecr; 1817737d5c6SDave Liu 1827737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, para_ram_base); 1837737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT) 1847737d5c6SDave Liu | QE_CR_FLG | QE_ASSIGN_PAGE); 1857737d5c6SDave Liu 1867737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */ 1877737d5c6SDave Liu do { 1887737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr); 1897737d5c6SDave Liu } while (cecr & QE_CR_FLG ); 1907737d5c6SDave Liu 1917737d5c6SDave Liu return; 1927737d5c6SDave Liu } 1937737d5c6SDave Liu 1947737d5c6SDave Liu /* 1957737d5c6SDave Liu * brg: 0~15 as BRG1~BRG16 1967737d5c6SDave Liu rate: baud rate 1977737d5c6SDave Liu * BRG input clock comes from the BRGCLK (internal clock generated from 1987737d5c6SDave Liu the QE clock, it is one-half of the QE clock), If need the clock source 1997737d5c6SDave Liu from CLKn pin, we have te change the function. 2007737d5c6SDave Liu */ 2017737d5c6SDave Liu 2027737d5c6SDave Liu #define BRG_CLK (gd->brg_clk) 2037737d5c6SDave Liu 2047737d5c6SDave Liu int qe_set_brg(uint brg, uint rate) 2057737d5c6SDave Liu { 2067737d5c6SDave Liu volatile uint *bp; 2077737d5c6SDave Liu u32 divisor; 2087737d5c6SDave Liu int div16 = 0; 2097737d5c6SDave Liu 2107737d5c6SDave Liu if (brg >= QE_NUM_OF_BRGS) 2117737d5c6SDave Liu return -EINVAL; 2127737d5c6SDave Liu bp = (uint *)&qe_immr->brg.brgc1; 2137737d5c6SDave Liu bp += brg; 2147737d5c6SDave Liu 2157737d5c6SDave Liu divisor = (BRG_CLK / rate); 2167737d5c6SDave Liu if (divisor > QE_BRGC_DIVISOR_MAX + 1) { 2177737d5c6SDave Liu div16 = 1; 2187737d5c6SDave Liu divisor /= 16; 2197737d5c6SDave Liu } 2207737d5c6SDave Liu 2217737d5c6SDave Liu *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; 2227737d5c6SDave Liu __asm__ __volatile__("sync"); 2237737d5c6SDave Liu 2247737d5c6SDave Liu if (div16) { 2257737d5c6SDave Liu *bp |= QE_BRGC_DIV16; 2267737d5c6SDave Liu __asm__ __volatile__("sync"); 2277737d5c6SDave Liu } 2287737d5c6SDave Liu 2297737d5c6SDave Liu return 0; 2307737d5c6SDave Liu } 2317737d5c6SDave Liu 2327737d5c6SDave Liu /* Set ethernet MII clock master 2337737d5c6SDave Liu */ 2347737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num) 2357737d5c6SDave Liu { 2367737d5c6SDave Liu u32 cmxgcr; 2377737d5c6SDave Liu 2387737d5c6SDave Liu /* check if the UCC number is in range. */ 2397737d5c6SDave Liu if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { 2407737d5c6SDave Liu printf("%s: ucc num not in ranges\n", __FUNCTION__); 2417737d5c6SDave Liu return -EINVAL; 2427737d5c6SDave Liu } 2437737d5c6SDave Liu 2447737d5c6SDave Liu cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); 2457737d5c6SDave Liu cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; 2467737d5c6SDave Liu cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT); 2477737d5c6SDave Liu out_be32(&qe_immr->qmx.cmxgcr, cmxgcr); 2487737d5c6SDave Liu 2497737d5c6SDave Liu return 0; 2507737d5c6SDave Liu } 2517737d5c6SDave Liu 252b8ec2385STimur Tabi /* The maximum number of RISCs we support */ 253b8ec2385STimur Tabi #define MAX_QE_RISC 2 254b8ec2385STimur Tabi 255b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */ 256b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info; 257b8ec2385STimur Tabi 258b8ec2385STimur Tabi /* 259b8ec2385STimur Tabi * Set to 1 if QE firmware has been uploaded, and therefore 260b8ec2385STimur Tabi * qe_firmware_info contains valid data. 261b8ec2385STimur Tabi */ 262b8ec2385STimur Tabi static int qe_firmware_uploaded; 263b8ec2385STimur Tabi 264b8ec2385STimur Tabi /* 265b8ec2385STimur Tabi * Upload a QE microcode 266b8ec2385STimur Tabi * 267b8ec2385STimur Tabi * This function is a worker function for qe_upload_firmware(). It does 268b8ec2385STimur Tabi * the actual uploading of the microcode. 269b8ec2385STimur Tabi */ 270b8ec2385STimur Tabi static void qe_upload_microcode(const void *base, 271b8ec2385STimur Tabi const struct qe_microcode *ucode) 272b8ec2385STimur Tabi { 273b8ec2385STimur Tabi const u32 *code = base + be32_to_cpu(ucode->code_offset); 274b8ec2385STimur Tabi unsigned int i; 275b8ec2385STimur Tabi 276b8ec2385STimur Tabi if (ucode->major || ucode->minor || ucode->revision) 277b8ec2385STimur Tabi printf("QE: uploading microcode '%s' version %u.%u.%u\n", 278b8ec2385STimur Tabi ucode->id, ucode->major, ucode->minor, ucode->revision); 279b8ec2385STimur Tabi else 280b8ec2385STimur Tabi printf("QE: uploading microcode '%s'\n", ucode->id); 281b8ec2385STimur Tabi 282b8ec2385STimur Tabi /* Use auto-increment */ 283b8ec2385STimur Tabi out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | 284b8ec2385STimur Tabi QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); 285b8ec2385STimur Tabi 286b8ec2385STimur Tabi for (i = 0; i < be32_to_cpu(ucode->count); i++) 287b8ec2385STimur Tabi out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); 288b8ec2385STimur Tabi } 289b8ec2385STimur Tabi 290b8ec2385STimur Tabi /* 291b8ec2385STimur Tabi * Upload a microcode to the I-RAM at a specific address. 292b8ec2385STimur Tabi * 293b8ec2385STimur Tabi * See docs/README.qe_firmware for information on QE microcode uploading. 294b8ec2385STimur Tabi * 295b8ec2385STimur Tabi * Currently, only version 1 is supported, so the 'version' field must be 296b8ec2385STimur Tabi * set to 1. 297b8ec2385STimur Tabi * 298b8ec2385STimur Tabi * The SOC model and revision are not validated, they are only displayed for 299b8ec2385STimur Tabi * informational purposes. 300b8ec2385STimur Tabi * 301b8ec2385STimur Tabi * 'calc_size' is the calculated size, in bytes, of the firmware structure and 302b8ec2385STimur Tabi * all of the microcode structures, minus the CRC. 303b8ec2385STimur Tabi * 304b8ec2385STimur Tabi * 'length' is the size that the structure says it is, including the CRC. 305b8ec2385STimur Tabi */ 306b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware) 307b8ec2385STimur Tabi { 308b8ec2385STimur Tabi unsigned int i; 309b8ec2385STimur Tabi unsigned int j; 310b8ec2385STimur Tabi u32 crc; 311b8ec2385STimur Tabi size_t calc_size = sizeof(struct qe_firmware); 312b8ec2385STimur Tabi size_t length; 313b8ec2385STimur Tabi const struct qe_header *hdr; 314b8ec2385STimur Tabi 315b8ec2385STimur Tabi if (!firmware) { 316b8ec2385STimur Tabi printf("Invalid address\n"); 317b8ec2385STimur Tabi return -EINVAL; 318b8ec2385STimur Tabi } 319b8ec2385STimur Tabi 320b8ec2385STimur Tabi hdr = &firmware->header; 321b8ec2385STimur Tabi length = be32_to_cpu(hdr->length); 322b8ec2385STimur Tabi 323b8ec2385STimur Tabi /* Check the magic */ 324b8ec2385STimur Tabi if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 325b8ec2385STimur Tabi (hdr->magic[2] != 'F')) { 326b8ec2385STimur Tabi printf("Not a microcode\n"); 327b8ec2385STimur Tabi return -EPERM; 328b8ec2385STimur Tabi } 329b8ec2385STimur Tabi 330b8ec2385STimur Tabi /* Check the version */ 331b8ec2385STimur Tabi if (hdr->version != 1) { 332b8ec2385STimur Tabi printf("Unsupported version\n"); 333b8ec2385STimur Tabi return -EPERM; 334b8ec2385STimur Tabi } 335b8ec2385STimur Tabi 336b8ec2385STimur Tabi /* Validate some of the fields */ 337*491fb6deSTimur Tabi if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 338b8ec2385STimur Tabi printf("Invalid data\n"); 339b8ec2385STimur Tabi return -EINVAL; 340b8ec2385STimur Tabi } 341b8ec2385STimur Tabi 342b8ec2385STimur Tabi /* Validate the length and check if there's a CRC */ 343b8ec2385STimur Tabi calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 344b8ec2385STimur Tabi 345b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) 346b8ec2385STimur Tabi /* 347b8ec2385STimur Tabi * For situations where the second RISC uses the same microcode 348b8ec2385STimur Tabi * as the first, the 'code_offset' and 'count' fields will be 349b8ec2385STimur Tabi * zero, so it's okay to add those. 350b8ec2385STimur Tabi */ 351b8ec2385STimur Tabi calc_size += sizeof(u32) * 352b8ec2385STimur Tabi be32_to_cpu(firmware->microcode[i].count); 353b8ec2385STimur Tabi 354b8ec2385STimur Tabi /* Validate the length */ 355b8ec2385STimur Tabi if (length != calc_size + sizeof(u32)) { 356b8ec2385STimur Tabi printf("Invalid length\n"); 357b8ec2385STimur Tabi return -EPERM; 358b8ec2385STimur Tabi } 359b8ec2385STimur Tabi 360b8ec2385STimur Tabi /* 361b8ec2385STimur Tabi * Validate the CRC. We would normally call crc32_no_comp(), but that 362b8ec2385STimur Tabi * function isn't available unless you turn on JFFS support. 363b8ec2385STimur Tabi */ 364b8ec2385STimur Tabi crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size)); 365b8ec2385STimur Tabi if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) { 366b8ec2385STimur Tabi printf("Firmware CRC is invalid\n"); 367b8ec2385STimur Tabi return -EIO; 368b8ec2385STimur Tabi } 369b8ec2385STimur Tabi 370b8ec2385STimur Tabi /* 371b8ec2385STimur Tabi * If the microcode calls for it, split the I-RAM. 372b8ec2385STimur Tabi */ 373b8ec2385STimur Tabi if (!firmware->split) { 374b8ec2385STimur Tabi out_be16(&qe_immr->cp.cercr, 375b8ec2385STimur Tabi in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR); 376b8ec2385STimur Tabi } 377b8ec2385STimur Tabi 378b8ec2385STimur Tabi if (firmware->soc.model) 379b8ec2385STimur Tabi printf("Firmware '%s' for %u V%u.%u\n", 380b8ec2385STimur Tabi firmware->id, be16_to_cpu(firmware->soc.model), 381b8ec2385STimur Tabi firmware->soc.major, firmware->soc.minor); 382b8ec2385STimur Tabi else 383b8ec2385STimur Tabi printf("Firmware '%s'\n", firmware->id); 384b8ec2385STimur Tabi 385b8ec2385STimur Tabi /* 386b8ec2385STimur Tabi * The QE only supports one microcode per RISC, so clear out all the 387b8ec2385STimur Tabi * saved microcode information and put in the new. 388b8ec2385STimur Tabi */ 389b8ec2385STimur Tabi memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); 39006c428bcSDave Liu strcpy(qe_firmware_info.id, (char *)firmware->id); 391b8ec2385STimur Tabi qe_firmware_info.extended_modes = firmware->extended_modes; 392b8ec2385STimur Tabi memcpy(qe_firmware_info.vtraps, firmware->vtraps, 393b8ec2385STimur Tabi sizeof(firmware->vtraps)); 394b8ec2385STimur Tabi qe_firmware_uploaded = 1; 395b8ec2385STimur Tabi 396b8ec2385STimur Tabi /* Loop through each microcode. */ 397b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) { 398b8ec2385STimur Tabi const struct qe_microcode *ucode = &firmware->microcode[i]; 399b8ec2385STimur Tabi 400b8ec2385STimur Tabi /* Upload a microcode if it's present */ 401b8ec2385STimur Tabi if (ucode->code_offset) 402b8ec2385STimur Tabi qe_upload_microcode(firmware, ucode); 403b8ec2385STimur Tabi 404b8ec2385STimur Tabi /* Program the traps for this processor */ 405b8ec2385STimur Tabi for (j = 0; j < 16; j++) { 406b8ec2385STimur Tabi u32 trap = be32_to_cpu(ucode->traps[j]); 407b8ec2385STimur Tabi 408b8ec2385STimur Tabi if (trap) 409b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].tibcr[j], trap); 410b8ec2385STimur Tabi } 411b8ec2385STimur Tabi 412b8ec2385STimur Tabi /* Enable traps */ 413b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); 414b8ec2385STimur Tabi } 415b8ec2385STimur Tabi 416b8ec2385STimur Tabi return 0; 417b8ec2385STimur Tabi } 418b8ec2385STimur Tabi 419b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void) 420b8ec2385STimur Tabi { 421b8ec2385STimur Tabi return qe_firmware_uploaded ? &qe_firmware_info : NULL; 422b8ec2385STimur Tabi } 423b8ec2385STimur Tabi 424b8ec2385STimur Tabi static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 425b8ec2385STimur Tabi { 426b8ec2385STimur Tabi ulong addr; 427b8ec2385STimur Tabi 428b8ec2385STimur Tabi if (argc < 3) { 429b8ec2385STimur Tabi printf ("Usage:\n%s\n", cmdtp->usage); 430b8ec2385STimur Tabi return 1; 431b8ec2385STimur Tabi } 432b8ec2385STimur Tabi 433b8ec2385STimur Tabi if (strcmp(argv[1], "fw") == 0) { 434b8ec2385STimur Tabi addr = simple_strtoul(argv[2], NULL, 16); 435b8ec2385STimur Tabi 436b8ec2385STimur Tabi if (!addr) { 437b8ec2385STimur Tabi printf("Invalid address\n"); 438b8ec2385STimur Tabi return -EINVAL; 439b8ec2385STimur Tabi } 440b8ec2385STimur Tabi 441b8ec2385STimur Tabi /* 442b8ec2385STimur Tabi * If a length was supplied, compare that with the 'length' 443b8ec2385STimur Tabi * field. 444b8ec2385STimur Tabi */ 445b8ec2385STimur Tabi 446b8ec2385STimur Tabi if (argc > 3) { 447b8ec2385STimur Tabi ulong length = simple_strtoul(argv[3], NULL, 16); 448b8ec2385STimur Tabi struct qe_firmware *firmware = (void *) addr; 449b8ec2385STimur Tabi 450b8ec2385STimur Tabi if (length != be32_to_cpu(firmware->header.length)) { 451b8ec2385STimur Tabi printf("Length mismatch\n"); 452b8ec2385STimur Tabi return -EINVAL; 453b8ec2385STimur Tabi } 454b8ec2385STimur Tabi } 455b8ec2385STimur Tabi 456b8ec2385STimur Tabi return qe_upload_firmware((const struct qe_firmware *) addr); 457b8ec2385STimur Tabi } 458b8ec2385STimur Tabi 459b8ec2385STimur Tabi printf ("Usage:\n%s\n", cmdtp->usage); 460b8ec2385STimur Tabi return 1; 461b8ec2385STimur Tabi } 462b8ec2385STimur Tabi 463b8ec2385STimur Tabi U_BOOT_CMD( 464b8ec2385STimur Tabi qe, 4, 0, qe_cmd, 465b8ec2385STimur Tabi "qe - QUICC Engine commands\n", 466b8ec2385STimur Tabi "fw <addr> [<length>] - Upload firmware binary at address <addr> to " 467b8ec2385STimur Tabi "the QE,\n\twith optional length <length> verification.\n" 468b8ec2385STimur Tabi ); 469b8ec2385STimur Tabi 4707737d5c6SDave Liu #endif /* CONFIG_QE */ 471