183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c916d7c9SKumar Gala /*
3c916d7c9SKumar Gala * Copyright 2009-2011 Freescale Semiconductor, Inc.
4c916d7c9SKumar Gala * Dave Liu <daveliu@freescale.com>
5c916d7c9SKumar Gala */
6c916d7c9SKumar Gala #include <common.h>
7c916d7c9SKumar Gala #include <malloc.h>
8c916d7c9SKumar Gala #include <asm/io.h>
91221ce45SMasahiro Yamada #include <linux/errno.h>
10c916d7c9SKumar Gala
11c916d7c9SKumar Gala #include "fm.h"
122459afb1SQianyu Gong #include <fsl_qe.h> /* For struct qe_firmware */
13c916d7c9SKumar Gala
14c916d7c9SKumar Gala #include <nand.h>
15c916d7c9SKumar Gala #include <spi_flash.h>
16c916d7c9SKumar Gala #include <mmc.h>
17*382c53f9SRajesh Bhagat #include <environment.h>
18*382c53f9SRajesh Bhagat
19*382c53f9SRajesh Bhagat #ifdef CONFIG_ARM64
20*382c53f9SRajesh Bhagat #include <asm/armv8/mmu.h>
21*382c53f9SRajesh Bhagat #include <asm/arch/cpu.h>
22c916d7c9SKumar Gala #endif
23c916d7c9SKumar Gala
24c916d7c9SKumar Gala struct fm_muram muram[CONFIG_SYS_NUM_FMAN];
25c916d7c9SKumar Gala
fm_muram_base(int fm_idx)269fc29db1SHou Zhiqiang void *fm_muram_base(int fm_idx)
27c916d7c9SKumar Gala {
28c916d7c9SKumar Gala return muram[fm_idx].base;
29c916d7c9SKumar Gala }
30c916d7c9SKumar Gala
fm_muram_alloc(int fm_idx,size_t size,ulong align)319fc29db1SHou Zhiqiang void *fm_muram_alloc(int fm_idx, size_t size, ulong align)
32c916d7c9SKumar Gala {
339fc29db1SHou Zhiqiang void *ret;
349fc29db1SHou Zhiqiang ulong align_mask;
359fc29db1SHou Zhiqiang size_t off;
369fc29db1SHou Zhiqiang void *save;
37c916d7c9SKumar Gala
38c916d7c9SKumar Gala align_mask = align - 1;
39c916d7c9SKumar Gala save = muram[fm_idx].alloc;
40c916d7c9SKumar Gala
419fc29db1SHou Zhiqiang off = (ulong)save & align_mask;
42c916d7c9SKumar Gala if (off != 0)
43c916d7c9SKumar Gala muram[fm_idx].alloc += (align - off);
44c916d7c9SKumar Gala off = size & align_mask;
45c916d7c9SKumar Gala if (off != 0)
46c916d7c9SKumar Gala size += (align - off);
47c916d7c9SKumar Gala if ((muram[fm_idx].alloc + size) >= muram[fm_idx].top) {
48c916d7c9SKumar Gala muram[fm_idx].alloc = save;
49c916d7c9SKumar Gala printf("%s: run out of ram.\n", __func__);
509fc29db1SHou Zhiqiang return NULL;
51c916d7c9SKumar Gala }
52c916d7c9SKumar Gala
53c916d7c9SKumar Gala ret = muram[fm_idx].alloc;
54c916d7c9SKumar Gala muram[fm_idx].alloc += size;
55c916d7c9SKumar Gala memset((void *)ret, 0, size);
56c916d7c9SKumar Gala
57c916d7c9SKumar Gala return ret;
58c916d7c9SKumar Gala }
59c916d7c9SKumar Gala
fm_init_muram(int fm_idx,void * reg)60c916d7c9SKumar Gala static void fm_init_muram(int fm_idx, void *reg)
61c916d7c9SKumar Gala {
629fc29db1SHou Zhiqiang void *base = reg;
63c916d7c9SKumar Gala
64c916d7c9SKumar Gala muram[fm_idx].base = base;
65c916d7c9SKumar Gala muram[fm_idx].size = CONFIG_SYS_FM_MURAM_SIZE;
66c916d7c9SKumar Gala muram[fm_idx].alloc = base + FM_MURAM_RES_SIZE;
67c916d7c9SKumar Gala muram[fm_idx].top = base + CONFIG_SYS_FM_MURAM_SIZE;
68c916d7c9SKumar Gala }
69c916d7c9SKumar Gala
70c916d7c9SKumar Gala /*
71c916d7c9SKumar Gala * fm_upload_ucode - Fman microcode upload worker function
72c916d7c9SKumar Gala *
73c916d7c9SKumar Gala * This function does the actual uploading of an Fman microcode
74c916d7c9SKumar Gala * to an Fman.
75c916d7c9SKumar Gala */
fm_upload_ucode(int fm_idx,struct fm_imem * imem,u32 * ucode,unsigned int size)76c916d7c9SKumar Gala static void fm_upload_ucode(int fm_idx, struct fm_imem *imem,
77c916d7c9SKumar Gala u32 *ucode, unsigned int size)
78c916d7c9SKumar Gala {
79c916d7c9SKumar Gala unsigned int i;
80c916d7c9SKumar Gala unsigned int timeout = 1000000;
81c916d7c9SKumar Gala
82c916d7c9SKumar Gala /* enable address auto increase */
83c916d7c9SKumar Gala out_be32(&imem->iadd, IRAM_IADD_AIE);
84c916d7c9SKumar Gala /* write microcode to IRAM */
85c916d7c9SKumar Gala for (i = 0; i < size / 4; i++)
86648bde6dSHou Zhiqiang out_be32(&imem->idata, (be32_to_cpu(ucode[i])));
87c916d7c9SKumar Gala
88c916d7c9SKumar Gala /* verify if the writing is over */
89c916d7c9SKumar Gala out_be32(&imem->iadd, 0);
90648bde6dSHou Zhiqiang while ((in_be32(&imem->idata) != be32_to_cpu(ucode[0])) && --timeout)
91c916d7c9SKumar Gala ;
92c916d7c9SKumar Gala if (!timeout)
93c916d7c9SKumar Gala printf("Fman%u: microcode upload timeout\n", fm_idx + 1);
94c916d7c9SKumar Gala
95c916d7c9SKumar Gala /* enable microcode from IRAM */
96c916d7c9SKumar Gala out_be32(&imem->iready, IRAM_READY);
97c916d7c9SKumar Gala }
98c916d7c9SKumar Gala
99c916d7c9SKumar Gala /*
100c916d7c9SKumar Gala * Upload an Fman firmware
101c916d7c9SKumar Gala *
102c916d7c9SKumar Gala * This function is similar to qe_upload_firmware(), exception that it uploads
103c916d7c9SKumar Gala * a microcode to the Fman instead of the QE.
104c916d7c9SKumar Gala *
105c916d7c9SKumar Gala * Because the process for uploading a microcode to the Fman is similar for
106c916d7c9SKumar Gala * that of the QE, the QE firmware binary format is used for Fman microcode.
107c916d7c9SKumar Gala * It should be possible to unify these two functions, but for now we keep them
108c916d7c9SKumar Gala * separate.
109c916d7c9SKumar Gala */
fman_upload_firmware(int fm_idx,struct fm_imem * fm_imem,const struct qe_firmware * firmware)110c916d7c9SKumar Gala static int fman_upload_firmware(int fm_idx,
111c916d7c9SKumar Gala struct fm_imem *fm_imem,
112c916d7c9SKumar Gala const struct qe_firmware *firmware)
113c916d7c9SKumar Gala {
114c916d7c9SKumar Gala unsigned int i;
115c916d7c9SKumar Gala u32 crc;
116c916d7c9SKumar Gala size_t calc_size = sizeof(struct qe_firmware);
117c916d7c9SKumar Gala size_t length;
118c916d7c9SKumar Gala const struct qe_header *hdr;
119c916d7c9SKumar Gala
120c916d7c9SKumar Gala if (!firmware) {
121c916d7c9SKumar Gala printf("Fman%u: Invalid address for firmware\n", fm_idx + 1);
122c916d7c9SKumar Gala return -EINVAL;
123c916d7c9SKumar Gala }
124c916d7c9SKumar Gala
125c916d7c9SKumar Gala hdr = &firmware->header;
126c916d7c9SKumar Gala length = be32_to_cpu(hdr->length);
127c916d7c9SKumar Gala
128c916d7c9SKumar Gala /* Check the magic */
129c916d7c9SKumar Gala if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
130c916d7c9SKumar Gala (hdr->magic[2] != 'F')) {
131c916d7c9SKumar Gala printf("Fman%u: Data at %p is not a firmware\n", fm_idx + 1,
132c916d7c9SKumar Gala firmware);
133c916d7c9SKumar Gala return -EPERM;
134c916d7c9SKumar Gala }
135c916d7c9SKumar Gala
136c916d7c9SKumar Gala /* Check the version */
137c916d7c9SKumar Gala if (hdr->version != 1) {
138c916d7c9SKumar Gala printf("Fman%u: Unsupported firmware version %u\n", fm_idx + 1,
139c916d7c9SKumar Gala hdr->version);
140c916d7c9SKumar Gala return -EPERM;
141c916d7c9SKumar Gala }
142c916d7c9SKumar Gala
143c916d7c9SKumar Gala /* Validate some of the fields */
144c916d7c9SKumar Gala if ((firmware->count != 1)) {
145c916d7c9SKumar Gala printf("Fman%u: Invalid data in firmware header\n", fm_idx + 1);
146c916d7c9SKumar Gala return -EINVAL;
147c916d7c9SKumar Gala }
148c916d7c9SKumar Gala
149c916d7c9SKumar Gala /* Validate the length and check if there's a CRC */
150c916d7c9SKumar Gala calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
151c916d7c9SKumar Gala
152c916d7c9SKumar Gala for (i = 0; i < firmware->count; i++)
153c916d7c9SKumar Gala /*
154c916d7c9SKumar Gala * For situations where the second RISC uses the same microcode
155c916d7c9SKumar Gala * as the first, the 'code_offset' and 'count' fields will be
156c916d7c9SKumar Gala * zero, so it's okay to add those.
157c916d7c9SKumar Gala */
158c916d7c9SKumar Gala calc_size += sizeof(u32) *
159c916d7c9SKumar Gala be32_to_cpu(firmware->microcode[i].count);
160c916d7c9SKumar Gala
161c916d7c9SKumar Gala /* Validate the length */
162c916d7c9SKumar Gala if (length != calc_size + sizeof(u32)) {
163c916d7c9SKumar Gala printf("Fman%u: Invalid length in firmware header\n",
164c916d7c9SKumar Gala fm_idx + 1);
165c916d7c9SKumar Gala return -EPERM;
166c916d7c9SKumar Gala }
167c916d7c9SKumar Gala
168c916d7c9SKumar Gala /*
169c916d7c9SKumar Gala * Validate the CRC. We would normally call crc32_no_comp(), but that
170c916d7c9SKumar Gala * function isn't available unless you turn on JFFS support.
171c916d7c9SKumar Gala */
172c916d7c9SKumar Gala crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
173c916d7c9SKumar Gala if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
174c916d7c9SKumar Gala printf("Fman%u: Firmware CRC is invalid\n", fm_idx + 1);
175c916d7c9SKumar Gala return -EIO;
176c916d7c9SKumar Gala }
177c916d7c9SKumar Gala
178c916d7c9SKumar Gala /* Loop through each microcode. */
179c916d7c9SKumar Gala for (i = 0; i < firmware->count; i++) {
180c916d7c9SKumar Gala const struct qe_microcode *ucode = &firmware->microcode[i];
181c916d7c9SKumar Gala
182c916d7c9SKumar Gala /* Upload a microcode if it's present */
183648bde6dSHou Zhiqiang if (be32_to_cpu(ucode->code_offset)) {
184c916d7c9SKumar Gala u32 ucode_size;
185c916d7c9SKumar Gala u32 *code;
186c916d7c9SKumar Gala printf("Fman%u: Uploading microcode version %u.%u.%u\n",
187c916d7c9SKumar Gala fm_idx + 1, ucode->major, ucode->minor,
188c916d7c9SKumar Gala ucode->revision);
189648bde6dSHou Zhiqiang code = (void *)firmware +
190648bde6dSHou Zhiqiang be32_to_cpu(ucode->code_offset);
191648bde6dSHou Zhiqiang ucode_size = sizeof(u32) * be32_to_cpu(ucode->count);
192c916d7c9SKumar Gala fm_upload_ucode(fm_idx, fm_imem, code, ucode_size);
193c916d7c9SKumar Gala }
194c916d7c9SKumar Gala }
195c916d7c9SKumar Gala
196c916d7c9SKumar Gala return 0;
197c916d7c9SKumar Gala }
198c916d7c9SKumar Gala
fm_assign_risc(int port_id)199c916d7c9SKumar Gala static u32 fm_assign_risc(int port_id)
200c916d7c9SKumar Gala {
201c916d7c9SKumar Gala u32 risc_sel, val;
202c916d7c9SKumar Gala risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
203c916d7c9SKumar Gala val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
204c916d7c9SKumar Gala val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
205c916d7c9SKumar Gala
206c916d7c9SKumar Gala return val;
207c916d7c9SKumar Gala }
208c916d7c9SKumar Gala
fm_init_fpm(struct fm_fpm * fpm)209c916d7c9SKumar Gala static void fm_init_fpm(struct fm_fpm *fpm)
210c916d7c9SKumar Gala {
211c916d7c9SKumar Gala int i, port_id;
212c916d7c9SKumar Gala u32 val;
213c916d7c9SKumar Gala
214c916d7c9SKumar Gala setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC |
215c916d7c9SKumar Gala FMFPEE_CER | FMFPEE_DER);
216c916d7c9SKumar Gala
217c916d7c9SKumar Gala /* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
218c916d7c9SKumar Gala
219c916d7c9SKumar Gala /* offline/parser port */
220c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_OH_PORT; i++) {
221c916d7c9SKumar Gala port_id = OH_PORT_ID_BASE + i;
222c916d7c9SKumar Gala val = fm_assign_risc(port_id);
223c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val);
224c916d7c9SKumar Gala }
225c916d7c9SKumar Gala /* Rx 1G port */
226c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
227c916d7c9SKumar Gala port_id = RX_PORT_1G_BASE + i;
228c916d7c9SKumar Gala val = fm_assign_risc(port_id);
229c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val);
230c916d7c9SKumar Gala }
231c916d7c9SKumar Gala /* Tx 1G port */
232c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
233c916d7c9SKumar Gala port_id = TX_PORT_1G_BASE + i;
234c916d7c9SKumar Gala val = fm_assign_risc(port_id);
235c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val);
236c916d7c9SKumar Gala }
237c916d7c9SKumar Gala /* Rx 10G port */
238c916d7c9SKumar Gala port_id = RX_PORT_10G_BASE;
239c916d7c9SKumar Gala val = fm_assign_risc(port_id);
240c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val);
241c916d7c9SKumar Gala /* Tx 10G port */
242c916d7c9SKumar Gala port_id = TX_PORT_10G_BASE;
243c916d7c9SKumar Gala val = fm_assign_risc(port_id);
244c916d7c9SKumar Gala out_be32(&fpm->fpmprc, val);
245c916d7c9SKumar Gala
246c916d7c9SKumar Gala /* disable the dispatch limit in IM case */
247c916d7c9SKumar Gala out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE);
248c916d7c9SKumar Gala /* clear events */
249c916d7c9SKumar Gala out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT);
250c916d7c9SKumar Gala
251c916d7c9SKumar Gala /* clear risc events */
252c916d7c9SKumar Gala for (i = 0; i < 4; i++)
253c916d7c9SKumar Gala out_be32(&fpm->fpmcev[i], 0xffffffff);
254c916d7c9SKumar Gala
255c916d7c9SKumar Gala /* clear error */
256c916d7c9SKumar Gala out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC);
257c916d7c9SKumar Gala }
258c916d7c9SKumar Gala
fm_init_bmi(int fm_idx,struct fm_bmi_common * bmi)259c916d7c9SKumar Gala static int fm_init_bmi(int fm_idx, struct fm_bmi_common *bmi)
260c916d7c9SKumar Gala {
261c916d7c9SKumar Gala int blk, i, port_id;
2629fc29db1SHou Zhiqiang u32 val;
2639fc29db1SHou Zhiqiang size_t offset;
2649fc29db1SHou Zhiqiang void *base;
265c916d7c9SKumar Gala
266c916d7c9SKumar Gala /* alloc free buffer pool in MURAM */
267c916d7c9SKumar Gala base = fm_muram_alloc(fm_idx, FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN);
268c916d7c9SKumar Gala if (!base) {
269c916d7c9SKumar Gala printf("%s: no muram for free buffer pool\n", __func__);
270c916d7c9SKumar Gala return -ENOMEM;
271c916d7c9SKumar Gala }
272c916d7c9SKumar Gala offset = base - fm_muram_base(fm_idx);
273c916d7c9SKumar Gala
274c916d7c9SKumar Gala /* Need 128KB total free buffer pool size */
275c916d7c9SKumar Gala val = offset / 256;
276c916d7c9SKumar Gala blk = FM_FREE_POOL_SIZE / 256;
277c916d7c9SKumar Gala /* in IM, we must not begin from offset 0 in MURAM */
278c916d7c9SKumar Gala val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
279c916d7c9SKumar Gala out_be32(&bmi->fmbm_cfg1, val);
280c916d7c9SKumar Gala
281c916d7c9SKumar Gala /* disable all BMI interrupt */
282c916d7c9SKumar Gala out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
283c916d7c9SKumar Gala
284c916d7c9SKumar Gala /* clear all events */
285c916d7c9SKumar Gala out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
286c916d7c9SKumar Gala
287c916d7c9SKumar Gala /*
288c916d7c9SKumar Gala * set port parameters - FMBM_PP_x
289c916d7c9SKumar Gala * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
290c916d7c9SKumar Gala * max dma 10G Rx/Tx=3, others is 1
291c916d7c9SKumar Gala * set port FIFO size - FMBM_PFS_x
292c916d7c9SKumar Gala * 4KB for all Rx and Tx ports
293c916d7c9SKumar Gala */
294c916d7c9SKumar Gala /* offline/parser port */
295c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_OH_PORT; i++) {
296c916d7c9SKumar Gala port_id = OH_PORT_ID_BASE + i - 1;
297c916d7c9SKumar Gala /* max tasks=1, max dma=1, no extra */
298c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], 0);
299c916d7c9SKumar Gala /* port FIFO size - 256 bytes, no extra */
300c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], 0);
301c916d7c9SKumar Gala }
302c916d7c9SKumar Gala /* Rx 1G port */
303c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
304c916d7c9SKumar Gala port_id = RX_PORT_1G_BASE + i - 1;
305c916d7c9SKumar Gala /* max tasks=4, max dma=1, no extra */
306c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
307c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */
308c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
309c916d7c9SKumar Gala }
310c916d7c9SKumar Gala /* Tx 1G port FIFO size - 4KB, no extra */
311c916d7c9SKumar Gala for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
312c916d7c9SKumar Gala port_id = TX_PORT_1G_BASE + i - 1;
313c916d7c9SKumar Gala /* max tasks=4, max dma=1, no extra */
314c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
315c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */
316c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
317c916d7c9SKumar Gala }
318c916d7c9SKumar Gala /* Rx 10G port */
319c916d7c9SKumar Gala port_id = RX_PORT_10G_BASE - 1;
320c916d7c9SKumar Gala /* max tasks=12, max dma=3, no extra */
321c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
322c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */
323c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
324c916d7c9SKumar Gala
325c916d7c9SKumar Gala /* Tx 10G port */
326c916d7c9SKumar Gala port_id = TX_PORT_10G_BASE - 1;
327c916d7c9SKumar Gala /* max tasks=12, max dma=3, no extra */
328c916d7c9SKumar Gala out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
329c916d7c9SKumar Gala /* FIFO size - 4KB, no extra */
330c916d7c9SKumar Gala out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
331c916d7c9SKumar Gala
332c916d7c9SKumar Gala /* initialize internal buffers data base (linked list) */
333c916d7c9SKumar Gala out_be32(&bmi->fmbm_init, FMBM_INIT_START);
334c916d7c9SKumar Gala
335c916d7c9SKumar Gala return 0;
336c916d7c9SKumar Gala }
337c916d7c9SKumar Gala
fm_init_qmi(struct fm_qmi_common * qmi)338c916d7c9SKumar Gala static void fm_init_qmi(struct fm_qmi_common *qmi)
339c916d7c9SKumar Gala {
340c916d7c9SKumar Gala /* disable all error interrupts */
341c916d7c9SKumar Gala out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
342c916d7c9SKumar Gala /* clear all error events */
343c916d7c9SKumar Gala out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
344c916d7c9SKumar Gala
345c916d7c9SKumar Gala /* disable all interrupts */
346c916d7c9SKumar Gala out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
347c916d7c9SKumar Gala /* clear all interrupts */
348c916d7c9SKumar Gala out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
349c916d7c9SKumar Gala }
350c916d7c9SKumar Gala
351c916d7c9SKumar Gala /* Init common part of FM, index is fm num# like fm as above */
352*382c53f9SRajesh Bhagat #ifdef CONFIG_TFABOOT
fm_init_common(int index,struct ccsr_fman * reg)353*382c53f9SRajesh Bhagat int fm_init_common(int index, struct ccsr_fman *reg)
354*382c53f9SRajesh Bhagat {
355*382c53f9SRajesh Bhagat int rc;
356*382c53f9SRajesh Bhagat void *addr = NULL;
357*382c53f9SRajesh Bhagat enum boot_src src = get_boot_src();
358*382c53f9SRajesh Bhagat
359*382c53f9SRajesh Bhagat if (src == BOOT_SOURCE_IFC_NOR) {
360*382c53f9SRajesh Bhagat addr = (void *)(CONFIG_SYS_FMAN_FW_ADDR +
361*382c53f9SRajesh Bhagat CONFIG_SYS_FSL_IFC_BASE);
362*382c53f9SRajesh Bhagat } else if (src == BOOT_SOURCE_IFC_NAND) {
363*382c53f9SRajesh Bhagat size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
364*382c53f9SRajesh Bhagat
365*382c53f9SRajesh Bhagat addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
366*382c53f9SRajesh Bhagat
367*382c53f9SRajesh Bhagat rc = nand_read(get_nand_dev_by_index(0),
368*382c53f9SRajesh Bhagat (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
369*382c53f9SRajesh Bhagat &fw_length, (u_char *)addr);
370*382c53f9SRajesh Bhagat if (rc == -EUCLEAN) {
371*382c53f9SRajesh Bhagat printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
372*382c53f9SRajesh Bhagat CONFIG_SYS_FMAN_FW_ADDR, rc);
373*382c53f9SRajesh Bhagat }
374*382c53f9SRajesh Bhagat } else if (src == BOOT_SOURCE_QSPI_NOR) {
375*382c53f9SRajesh Bhagat struct spi_flash *ucode_flash;
376*382c53f9SRajesh Bhagat
377*382c53f9SRajesh Bhagat addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
378*382c53f9SRajesh Bhagat int ret = 0;
379*382c53f9SRajesh Bhagat
380*382c53f9SRajesh Bhagat #ifdef CONFIG_DM_SPI_FLASH
381*382c53f9SRajesh Bhagat struct udevice *new;
382*382c53f9SRajesh Bhagat
383*382c53f9SRajesh Bhagat /* speed and mode will be read from DT */
384*382c53f9SRajesh Bhagat ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS,
385*382c53f9SRajesh Bhagat CONFIG_ENV_SPI_CS, 0, 0, &new);
386*382c53f9SRajesh Bhagat
387*382c53f9SRajesh Bhagat ucode_flash = dev_get_uclass_priv(new);
388*382c53f9SRajesh Bhagat #else
389*382c53f9SRajesh Bhagat ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
390*382c53f9SRajesh Bhagat CONFIG_ENV_SPI_CS,
391*382c53f9SRajesh Bhagat CONFIG_ENV_SPI_MAX_HZ,
392*382c53f9SRajesh Bhagat CONFIG_ENV_SPI_MODE);
393*382c53f9SRajesh Bhagat #endif
394*382c53f9SRajesh Bhagat if (!ucode_flash) {
395*382c53f9SRajesh Bhagat printf("SF: probe for ucode failed\n");
396*382c53f9SRajesh Bhagat } else {
397*382c53f9SRajesh Bhagat ret = spi_flash_read(ucode_flash,
398*382c53f9SRajesh Bhagat CONFIG_SYS_FMAN_FW_ADDR +
399*382c53f9SRajesh Bhagat CONFIG_SYS_FSL_QSPI_BASE,
400*382c53f9SRajesh Bhagat CONFIG_SYS_QE_FMAN_FW_LENGTH,
401*382c53f9SRajesh Bhagat addr);
402*382c53f9SRajesh Bhagat if (ret)
403*382c53f9SRajesh Bhagat printf("SF: read for ucode failed\n");
404*382c53f9SRajesh Bhagat spi_flash_free(ucode_flash);
405*382c53f9SRajesh Bhagat }
406*382c53f9SRajesh Bhagat } else if (src == BOOT_SOURCE_SD_MMC) {
407*382c53f9SRajesh Bhagat int dev = CONFIG_SYS_MMC_ENV_DEV;
408*382c53f9SRajesh Bhagat
409*382c53f9SRajesh Bhagat addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
410*382c53f9SRajesh Bhagat u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
411*382c53f9SRajesh Bhagat u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512;
412*382c53f9SRajesh Bhagat struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
413*382c53f9SRajesh Bhagat
414*382c53f9SRajesh Bhagat if (!mmc) {
415*382c53f9SRajesh Bhagat printf("\nMMC cannot find device for ucode\n");
416*382c53f9SRajesh Bhagat } else {
417*382c53f9SRajesh Bhagat printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
418*382c53f9SRajesh Bhagat dev, blk, cnt);
419*382c53f9SRajesh Bhagat mmc_init(mmc);
420*382c53f9SRajesh Bhagat (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
421*382c53f9SRajesh Bhagat addr);
422*382c53f9SRajesh Bhagat }
423*382c53f9SRajesh Bhagat } else {
424*382c53f9SRajesh Bhagat addr = NULL;
425*382c53f9SRajesh Bhagat }
426*382c53f9SRajesh Bhagat
427*382c53f9SRajesh Bhagat /* Upload the Fman microcode if it's present */
428*382c53f9SRajesh Bhagat rc = fman_upload_firmware(index, ®->fm_imem, addr);
429*382c53f9SRajesh Bhagat if (rc)
430*382c53f9SRajesh Bhagat return rc;
431*382c53f9SRajesh Bhagat env_set_addr("fman_ucode", addr);
432*382c53f9SRajesh Bhagat
433*382c53f9SRajesh Bhagat fm_init_muram(index, ®->muram);
434*382c53f9SRajesh Bhagat fm_init_qmi(®->fm_qmi_common);
435*382c53f9SRajesh Bhagat fm_init_fpm(®->fm_fpm);
436*382c53f9SRajesh Bhagat
437*382c53f9SRajesh Bhagat /* clear DMA status */
438*382c53f9SRajesh Bhagat setbits_be32(®->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
439*382c53f9SRajesh Bhagat
440*382c53f9SRajesh Bhagat /* set DMA mode */
441*382c53f9SRajesh Bhagat setbits_be32(®->fm_dma.fmdmmr, FMDMMR_SBER);
442*382c53f9SRajesh Bhagat
443*382c53f9SRajesh Bhagat return fm_init_bmi(index, ®->fm_bmi_common);
444*382c53f9SRajesh Bhagat }
445*382c53f9SRajesh Bhagat #else
fm_init_common(int index,struct ccsr_fman * reg)446c916d7c9SKumar Gala int fm_init_common(int index, struct ccsr_fman *reg)
447c916d7c9SKumar Gala {
448c916d7c9SKumar Gala int rc;
449f2717b47STimur Tabi #if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR)
450dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
451f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND)
452f2717b47STimur Tabi size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
453f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
454c916d7c9SKumar Gala
455750b34c9SGrygorii Strashko rc = nand_read(get_nand_dev_by_index(0),
456750b34c9SGrygorii Strashko (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
457c916d7c9SKumar Gala &fw_length, (u_char *)addr);
458c916d7c9SKumar Gala if (rc == -EUCLEAN) {
459c916d7c9SKumar Gala printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
460dcf1d774SZhao Qiang CONFIG_SYS_FMAN_FW_ADDR, rc);
461c916d7c9SKumar Gala }
462c916d7c9SKumar Gala #elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
463c916d7c9SKumar Gala struct spi_flash *ucode_flash;
464f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
465c916d7c9SKumar Gala int ret = 0;
466c916d7c9SKumar Gala
46777b571daSQianyu Gong #ifdef CONFIG_DM_SPI_FLASH
46877b571daSQianyu Gong struct udevice *new;
46977b571daSQianyu Gong
47077b571daSQianyu Gong /* speed and mode will be read from DT */
47177b571daSQianyu Gong ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
47277b571daSQianyu Gong 0, 0, &new);
47377b571daSQianyu Gong
47477b571daSQianyu Gong ucode_flash = dev_get_uclass_priv(new);
47577b571daSQianyu Gong #else
476c916d7c9SKumar Gala ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
477c916d7c9SKumar Gala CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
47877b571daSQianyu Gong #endif
479c916d7c9SKumar Gala if (!ucode_flash)
480c916d7c9SKumar Gala printf("SF: probe for ucode failed\n");
481c916d7c9SKumar Gala else {
482dcf1d774SZhao Qiang ret = spi_flash_read(ucode_flash, CONFIG_SYS_FMAN_FW_ADDR,
483f2717b47STimur Tabi CONFIG_SYS_QE_FMAN_FW_LENGTH, addr);
484c916d7c9SKumar Gala if (ret)
485c916d7c9SKumar Gala printf("SF: read for ucode failed\n");
486c916d7c9SKumar Gala spi_flash_free(ucode_flash);
487c916d7c9SKumar Gala }
488f2717b47STimur Tabi #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
489c916d7c9SKumar Gala int dev = CONFIG_SYS_MMC_ENV_DEV;
490f2717b47STimur Tabi void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
491f2717b47STimur Tabi u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
492dcf1d774SZhao Qiang u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512;
493c916d7c9SKumar Gala struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
494c916d7c9SKumar Gala
495c916d7c9SKumar Gala if (!mmc)
496c916d7c9SKumar Gala printf("\nMMC cannot find device for ucode\n");
497c916d7c9SKumar Gala else {
498c916d7c9SKumar Gala printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
499c916d7c9SKumar Gala dev, blk, cnt);
500c916d7c9SKumar Gala mmc_init(mmc);
501c3ced8a6SYinbo Zhu (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
5027c4213f6SStephen Warren addr);
503c916d7c9SKumar Gala }
504292dc6c5SLiu Gang #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE)
505dcf1d774SZhao Qiang void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
5067adefb55SYork Sun #else
5077adefb55SYork Sun void *addr = NULL;
508c916d7c9SKumar Gala #endif
509c916d7c9SKumar Gala
510c916d7c9SKumar Gala /* Upload the Fman microcode if it's present */
511c916d7c9SKumar Gala rc = fman_upload_firmware(index, ®->fm_imem, addr);
512c916d7c9SKumar Gala if (rc)
513c916d7c9SKumar Gala return rc;
514018f5303SSimon Glass env_set_addr("fman_ucode", addr);
515c916d7c9SKumar Gala
516c916d7c9SKumar Gala fm_init_muram(index, ®->muram);
517c916d7c9SKumar Gala fm_init_qmi(®->fm_qmi_common);
518c916d7c9SKumar Gala fm_init_fpm(®->fm_fpm);
519c916d7c9SKumar Gala
520c916d7c9SKumar Gala /* clear DMA status */
521c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
522c916d7c9SKumar Gala
523c916d7c9SKumar Gala /* set DMA mode */
524c916d7c9SKumar Gala setbits_be32(®->fm_dma.fmdmmr, FMDMMR_SBER);
525c916d7c9SKumar Gala
526c916d7c9SKumar Gala return fm_init_bmi(index, ®->fm_bmi_common);
527c916d7c9SKumar Gala }
528*382c53f9SRajesh Bhagat #endif
529