183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
27737d5c6SDave Liu /*
34e7b25e4SHaiying Wang * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
47737d5c6SDave Liu *
57737d5c6SDave Liu * Dave Liu <daveliu@freescale.com>
67737d5c6SDave Liu * based on source code of Shlomi Gridish
77737d5c6SDave Liu */
87737d5c6SDave Liu
9b5bf5cb3SMasahiro Yamada #include <common.h>
105aa03dddSZhao Qiang #include <malloc.h>
11b8ec2385STimur Tabi #include <command.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
13b5bf5cb3SMasahiro Yamada #include <asm/io.h>
14b5bf5cb3SMasahiro Yamada #include <linux/immap_qe.h>
152459afb1SQianyu Gong #include <fsl_qe.h>
16*c5e6637fSRajesh Bhagat #include <mmc.h>
17*c5e6637fSRajesh Bhagat #include <environment.h>
18*c5e6637fSRajesh Bhagat
1973fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A
209c7c86f4SZhao Qiang #include <asm/arch/immap_ls102xa.h>
219c7c86f4SZhao Qiang #endif
22*c5e6637fSRajesh Bhagat #ifdef CONFIG_ARM64
23*c5e6637fSRajesh Bhagat #include <asm/armv8/mmu.h>
24*c5e6637fSRajesh Bhagat #include <asm/arch/cpu.h>
255aa03dddSZhao Qiang #endif
265aa03dddSZhao Qiang
27ca721fb2SZhao Qiang #define MPC85xx_DEVDISR_QE_DISABLE 0x1
28ca721fb2SZhao Qiang
297737d5c6SDave Liu qe_map_t *qe_immr = NULL;
303bf46e6aSZhao Qiang #ifdef CONFIG_QE
317737d5c6SDave Liu static qe_snum_t snums[QE_NUM_OF_SNUM];
323bf46e6aSZhao Qiang #endif
337737d5c6SDave Liu
341218abf1SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
351218abf1SWolfgang Denk
qe_issue_cmd(uint cmd,uint sbc,u8 mcn,u32 cmd_data)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
5593d33204SZhao Qiang #ifdef CONFIG_QE
qe_muram_alloc(uint size,uint align)567737d5c6SDave Liu uint qe_muram_alloc(uint size, uint align)
577737d5c6SDave Liu {
587737d5c6SDave Liu uint retloc;
597737d5c6SDave Liu uint align_mask, off;
607737d5c6SDave Liu uint savebase;
617737d5c6SDave Liu
627737d5c6SDave Liu align_mask = align - 1;
6345bae2e3SSimon Glass savebase = gd->arch.mp_alloc_base;
647737d5c6SDave Liu
6545bae2e3SSimon Glass off = gd->arch.mp_alloc_base & align_mask;
6645bae2e3SSimon Glass if (off != 0)
6745bae2e3SSimon Glass gd->arch.mp_alloc_base += (align - off);
687737d5c6SDave Liu
697737d5c6SDave Liu if ((off = size & align_mask) != 0)
707737d5c6SDave Liu size += (align - off);
717737d5c6SDave Liu
7245bae2e3SSimon Glass if ((gd->arch.mp_alloc_base + size) >= gd->arch.mp_alloc_top) {
7345bae2e3SSimon Glass gd->arch.mp_alloc_base = savebase;
747737d5c6SDave Liu printf("%s: ran out of ram.\n", __FUNCTION__);
757737d5c6SDave Liu }
767737d5c6SDave Liu
7745bae2e3SSimon Glass retloc = gd->arch.mp_alloc_base;
7845bae2e3SSimon Glass gd->arch.mp_alloc_base += size;
797737d5c6SDave Liu
807737d5c6SDave Liu memset((void *)&qe_immr->muram[retloc], 0, size);
817737d5c6SDave Liu
827737d5c6SDave Liu __asm__ __volatile__("sync");
837737d5c6SDave Liu
847737d5c6SDave Liu return retloc;
857737d5c6SDave Liu }
8693d33204SZhao Qiang #endif
877737d5c6SDave Liu
qe_muram_addr(uint offset)887737d5c6SDave Liu void *qe_muram_addr(uint offset)
897737d5c6SDave Liu {
907737d5c6SDave Liu return (void *)&qe_immr->muram[offset];
917737d5c6SDave Liu }
927737d5c6SDave Liu
933bf46e6aSZhao Qiang #ifdef CONFIG_QE
qe_sdma_init(void)947737d5c6SDave Liu static void qe_sdma_init(void)
957737d5c6SDave Liu {
967737d5c6SDave Liu volatile sdma_t *p;
977737d5c6SDave Liu uint sdma_buffer_base;
987737d5c6SDave Liu
997737d5c6SDave Liu p = (volatile sdma_t *)&qe_immr->sdma;
1007737d5c6SDave Liu
1017737d5c6SDave Liu /* All of DMA transaction in bus 1 */
1027737d5c6SDave Liu out_be32(&p->sdaqr, 0);
1037737d5c6SDave Liu out_be32(&p->sdaqmr, 0);
1047737d5c6SDave Liu
1057737d5c6SDave Liu /* Allocate 2KB temporary buffer for sdma */
106ff9658d7SDave Liu sdma_buffer_base = qe_muram_alloc(2048, 4096);
1077737d5c6SDave Liu out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
1087737d5c6SDave Liu
1097737d5c6SDave Liu /* Clear sdma status */
1107737d5c6SDave Liu out_be32(&p->sdsr, 0x03000000);
1117737d5c6SDave Liu
1127737d5c6SDave Liu /* Enable global mode on bus 1, and 2KB buffer size */
1137737d5c6SDave Liu out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
1147737d5c6SDave Liu }
1157737d5c6SDave Liu
1164e7b25e4SHaiying Wang /* This table is a list of the serial numbers of the Threads, taken from the
1174e7b25e4SHaiying Wang * "SNUM Table" chart in the QE Reference Manual. The order is not important,
1184e7b25e4SHaiying Wang * we just need to know what the SNUMs are for the threads.
1194e7b25e4SHaiying Wang */
1204e7b25e4SHaiying Wang static u8 thread_snum[] = {
121a88731a6SGerlando Falauto /* Evthreads 16-29 are not supported in MPC8309 */
122a88731a6SGerlando Falauto #if !defined(CONFIG_MPC8309)
1237737d5c6SDave Liu 0x04, 0x05, 0x0c, 0x0d,
1247737d5c6SDave Liu 0x14, 0x15, 0x1c, 0x1d,
1257737d5c6SDave Liu 0x24, 0x25, 0x2c, 0x2d,
126a88731a6SGerlando Falauto 0x34, 0x35,
127a88731a6SGerlando Falauto #endif
128a88731a6SGerlando Falauto 0x88, 0x89, 0x98, 0x99,
129a88731a6SGerlando Falauto 0xa8, 0xa9, 0xb8, 0xb9,
130a88731a6SGerlando Falauto 0xc8, 0xc9, 0xd8, 0xd9,
131a88731a6SGerlando Falauto 0xe8, 0xe9, 0x08, 0x09,
132a88731a6SGerlando Falauto 0x18, 0x19, 0x28, 0x29,
133a88731a6SGerlando Falauto 0x38, 0x39, 0x48, 0x49,
134a88731a6SGerlando Falauto 0x58, 0x59, 0x68, 0x69,
135a88731a6SGerlando Falauto 0x78, 0x79, 0x80, 0x81
1367737d5c6SDave Liu };
1377737d5c6SDave Liu
qe_snums_init(void)1387737d5c6SDave Liu static void qe_snums_init(void)
1397737d5c6SDave Liu {
1407737d5c6SDave Liu int i;
1417737d5c6SDave Liu
1427737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1437737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE;
1447737d5c6SDave Liu snums[i].num = thread_snum[i];
1457737d5c6SDave Liu }
1467737d5c6SDave Liu }
1477737d5c6SDave Liu
qe_get_snum(void)1487737d5c6SDave Liu int qe_get_snum(void)
1497737d5c6SDave Liu {
1507737d5c6SDave Liu int snum = -EBUSY;
1517737d5c6SDave Liu int i;
1527737d5c6SDave Liu
1537737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1547737d5c6SDave Liu if (snums[i].state == QE_SNUM_STATE_FREE) {
1557737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_USED;
1567737d5c6SDave Liu snum = snums[i].num;
1577737d5c6SDave Liu break;
1587737d5c6SDave Liu }
1597737d5c6SDave Liu }
1607737d5c6SDave Liu
1617737d5c6SDave Liu return snum;
1627737d5c6SDave Liu }
1637737d5c6SDave Liu
qe_put_snum(u8 snum)1647737d5c6SDave Liu void qe_put_snum(u8 snum)
1657737d5c6SDave Liu {
1667737d5c6SDave Liu int i;
1677737d5c6SDave Liu
1687737d5c6SDave Liu for (i = 0; i < QE_NUM_OF_SNUM; i++) {
1697737d5c6SDave Liu if (snums[i].num == snum) {
1707737d5c6SDave Liu snums[i].state = QE_SNUM_STATE_FREE;
1717737d5c6SDave Liu break;
1727737d5c6SDave Liu }
1737737d5c6SDave Liu }
1747737d5c6SDave Liu }
1757737d5c6SDave Liu
176*c5e6637fSRajesh Bhagat #ifdef CONFIG_TFABOOT
qe_init(uint qe_base)177*c5e6637fSRajesh Bhagat void qe_init(uint qe_base)
178*c5e6637fSRajesh Bhagat {
179*c5e6637fSRajesh Bhagat enum boot_src src = get_boot_src();
180*c5e6637fSRajesh Bhagat
181*c5e6637fSRajesh Bhagat /* Init the QE IMMR base */
182*c5e6637fSRajesh Bhagat qe_immr = (qe_map_t *)qe_base;
183*c5e6637fSRajesh Bhagat
184*c5e6637fSRajesh Bhagat if (src == BOOT_SOURCE_IFC_NOR) {
185*c5e6637fSRajesh Bhagat /*
186*c5e6637fSRajesh Bhagat * Upload microcode to IRAM for those SOCs
187*c5e6637fSRajesh Bhagat * which do not have ROM in QE.
188*c5e6637fSRajesh Bhagat */
189*c5e6637fSRajesh Bhagat qe_upload_firmware((const void *)(CONFIG_SYS_QE_FW_ADDR +
190*c5e6637fSRajesh Bhagat CONFIG_SYS_FSL_IFC_BASE));
191*c5e6637fSRajesh Bhagat
192*c5e6637fSRajesh Bhagat /* enable the microcode in IRAM */
193*c5e6637fSRajesh Bhagat out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
194*c5e6637fSRajesh Bhagat }
195*c5e6637fSRajesh Bhagat
196*c5e6637fSRajesh Bhagat gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
197*c5e6637fSRajesh Bhagat gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
198*c5e6637fSRajesh Bhagat
199*c5e6637fSRajesh Bhagat qe_sdma_init();
200*c5e6637fSRajesh Bhagat qe_snums_init();
201*c5e6637fSRajesh Bhagat }
202*c5e6637fSRajesh Bhagat #else
qe_init(uint qe_base)2037737d5c6SDave Liu void qe_init(uint qe_base)
2047737d5c6SDave Liu {
2057737d5c6SDave Liu /* Init the QE IMMR base */
2067737d5c6SDave Liu qe_immr = (qe_map_t *)qe_base;
2077737d5c6SDave Liu
208f2717b47STimur Tabi #ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
209c0a14aedSWolfgang Denk /*
210c0a14aedSWolfgang Denk * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
2112d4de6aeSHaiying Wang */
212dcf1d774SZhao Qiang qe_upload_firmware((const void *)CONFIG_SYS_QE_FW_ADDR);
2132d4de6aeSHaiying Wang
2142d4de6aeSHaiying Wang /* enable the microcode in IRAM */
2152d4de6aeSHaiying Wang out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
2162d4de6aeSHaiying Wang #endif
2172d4de6aeSHaiying Wang
21845bae2e3SSimon Glass gd->arch.mp_alloc_base = QE_DATAONLY_BASE;
21945bae2e3SSimon Glass gd->arch.mp_alloc_top = gd->arch.mp_alloc_base + QE_DATAONLY_SIZE;
2207737d5c6SDave Liu
2217737d5c6SDave Liu qe_sdma_init();
2227737d5c6SDave Liu qe_snums_init();
2237737d5c6SDave Liu }
2243bf46e6aSZhao Qiang #endif
225*c5e6637fSRajesh Bhagat #endif
2267737d5c6SDave Liu
22793d33204SZhao Qiang #ifdef CONFIG_U_QE
228*c5e6637fSRajesh Bhagat #ifdef CONFIG_TFABOOT
u_qe_init(void)229*c5e6637fSRajesh Bhagat void u_qe_init(void)
230*c5e6637fSRajesh Bhagat {
231*c5e6637fSRajesh Bhagat enum boot_src src = get_boot_src();
232*c5e6637fSRajesh Bhagat
233*c5e6637fSRajesh Bhagat qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
234*c5e6637fSRajesh Bhagat
235*c5e6637fSRajesh Bhagat void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
236*c5e6637fSRajesh Bhagat
237*c5e6637fSRajesh Bhagat if (src == BOOT_SOURCE_IFC_NOR)
238*c5e6637fSRajesh Bhagat addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_IFC_BASE);
239*c5e6637fSRajesh Bhagat
240*c5e6637fSRajesh Bhagat if (src == BOOT_SOURCE_QSPI_NOR)
241*c5e6637fSRajesh Bhagat addr = (void *)(CONFIG_SYS_QE_FW_ADDR + CONFIG_SYS_FSL_QSPI_BASE);
242*c5e6637fSRajesh Bhagat
243*c5e6637fSRajesh Bhagat if (src == BOOT_SOURCE_SD_MMC) {
244*c5e6637fSRajesh Bhagat int dev = CONFIG_SYS_MMC_ENV_DEV;
245*c5e6637fSRajesh Bhagat u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
246*c5e6637fSRajesh Bhagat u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
247*c5e6637fSRajesh Bhagat
248*c5e6637fSRajesh Bhagat if (mmc_initialize(gd->bd)) {
249*c5e6637fSRajesh Bhagat printf("%s: mmc_initialize() failed\n", __func__);
250*c5e6637fSRajesh Bhagat return;
251*c5e6637fSRajesh Bhagat }
252*c5e6637fSRajesh Bhagat addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
253*c5e6637fSRajesh Bhagat struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
254*c5e6637fSRajesh Bhagat
255*c5e6637fSRajesh Bhagat if (!mmc) {
256*c5e6637fSRajesh Bhagat free(addr);
257*c5e6637fSRajesh Bhagat printf("\nMMC cannot find device for ucode\n");
258*c5e6637fSRajesh Bhagat } else {
259*c5e6637fSRajesh Bhagat printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
260*c5e6637fSRajesh Bhagat dev, blk, cnt);
261*c5e6637fSRajesh Bhagat mmc_init(mmc);
262*c5e6637fSRajesh Bhagat (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
263*c5e6637fSRajesh Bhagat addr);
264*c5e6637fSRajesh Bhagat }
265*c5e6637fSRajesh Bhagat }
266*c5e6637fSRajesh Bhagat if (!u_qe_upload_firmware(addr))
267*c5e6637fSRajesh Bhagat out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
268*c5e6637fSRajesh Bhagat if (src == BOOT_SOURCE_SD_MMC)
269*c5e6637fSRajesh Bhagat free(addr);
270*c5e6637fSRajesh Bhagat }
271*c5e6637fSRajesh Bhagat #else
u_qe_init(void)27293d33204SZhao Qiang void u_qe_init(void)
27393d33204SZhao Qiang {
274d3e6d30cSZhao Qiang qe_immr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
27593d33204SZhao Qiang
2765aa03dddSZhao Qiang void *addr = (void *)CONFIG_SYS_QE_FW_ADDR;
2775aa03dddSZhao Qiang #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
2785aa03dddSZhao Qiang int dev = CONFIG_SYS_MMC_ENV_DEV;
2795aa03dddSZhao Qiang u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
2805aa03dddSZhao Qiang u32 blk = CONFIG_SYS_QE_FW_ADDR / 512;
2815aa03dddSZhao Qiang
2825aa03dddSZhao Qiang if (mmc_initialize(gd->bd)) {
2835aa03dddSZhao Qiang printf("%s: mmc_initialize() failed\n", __func__);
2845aa03dddSZhao Qiang return;
2855aa03dddSZhao Qiang }
2865aa03dddSZhao Qiang addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
2875aa03dddSZhao Qiang struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
2885aa03dddSZhao Qiang
2895aa03dddSZhao Qiang if (!mmc) {
2905aa03dddSZhao Qiang free(addr);
2915aa03dddSZhao Qiang printf("\nMMC cannot find device for ucode\n");
2925aa03dddSZhao Qiang } else {
2935aa03dddSZhao Qiang printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
2945aa03dddSZhao Qiang dev, blk, cnt);
2955aa03dddSZhao Qiang mmc_init(mmc);
296c3ced8a6SYinbo Zhu (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
2975aa03dddSZhao Qiang addr);
2985aa03dddSZhao Qiang }
2995aa03dddSZhao Qiang #endif
300a7a81756SZhao Qiang if (!u_qe_upload_firmware(addr))
30193d33204SZhao Qiang out_be32(&qe_immr->iram.iready, QE_IRAM_READY);
3025aa03dddSZhao Qiang #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC
3035aa03dddSZhao Qiang free(addr);
3045aa03dddSZhao Qiang #endif
30593d33204SZhao Qiang }
30693d33204SZhao Qiang #endif
307*c5e6637fSRajesh Bhagat #endif
30893d33204SZhao Qiang
309ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
u_qe_resume(void)310ae42eb03SZhao Qiang void u_qe_resume(void)
311ae42eb03SZhao Qiang {
312ae42eb03SZhao Qiang qe_map_t *qe_immrr;
313ae42eb03SZhao Qiang
314d3e6d30cSZhao Qiang qe_immrr = (qe_map_t *)(CONFIG_SYS_IMMR + QE_IMMR_OFFSET);
315ae42eb03SZhao Qiang u_qe_firmware_resume((const void *)CONFIG_SYS_QE_FW_ADDR, qe_immrr);
316ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iready, QE_IRAM_READY);
317ae42eb03SZhao Qiang }
318ae42eb03SZhao Qiang #endif
319ae42eb03SZhao Qiang
qe_reset(void)3207737d5c6SDave Liu void qe_reset(void)
3217737d5c6SDave Liu {
3227737d5c6SDave Liu qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
3237737d5c6SDave Liu (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
3247737d5c6SDave Liu }
3257737d5c6SDave Liu
3263bf46e6aSZhao Qiang #ifdef CONFIG_QE
qe_assign_page(uint snum,uint para_ram_base)3277737d5c6SDave Liu void qe_assign_page(uint snum, uint para_ram_base)
3287737d5c6SDave Liu {
3297737d5c6SDave Liu u32 cecr;
3307737d5c6SDave Liu
3317737d5c6SDave Liu out_be32(&qe_immr->cp.cecdr, para_ram_base);
3327737d5c6SDave Liu out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
3337737d5c6SDave Liu | QE_CR_FLG | QE_ASSIGN_PAGE);
3347737d5c6SDave Liu
3357737d5c6SDave Liu /* Wait for the QE_CR_FLG to clear */
3367737d5c6SDave Liu do {
3377737d5c6SDave Liu cecr = in_be32(&qe_immr->cp.cecr);
3387737d5c6SDave Liu } while (cecr & QE_CR_FLG );
3397737d5c6SDave Liu
3407737d5c6SDave Liu return;
3417737d5c6SDave Liu }
3423bf46e6aSZhao Qiang #endif
3437737d5c6SDave Liu
3447737d5c6SDave Liu /*
3457737d5c6SDave Liu * brg: 0~15 as BRG1~BRG16
3467737d5c6SDave Liu rate: baud rate
3477737d5c6SDave Liu * BRG input clock comes from the BRGCLK (internal clock generated from
3487737d5c6SDave Liu the QE clock, it is one-half of the QE clock), If need the clock source
3497737d5c6SDave Liu from CLKn pin, we have te change the function.
3507737d5c6SDave Liu */
3517737d5c6SDave Liu
3521206c184SSimon Glass #define BRG_CLK (gd->arch.brg_clk)
3537737d5c6SDave Liu
35493d33204SZhao Qiang #ifdef CONFIG_QE
qe_set_brg(uint brg,uint rate)3557737d5c6SDave Liu int qe_set_brg(uint brg, uint rate)
3567737d5c6SDave Liu {
3577737d5c6SDave Liu volatile uint *bp;
3587737d5c6SDave Liu u32 divisor;
3597737d5c6SDave Liu int div16 = 0;
3607737d5c6SDave Liu
3617737d5c6SDave Liu if (brg >= QE_NUM_OF_BRGS)
3627737d5c6SDave Liu return -EINVAL;
3637737d5c6SDave Liu bp = (uint *)&qe_immr->brg.brgc1;
3647737d5c6SDave Liu bp += brg;
3657737d5c6SDave Liu
3667737d5c6SDave Liu divisor = (BRG_CLK / rate);
3677737d5c6SDave Liu if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
3687737d5c6SDave Liu div16 = 1;
3697737d5c6SDave Liu divisor /= 16;
3707737d5c6SDave Liu }
3717737d5c6SDave Liu
3727737d5c6SDave Liu *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
3737737d5c6SDave Liu __asm__ __volatile__("sync");
3747737d5c6SDave Liu
3757737d5c6SDave Liu if (div16) {
3767737d5c6SDave Liu *bp |= QE_BRGC_DIV16;
3777737d5c6SDave Liu __asm__ __volatile__("sync");
3787737d5c6SDave Liu }
3797737d5c6SDave Liu
3807737d5c6SDave Liu return 0;
3817737d5c6SDave Liu }
38293d33204SZhao Qiang #endif
3837737d5c6SDave Liu
3847737d5c6SDave Liu /* Set ethernet MII clock master
3857737d5c6SDave Liu */
qe_set_mii_clk_src(int ucc_num)3867737d5c6SDave Liu int qe_set_mii_clk_src(int ucc_num)
3877737d5c6SDave Liu {
3887737d5c6SDave Liu u32 cmxgcr;
3897737d5c6SDave Liu
3907737d5c6SDave Liu /* check if the UCC number is in range. */
3917737d5c6SDave Liu if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
3927737d5c6SDave Liu printf("%s: ucc num not in ranges\n", __FUNCTION__);
3937737d5c6SDave Liu return -EINVAL;
3947737d5c6SDave Liu }
3957737d5c6SDave Liu
3967737d5c6SDave Liu cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
3977737d5c6SDave Liu cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
3987737d5c6SDave Liu cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
3997737d5c6SDave Liu out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
4007737d5c6SDave Liu
4017737d5c6SDave Liu return 0;
4027737d5c6SDave Liu }
4037737d5c6SDave Liu
404b8ec2385STimur Tabi /* Firmware information stored here for qe_get_firmware_info() */
405b8ec2385STimur Tabi static struct qe_firmware_info qe_firmware_info;
406b8ec2385STimur Tabi
407b8ec2385STimur Tabi /*
408b8ec2385STimur Tabi * Set to 1 if QE firmware has been uploaded, and therefore
409b8ec2385STimur Tabi * qe_firmware_info contains valid data.
410b8ec2385STimur Tabi */
411b8ec2385STimur Tabi static int qe_firmware_uploaded;
412b8ec2385STimur Tabi
413b8ec2385STimur Tabi /*
414b8ec2385STimur Tabi * Upload a QE microcode
415b8ec2385STimur Tabi *
416b8ec2385STimur Tabi * This function is a worker function for qe_upload_firmware(). It does
417b8ec2385STimur Tabi * the actual uploading of the microcode.
418b8ec2385STimur Tabi */
qe_upload_microcode(const void * base,const struct qe_microcode * ucode)419b8ec2385STimur Tabi static void qe_upload_microcode(const void *base,
420b8ec2385STimur Tabi const struct qe_microcode *ucode)
421b8ec2385STimur Tabi {
422b8ec2385STimur Tabi const u32 *code = base + be32_to_cpu(ucode->code_offset);
423b8ec2385STimur Tabi unsigned int i;
424b8ec2385STimur Tabi
425b8ec2385STimur Tabi if (ucode->major || ucode->minor || ucode->revision)
426b8ec2385STimur Tabi printf("QE: uploading microcode '%s' version %u.%u.%u\n",
427e94a8fd3SZhao Qiang (char *)ucode->id, (u16)ucode->major, (u16)ucode->minor,
428e94a8fd3SZhao Qiang (u16)ucode->revision);
429b8ec2385STimur Tabi else
430e94a8fd3SZhao Qiang printf("QE: uploading microcode '%s'\n", (char *)ucode->id);
431b8ec2385STimur Tabi
432b8ec2385STimur Tabi /* Use auto-increment */
433b8ec2385STimur Tabi out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
434b8ec2385STimur Tabi QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
435b8ec2385STimur Tabi
436b8ec2385STimur Tabi for (i = 0; i < be32_to_cpu(ucode->count); i++)
437b8ec2385STimur Tabi out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
438b8ec2385STimur Tabi }
439b8ec2385STimur Tabi
440b8ec2385STimur Tabi /*
441b8ec2385STimur Tabi * Upload a microcode to the I-RAM at a specific address.
442b8ec2385STimur Tabi *
443b8ec2385STimur Tabi * See docs/README.qe_firmware for information on QE microcode uploading.
444b8ec2385STimur Tabi *
445b8ec2385STimur Tabi * Currently, only version 1 is supported, so the 'version' field must be
446b8ec2385STimur Tabi * set to 1.
447b8ec2385STimur Tabi *
448b8ec2385STimur Tabi * The SOC model and revision are not validated, they are only displayed for
449b8ec2385STimur Tabi * informational purposes.
450b8ec2385STimur Tabi *
451b8ec2385STimur Tabi * 'calc_size' is the calculated size, in bytes, of the firmware structure and
452b8ec2385STimur Tabi * all of the microcode structures, minus the CRC.
453b8ec2385STimur Tabi *
454b8ec2385STimur Tabi * 'length' is the size that the structure says it is, including the CRC.
455b8ec2385STimur Tabi */
qe_upload_firmware(const struct qe_firmware * firmware)456b8ec2385STimur Tabi int qe_upload_firmware(const struct qe_firmware *firmware)
457b8ec2385STimur Tabi {
458b8ec2385STimur Tabi unsigned int i;
459b8ec2385STimur Tabi unsigned int j;
460b8ec2385STimur Tabi u32 crc;
461b8ec2385STimur Tabi size_t calc_size = sizeof(struct qe_firmware);
462b8ec2385STimur Tabi size_t length;
463b8ec2385STimur Tabi const struct qe_header *hdr;
464ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
46573fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A
4669c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
4679c7c86f4SZhao Qiang #else
468ca721fb2SZhao Qiang ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
469ca721fb2SZhao Qiang #endif
4709c7c86f4SZhao Qiang #endif
471b8ec2385STimur Tabi if (!firmware) {
472b8ec2385STimur Tabi printf("Invalid address\n");
473b8ec2385STimur Tabi return -EINVAL;
474b8ec2385STimur Tabi }
475b8ec2385STimur Tabi
476b8ec2385STimur Tabi hdr = &firmware->header;
477b8ec2385STimur Tabi length = be32_to_cpu(hdr->length);
478b8ec2385STimur Tabi
479b8ec2385STimur Tabi /* Check the magic */
480b8ec2385STimur Tabi if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
481b8ec2385STimur Tabi (hdr->magic[2] != 'F')) {
48212eeb135SVijay Rai printf("QE microcode not found\n");
483ca721fb2SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
484ca721fb2SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
485ca721fb2SZhao Qiang #endif
486b8ec2385STimur Tabi return -EPERM;
487b8ec2385STimur Tabi }
488b8ec2385STimur Tabi
489b8ec2385STimur Tabi /* Check the version */
490b8ec2385STimur Tabi if (hdr->version != 1) {
491b8ec2385STimur Tabi printf("Unsupported version\n");
492b8ec2385STimur Tabi return -EPERM;
493b8ec2385STimur Tabi }
494b8ec2385STimur Tabi
495b8ec2385STimur Tabi /* Validate some of the fields */
496491fb6deSTimur Tabi if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
497b8ec2385STimur Tabi printf("Invalid data\n");
498b8ec2385STimur Tabi return -EINVAL;
499b8ec2385STimur Tabi }
500b8ec2385STimur Tabi
501b8ec2385STimur Tabi /* Validate the length and check if there's a CRC */
502b8ec2385STimur Tabi calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
503b8ec2385STimur Tabi
504b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++)
505b8ec2385STimur Tabi /*
506b8ec2385STimur Tabi * For situations where the second RISC uses the same microcode
507b8ec2385STimur Tabi * as the first, the 'code_offset' and 'count' fields will be
508b8ec2385STimur Tabi * zero, so it's okay to add those.
509b8ec2385STimur Tabi */
510b8ec2385STimur Tabi calc_size += sizeof(u32) *
511b8ec2385STimur Tabi be32_to_cpu(firmware->microcode[i].count);
512b8ec2385STimur Tabi
513b8ec2385STimur Tabi /* Validate the length */
514b8ec2385STimur Tabi if (length != calc_size + sizeof(u32)) {
515b8ec2385STimur Tabi printf("Invalid length\n");
516b8ec2385STimur Tabi return -EPERM;
517b8ec2385STimur Tabi }
518b8ec2385STimur Tabi
519b8ec2385STimur Tabi /*
520b8ec2385STimur Tabi * Validate the CRC. We would normally call crc32_no_comp(), but that
521b8ec2385STimur Tabi * function isn't available unless you turn on JFFS support.
522b8ec2385STimur Tabi */
523b8ec2385STimur Tabi crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
524b8ec2385STimur Tabi if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
525b8ec2385STimur Tabi printf("Firmware CRC is invalid\n");
526b8ec2385STimur Tabi return -EIO;
527b8ec2385STimur Tabi }
528b8ec2385STimur Tabi
529b8ec2385STimur Tabi /*
530b8ec2385STimur Tabi * If the microcode calls for it, split the I-RAM.
531b8ec2385STimur Tabi */
532b8ec2385STimur Tabi if (!firmware->split) {
533b8ec2385STimur Tabi out_be16(&qe_immr->cp.cercr,
534b8ec2385STimur Tabi in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
535b8ec2385STimur Tabi }
536b8ec2385STimur Tabi
537b8ec2385STimur Tabi if (firmware->soc.model)
538b8ec2385STimur Tabi printf("Firmware '%s' for %u V%u.%u\n",
539b8ec2385STimur Tabi firmware->id, be16_to_cpu(firmware->soc.model),
540b8ec2385STimur Tabi firmware->soc.major, firmware->soc.minor);
541b8ec2385STimur Tabi else
542b8ec2385STimur Tabi printf("Firmware '%s'\n", firmware->id);
543b8ec2385STimur Tabi
544b8ec2385STimur Tabi /*
545b8ec2385STimur Tabi * The QE only supports one microcode per RISC, so clear out all the
546b8ec2385STimur Tabi * saved microcode information and put in the new.
547b8ec2385STimur Tabi */
548b8ec2385STimur Tabi memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
5490e0224eeSZhao Qiang strncpy(qe_firmware_info.id, (char *)firmware->id, 62);
550b8ec2385STimur Tabi qe_firmware_info.extended_modes = firmware->extended_modes;
551b8ec2385STimur Tabi memcpy(qe_firmware_info.vtraps, firmware->vtraps,
552b8ec2385STimur Tabi sizeof(firmware->vtraps));
553b8ec2385STimur Tabi qe_firmware_uploaded = 1;
554b8ec2385STimur Tabi
555b8ec2385STimur Tabi /* Loop through each microcode. */
556b8ec2385STimur Tabi for (i = 0; i < firmware->count; i++) {
557b8ec2385STimur Tabi const struct qe_microcode *ucode = &firmware->microcode[i];
558b8ec2385STimur Tabi
559b8ec2385STimur Tabi /* Upload a microcode if it's present */
560b8ec2385STimur Tabi if (ucode->code_offset)
561b8ec2385STimur Tabi qe_upload_microcode(firmware, ucode);
562b8ec2385STimur Tabi
563b8ec2385STimur Tabi /* Program the traps for this processor */
564b8ec2385STimur Tabi for (j = 0; j < 16; j++) {
565b8ec2385STimur Tabi u32 trap = be32_to_cpu(ucode->traps[j]);
566b8ec2385STimur Tabi
567b8ec2385STimur Tabi if (trap)
568b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].tibcr[j], trap);
569b8ec2385STimur Tabi }
570b8ec2385STimur Tabi
571b8ec2385STimur Tabi /* Enable traps */
572b8ec2385STimur Tabi out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
573b8ec2385STimur Tabi }
574b8ec2385STimur Tabi
575b8ec2385STimur Tabi return 0;
576b8ec2385STimur Tabi }
577b8ec2385STimur Tabi
5785632d15cSZhao Qiang #ifdef CONFIG_U_QE
5795632d15cSZhao Qiang /*
5805632d15cSZhao Qiang * Upload a microcode to the I-RAM at a specific address.
5815632d15cSZhao Qiang *
5825632d15cSZhao Qiang * See docs/README.qe_firmware for information on QE microcode uploading.
5835632d15cSZhao Qiang *
5845632d15cSZhao Qiang * Currently, only version 1 is supported, so the 'version' field must be
5855632d15cSZhao Qiang * set to 1.
5865632d15cSZhao Qiang *
5875632d15cSZhao Qiang * The SOC model and revision are not validated, they are only displayed for
5885632d15cSZhao Qiang * informational purposes.
5895632d15cSZhao Qiang *
5905632d15cSZhao Qiang * 'calc_size' is the calculated size, in bytes, of the firmware structure and
5915632d15cSZhao Qiang * all of the microcode structures, minus the CRC.
5925632d15cSZhao Qiang *
5935632d15cSZhao Qiang * 'length' is the size that the structure says it is, including the CRC.
5945632d15cSZhao Qiang */
u_qe_upload_firmware(const struct qe_firmware * firmware)5955632d15cSZhao Qiang int u_qe_upload_firmware(const struct qe_firmware *firmware)
5965632d15cSZhao Qiang {
5975632d15cSZhao Qiang unsigned int i;
5985632d15cSZhao Qiang unsigned int j;
5995632d15cSZhao Qiang u32 crc;
6005632d15cSZhao Qiang size_t calc_size = sizeof(struct qe_firmware);
6015632d15cSZhao Qiang size_t length;
6025632d15cSZhao Qiang const struct qe_header *hdr;
6035632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
60473fb5838SYork Sun #ifdef CONFIG_ARCH_LS1021A
6059c7c86f4SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
6069c7c86f4SZhao Qiang #else
6075632d15cSZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
6085632d15cSZhao Qiang #endif
6099c7c86f4SZhao Qiang #endif
6105632d15cSZhao Qiang if (!firmware) {
6115632d15cSZhao Qiang printf("Invalid address\n");
6125632d15cSZhao Qiang return -EINVAL;
6135632d15cSZhao Qiang }
6145632d15cSZhao Qiang
6155632d15cSZhao Qiang hdr = &firmware->header;
6165632d15cSZhao Qiang length = be32_to_cpu(hdr->length);
6175632d15cSZhao Qiang
6185632d15cSZhao Qiang /* Check the magic */
6195632d15cSZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
6205632d15cSZhao Qiang (hdr->magic[2] != 'F')) {
6215632d15cSZhao Qiang printf("Not a microcode\n");
6225632d15cSZhao Qiang #ifdef CONFIG_DEEP_SLEEP
6235632d15cSZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
6245632d15cSZhao Qiang #endif
6255632d15cSZhao Qiang return -EPERM;
6265632d15cSZhao Qiang }
6275632d15cSZhao Qiang
6285632d15cSZhao Qiang /* Check the version */
6295632d15cSZhao Qiang if (hdr->version != 1) {
6305632d15cSZhao Qiang printf("Unsupported version\n");
6315632d15cSZhao Qiang return -EPERM;
6325632d15cSZhao Qiang }
6335632d15cSZhao Qiang
6345632d15cSZhao Qiang /* Validate some of the fields */
6355632d15cSZhao Qiang if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
6365632d15cSZhao Qiang printf("Invalid data\n");
6375632d15cSZhao Qiang return -EINVAL;
6385632d15cSZhao Qiang }
6395632d15cSZhao Qiang
6405632d15cSZhao Qiang /* Validate the length and check if there's a CRC */
6415632d15cSZhao Qiang calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
6425632d15cSZhao Qiang
6435632d15cSZhao Qiang for (i = 0; i < firmware->count; i++)
6445632d15cSZhao Qiang /*
6455632d15cSZhao Qiang * For situations where the second RISC uses the same microcode
6465632d15cSZhao Qiang * as the first, the 'code_offset' and 'count' fields will be
6475632d15cSZhao Qiang * zero, so it's okay to add those.
6485632d15cSZhao Qiang */
6495632d15cSZhao Qiang calc_size += sizeof(u32) *
6505632d15cSZhao Qiang be32_to_cpu(firmware->microcode[i].count);
6515632d15cSZhao Qiang
6525632d15cSZhao Qiang /* Validate the length */
6535632d15cSZhao Qiang if (length != calc_size + sizeof(u32)) {
6545632d15cSZhao Qiang printf("Invalid length\n");
6555632d15cSZhao Qiang return -EPERM;
6565632d15cSZhao Qiang }
6575632d15cSZhao Qiang
6585632d15cSZhao Qiang /*
6595632d15cSZhao Qiang * Validate the CRC. We would normally call crc32_no_comp(), but that
6605632d15cSZhao Qiang * function isn't available unless you turn on JFFS support.
6615632d15cSZhao Qiang */
6625632d15cSZhao Qiang crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
6635632d15cSZhao Qiang if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
6645632d15cSZhao Qiang printf("Firmware CRC is invalid\n");
6655632d15cSZhao Qiang return -EIO;
6665632d15cSZhao Qiang }
6675632d15cSZhao Qiang
6685632d15cSZhao Qiang /*
6695632d15cSZhao Qiang * If the microcode calls for it, split the I-RAM.
6705632d15cSZhao Qiang */
6715632d15cSZhao Qiang if (!firmware->split) {
6725632d15cSZhao Qiang out_be16(&qe_immr->cp.cercr,
6735632d15cSZhao Qiang in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
6745632d15cSZhao Qiang }
6755632d15cSZhao Qiang
6765632d15cSZhao Qiang if (firmware->soc.model)
6775632d15cSZhao Qiang printf("Firmware '%s' for %u V%u.%u\n",
6785632d15cSZhao Qiang firmware->id, be16_to_cpu(firmware->soc.model),
6795632d15cSZhao Qiang firmware->soc.major, firmware->soc.minor);
6805632d15cSZhao Qiang else
6815632d15cSZhao Qiang printf("Firmware '%s'\n", firmware->id);
6825632d15cSZhao Qiang
6835632d15cSZhao Qiang /* Loop through each microcode. */
6845632d15cSZhao Qiang for (i = 0; i < firmware->count; i++) {
6855632d15cSZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i];
6865632d15cSZhao Qiang
6875632d15cSZhao Qiang /* Upload a microcode if it's present */
6885632d15cSZhao Qiang if (ucode->code_offset)
6895632d15cSZhao Qiang qe_upload_microcode(firmware, ucode);
6905632d15cSZhao Qiang
6915632d15cSZhao Qiang /* Program the traps for this processor */
6925632d15cSZhao Qiang for (j = 0; j < 16; j++) {
6935632d15cSZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]);
6945632d15cSZhao Qiang
6955632d15cSZhao Qiang if (trap)
6965632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].tibcr[j], trap);
6975632d15cSZhao Qiang }
6985632d15cSZhao Qiang
6995632d15cSZhao Qiang /* Enable traps */
7005632d15cSZhao Qiang out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
7015632d15cSZhao Qiang }
7025632d15cSZhao Qiang
7035632d15cSZhao Qiang return 0;
7045632d15cSZhao Qiang }
7055632d15cSZhao Qiang #endif
7065632d15cSZhao Qiang
707ae42eb03SZhao Qiang #ifdef CONFIG_U_QE
u_qe_firmware_resume(const struct qe_firmware * firmware,qe_map_t * qe_immrr)708ae42eb03SZhao Qiang int u_qe_firmware_resume(const struct qe_firmware *firmware, qe_map_t *qe_immrr)
709ae42eb03SZhao Qiang {
710ae42eb03SZhao Qiang unsigned int i;
711ae42eb03SZhao Qiang unsigned int j;
712ae42eb03SZhao Qiang const struct qe_header *hdr;
713ae42eb03SZhao Qiang const u32 *code;
714ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
715ae42eb03SZhao Qiang #ifdef CONFIG_PPC
716ae42eb03SZhao Qiang ccsr_gur_t __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
717ae42eb03SZhao Qiang #else
718ae42eb03SZhao Qiang struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
719ae42eb03SZhao Qiang #endif
720ae42eb03SZhao Qiang #endif
721ae42eb03SZhao Qiang
722ae42eb03SZhao Qiang if (!firmware)
723ae42eb03SZhao Qiang return -EINVAL;
724ae42eb03SZhao Qiang
725ae42eb03SZhao Qiang hdr = &firmware->header;
726ae42eb03SZhao Qiang
727ae42eb03SZhao Qiang /* Check the magic */
728ae42eb03SZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
729ae42eb03SZhao Qiang (hdr->magic[2] != 'F')) {
730ae42eb03SZhao Qiang #ifdef CONFIG_DEEP_SLEEP
731ae42eb03SZhao Qiang setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
732ae42eb03SZhao Qiang #endif
733ae42eb03SZhao Qiang return -EPERM;
734ae42eb03SZhao Qiang }
735ae42eb03SZhao Qiang
736ae42eb03SZhao Qiang /*
737ae42eb03SZhao Qiang * If the microcode calls for it, split the I-RAM.
738ae42eb03SZhao Qiang */
739ae42eb03SZhao Qiang if (!firmware->split) {
740ae42eb03SZhao Qiang out_be16(&qe_immrr->cp.cercr,
741ae42eb03SZhao Qiang in_be16(&qe_immrr->cp.cercr) | QE_CP_CERCR_CIR);
742ae42eb03SZhao Qiang }
743ae42eb03SZhao Qiang
744ae42eb03SZhao Qiang /* Loop through each microcode. */
745ae42eb03SZhao Qiang for (i = 0; i < firmware->count; i++) {
746ae42eb03SZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i];
747ae42eb03SZhao Qiang
748ae42eb03SZhao Qiang /* Upload a microcode if it's present */
749ae42eb03SZhao Qiang if (!ucode->code_offset)
750ae42eb03SZhao Qiang return 0;
751ae42eb03SZhao Qiang
752ae42eb03SZhao Qiang code = (const void *)firmware + be32_to_cpu(ucode->code_offset);
753ae42eb03SZhao Qiang
754ae42eb03SZhao Qiang /* Use auto-increment */
755ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
756ae42eb03SZhao Qiang QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
757ae42eb03SZhao Qiang
758ae42eb03SZhao Qiang for (i = 0; i < be32_to_cpu(ucode->count); i++)
759ae42eb03SZhao Qiang out_be32(&qe_immrr->iram.idata, be32_to_cpu(code[i]));
760ae42eb03SZhao Qiang
761ae42eb03SZhao Qiang /* Program the traps for this processor */
762ae42eb03SZhao Qiang for (j = 0; j < 16; j++) {
763ae42eb03SZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]);
764ae42eb03SZhao Qiang
765ae42eb03SZhao Qiang if (trap)
766ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].tibcr[j], trap);
767ae42eb03SZhao Qiang }
768ae42eb03SZhao Qiang
769ae42eb03SZhao Qiang /* Enable traps */
770ae42eb03SZhao Qiang out_be32(&qe_immrr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
771ae42eb03SZhao Qiang }
772ae42eb03SZhao Qiang
773ae42eb03SZhao Qiang return 0;
774ae42eb03SZhao Qiang }
775ae42eb03SZhao Qiang #endif
776ae42eb03SZhao Qiang
qe_get_firmware_info(void)777b8ec2385STimur Tabi struct qe_firmware_info *qe_get_firmware_info(void)
778b8ec2385STimur Tabi {
779b8ec2385STimur Tabi return qe_firmware_uploaded ? &qe_firmware_info : NULL;
780b8ec2385STimur Tabi }
781b8ec2385STimur Tabi
qe_cmd(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])78254841ab5SWolfgang Denk static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
783b8ec2385STimur Tabi {
784b8ec2385STimur Tabi ulong addr;
785b8ec2385STimur Tabi
78647e26b1bSWolfgang Denk if (argc < 3)
78747e26b1bSWolfgang Denk return cmd_usage(cmdtp);
788b8ec2385STimur Tabi
789b8ec2385STimur Tabi if (strcmp(argv[1], "fw") == 0) {
790b8ec2385STimur Tabi addr = simple_strtoul(argv[2], NULL, 16);
791b8ec2385STimur Tabi
792b8ec2385STimur Tabi if (!addr) {
793b8ec2385STimur Tabi printf("Invalid address\n");
794b8ec2385STimur Tabi return -EINVAL;
795b8ec2385STimur Tabi }
796b8ec2385STimur Tabi
797b8ec2385STimur Tabi /*
798b8ec2385STimur Tabi * If a length was supplied, compare that with the 'length'
799b8ec2385STimur Tabi * field.
800b8ec2385STimur Tabi */
801b8ec2385STimur Tabi
802b8ec2385STimur Tabi if (argc > 3) {
803b8ec2385STimur Tabi ulong length = simple_strtoul(argv[3], NULL, 16);
804b8ec2385STimur Tabi struct qe_firmware *firmware = (void *) addr;
805b8ec2385STimur Tabi
806b8ec2385STimur Tabi if (length != be32_to_cpu(firmware->header.length)) {
807b8ec2385STimur Tabi printf("Length mismatch\n");
808b8ec2385STimur Tabi return -EINVAL;
809b8ec2385STimur Tabi }
810b8ec2385STimur Tabi }
811b8ec2385STimur Tabi
812b8ec2385STimur Tabi return qe_upload_firmware((const struct qe_firmware *) addr);
813b8ec2385STimur Tabi }
814b8ec2385STimur Tabi
81547e26b1bSWolfgang Denk return cmd_usage(cmdtp);
816b8ec2385STimur Tabi }
817b8ec2385STimur Tabi
818b8ec2385STimur Tabi U_BOOT_CMD(
819b8ec2385STimur Tabi qe, 4, 0, qe_cmd,
8202fb2604dSPeter Tyser "QUICC Engine commands",
821b8ec2385STimur Tabi "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
822a89c33dbSWolfgang Denk "the QE,\n"
823a89c33dbSWolfgang Denk "\twith optional length <length> verification."
824b8ec2385STimur Tabi );
825