xref: /openbmc/u-boot/drivers/net/fm/fm.c (revision d94604d558cda9f89722c967d6f8d6269a2db21c)
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, &reg->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, &reg->muram);
434*382c53f9SRajesh Bhagat 	fm_init_qmi(&reg->fm_qmi_common);
435*382c53f9SRajesh Bhagat 	fm_init_fpm(&reg->fm_fpm);
436*382c53f9SRajesh Bhagat 
437*382c53f9SRajesh Bhagat 	/* clear DMA status */
438*382c53f9SRajesh Bhagat 	setbits_be32(&reg->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
439*382c53f9SRajesh Bhagat 
440*382c53f9SRajesh Bhagat 	/* set DMA mode */
441*382c53f9SRajesh Bhagat 	setbits_be32(&reg->fm_dma.fmdmmr, FMDMMR_SBER);
442*382c53f9SRajesh Bhagat 
443*382c53f9SRajesh Bhagat 	return fm_init_bmi(index, &reg->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, &reg->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, &reg->muram);
517c916d7c9SKumar Gala 	fm_init_qmi(&reg->fm_qmi_common);
518c916d7c9SKumar Gala 	fm_init_fpm(&reg->fm_fpm);
519c916d7c9SKumar Gala 
520c916d7c9SKumar Gala 	/* clear DMA status */
521c916d7c9SKumar Gala 	setbits_be32(&reg->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
522c916d7c9SKumar Gala 
523c916d7c9SKumar Gala 	/* set DMA mode */
524c916d7c9SKumar Gala 	setbits_be32(&reg->fm_dma.fmdmmr, FMDMMR_SBER);
525c916d7c9SKumar Gala 
526c916d7c9SKumar Gala 	return fm_init_bmi(index, &reg->fm_bmi_common);
527c916d7c9SKumar Gala }
528*382c53f9SRajesh Bhagat #endif
529