1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2008-2011 Freescale Semiconductor, Inc.
4 */
5
6#include <common.h>
7#include <log.h>
8#include <linux/libfdt.h>
9#include <fdt_support.h>
10
11#include <asm/immap_85xx.h>
12#include <asm/io.h>
13#include <asm/processor.h>
14#include <asm/fsl_portals.h>
15#include <asm/fsl_liodn.h>
16
17int get_dpaa_liodn(enum fsl_dpaa_dev dpaa_dev, u32 *liodns, int liodn_offset)
18{
19	liodns[0] = liodn_bases[dpaa_dev].id[0] + liodn_offset;
20
21	if (liodn_bases[dpaa_dev].num_ids == 2)
22		liodns[1] = liodn_bases[dpaa_dev].id[1] + liodn_offset;
23
24	return liodn_bases[dpaa_dev].num_ids;
25}
26
27#ifdef CONFIG_SYS_SRIO
28static void set_srio_liodn(struct srio_liodn_id_table *tbl, int size)
29{
30	int i;
31
32	for (i = 0; i < size; i++) {
33		unsigned long reg_off = tbl[i].reg_offset[0];
34		out_be32((u32 *)reg_off, tbl[i].id[0]);
35
36		if (tbl[i].num_ids == 2) {
37			reg_off = tbl[i].reg_offset[1];
38			out_be32((u32 *)reg_off, tbl[i].id[1]);
39		}
40	}
41}
42#endif
43
44static void set_liodn(struct liodn_id_table *tbl, int size)
45{
46	int i;
47
48	for (i = 0; i < size; i++) {
49		u32 liodn;
50		if (tbl[i].num_ids == 2) {
51			liodn = (tbl[i].id[0] << 16) | tbl[i].id[1];
52		} else {
53			liodn = tbl[i].id[0];
54		}
55
56		out_be32((volatile u32 *)(tbl[i].reg_offset), liodn);
57	}
58}
59
60#ifdef CONFIG_SYS_DPAA_FMAN
61static void set_fman_liodn(struct fman_liodn_id_table *tbl, int size)
62{
63	int i;
64
65	for (i = 0; i < size; i++) {
66		u32 liodn;
67		if (tbl[i].num_ids == 2)
68			liodn = (tbl[i].id[0] << 16) | tbl[i].id[1];
69		else
70			liodn = tbl[i].id[0];
71
72		out_be32((volatile u32 *)(tbl[i].reg_offset), liodn);
73	}
74}
75#endif
76
77static void setup_sec_liodn_base(void)
78{
79	ccsr_sec_t *sec = (void *)CFG_SYS_FSL_SEC_ADDR;
80	u32 base;
81
82	if (!IS_E_PROCESSOR(get_svr()))
83		return;
84
85	/* QILCR[QSLOM] */
86	sec_out32(&sec->qilcr_ms, 0x3ff<<16);
87
88	base = (liodn_bases[FSL_HW_PORTAL_SEC].id[0] << 16) |
89		liodn_bases[FSL_HW_PORTAL_SEC].id[1];
90
91	sec_out32(&sec->qilcr_ls, base);
92}
93
94#ifdef CONFIG_SYS_DPAA_FMAN
95static void setup_fman_liodn_base(enum fsl_dpaa_dev dev,
96				  struct fman_liodn_id_table *tbl, int size)
97{
98	int i;
99	ccsr_fman_t *fm;
100	u32 base;
101
102	switch(dev) {
103	case FSL_HW_PORTAL_FMAN1:
104		fm = (void *)CFG_SYS_FSL_FM1_ADDR;
105		break;
106
107#if (CFG_SYS_NUM_FMAN == 2)
108	case FSL_HW_PORTAL_FMAN2:
109		fm = (void *)CFG_SYS_FSL_FM2_ADDR;
110		break;
111#endif
112	default:
113		printf("Error: Invalid device type to %s\n", __FUNCTION__);
114		return;
115	}
116
117	base = (liodn_bases[dev].id[0] << 16) | liodn_bases[dev].id[0];
118
119	/* setup all bases the same */
120	for (i = 0; i < 32; i++) {
121		out_be32(&fm->fm_dma.fmdmplr[i], base);
122	}
123
124	/* update tbl to ... */
125	for (i = 0; i < size; i++)
126		tbl[i].id[0] += liodn_bases[dev].id[0];
127}
128#endif
129
130static void setup_pme_liodn_base(void)
131{
132#ifdef CONFIG_SYS_DPAA_PME
133	ccsr_pme_t *pme = (void *)CFG_SYS_FSL_CORENET_PME_ADDR;
134	u32 base = (liodn_bases[FSL_HW_PORTAL_PME].id[0] << 16) |
135			liodn_bases[FSL_HW_PORTAL_PME].id[1];
136
137	out_be32(&pme->liodnbr, base);
138#endif
139}
140
141#ifdef CONFIG_SYS_FSL_RAID_ENGINE
142static void setup_raide_liodn_base(void)
143{
144	struct ccsr_raide *raide = (void *)CFG_SYS_FSL_RAID_ENGINE_ADDR;
145
146	/* setup raid engine liodn base for data/desc ; both set to 47 */
147	u32 base = (liodn_bases[FSL_HW_PORTAL_RAID_ENGINE].id[0] << 16) |
148			liodn_bases[FSL_HW_PORTAL_RAID_ENGINE].id[0];
149
150	out_be32(&raide->liodnbr, base);
151}
152#endif
153
154#ifdef CONFIG_SYS_DPAA_RMAN
155static void set_rman_liodn(struct liodn_id_table *tbl, int size)
156{
157	int i;
158	struct ccsr_rman *rman = (void *)CFG_SYS_FSL_CORENET_RMAN_ADDR;
159
160	for (i = 0; i < size; i++) {
161		/* write the RMan block number */
162		out_be32(&rman->mmitar, i);
163		/* write the liodn offset corresponding to the block */
164		out_be32((u32 *)(tbl[i].reg_offset), tbl[i].id[0]);
165	}
166}
167
168static void setup_rman_liodn_base(struct liodn_id_table *tbl, int size)
169{
170	int i;
171	struct ccsr_rman *rman = (void *)CFG_SYS_FSL_CORENET_RMAN_ADDR;
172	u32 base = liodn_bases[FSL_HW_PORTAL_RMAN].id[0];
173
174	out_be32(&rman->mmliodnbr, base);
175
176	/* update liodn offset */
177	for (i = 0; i < size; i++)
178		tbl[i].id[0] += base;
179}
180#endif
181
182void set_liodns(void)
183{
184	/* setup general liodn offsets */
185	set_liodn(liodn_tbl, liodn_tbl_sz);
186
187#ifdef CONFIG_SYS_SRIO
188	/* setup SRIO port liodns */
189	set_srio_liodn(srio_liodn_tbl, srio_liodn_tbl_sz);
190#endif
191
192	/* setup SEC block liodn bases & offsets if we have one */
193	if (IS_E_PROCESSOR(get_svr())) {
194		set_liodn(sec_liodn_tbl, sec_liodn_tbl_sz);
195		setup_sec_liodn_base();
196	}
197
198	/* setup FMAN block(s) liodn bases & offsets if we have one */
199#ifdef CONFIG_SYS_DPAA_FMAN
200	set_fman_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz);
201	setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl,
202				fman1_liodn_tbl_sz);
203
204#if (CFG_SYS_NUM_FMAN == 2)
205	set_fman_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz);
206	setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl,
207				fman2_liodn_tbl_sz);
208#endif
209#endif
210	/* setup PME liodn base */
211	setup_pme_liodn_base();
212
213#ifdef CONFIG_SYS_FSL_RAID_ENGINE
214	/* raid engine ccr addr code for liodn */
215	set_liodn(raide_liodn_tbl, raide_liodn_tbl_sz);
216	setup_raide_liodn_base();
217#endif
218
219#ifdef CONFIG_SYS_DPAA_RMAN
220	/* setup RMan liodn offsets */
221	set_rman_liodn(rman_liodn_tbl, rman_liodn_tbl_sz);
222	/* setup RMan liodn base */
223	setup_rman_liodn_base(rman_liodn_tbl, rman_liodn_tbl_sz);
224#endif
225}
226
227#ifdef CONFIG_SYS_SRIO
228static void fdt_fixup_srio_liodn(void *blob, struct srio_liodn_id_table *tbl)
229{
230	int i, srio_off;
231
232	/* search for srio node, if doesn't exist just return - nothing todo */
233	srio_off = fdt_node_offset_by_compatible(blob, -1, "fsl,srio");
234	if (srio_off < 0)
235		return;
236
237	for (i = 0; i < srio_liodn_tbl_sz; i++) {
238		int off, portid = tbl[i].portid;
239
240		off = fdt_node_offset_by_prop_value(blob, srio_off,
241			 "cell-index", &portid, 4);
242		if (off >= 0) {
243			off = fdt_setprop(blob, off, "fsl,liodn",
244				&tbl[i].id[0],
245				sizeof(u32) * tbl[i].num_ids);
246			if (off > 0)
247				printf("WARNING unable to set fsl,liodn for "
248					"fsl,srio port %d: %s\n",
249					portid, fdt_strerror(off));
250		} else {
251			debug("WARNING: couldn't set fsl,liodn for srio: %s.\n",
252				fdt_strerror(off));
253		}
254	}
255}
256#endif
257
258#define CFG_SYS_MAX_PCI_EPS		8
259
260static void fdt_fixup_pci_liodn_offsets(void *fdt, const char *compat,
261					int ep_liodn_start)
262{
263	int off, pci_idx = 0, pci_cnt = 0, i, rc;
264	const uint32_t *base_liodn;
265	uint32_t liodn_offs[CFG_SYS_MAX_PCI_EPS + 1] = { 0 };
266
267	/*
268	 * Count the number of pci nodes.
269	 * It's needed later when the interleaved liodn offsets are generated.
270	 */
271	fdt_for_each_node_by_compatible(off, fdt, -1, compat)
272		pci_cnt++;
273
274	fdt_for_each_node_by_compatible(off, fdt, -1, compat) {
275		base_liodn = fdt_getprop(fdt, off, "fsl,liodn", &rc);
276		if (!base_liodn) {
277			char path[64];
278
279			if (fdt_get_path(fdt, off, path, sizeof(path)) < 0)
280				strcpy(path, "(unknown)");
281			printf("WARNING Could not get liodn of node %s: %s\n",
282			       path, fdt_strerror(rc));
283			continue;
284		}
285		for (i = 0; i < CFG_SYS_MAX_PCI_EPS; i++)
286			liodn_offs[i + 1] = ep_liodn_start +
287					i * pci_cnt + pci_idx - *base_liodn;
288		rc = fdt_setprop(fdt, off, "fsl,liodn-offset-list",
289				 liodn_offs, sizeof(liodn_offs));
290		if (rc) {
291			char path[64];
292
293			if (fdt_get_path(fdt, off, path, sizeof(path)) < 0)
294				strcpy(path, "(unknown)");
295			printf("WARNING Unable to set fsl,liodn-offset-list for "
296			       "node %s: %s\n", path, fdt_strerror(rc));
297			continue;
298		}
299		pci_idx++;
300	}
301}
302
303static void fdt_fixup_liodn_tbl(void *blob, struct liodn_id_table *tbl, int sz)
304{
305	int i;
306
307	for (i = 0; i < sz; i++) {
308		int off;
309
310		if (tbl[i].compat == NULL)
311			continue;
312
313		off = fdt_node_offset_by_compat_reg(blob,
314				tbl[i].compat, tbl[i].compat_offset);
315		if (off >= 0) {
316			off = fdt_setprop(blob, off, "fsl,liodn",
317				&tbl[i].id[0],
318				sizeof(u32) * tbl[i].num_ids);
319			if (off > 0)
320				printf("WARNING unable to set fsl,liodn for "
321					"%s: %s\n",
322					tbl[i].compat, fdt_strerror(off));
323		} else {
324			debug("WARNING: could not set fsl,liodn for %s: %s.\n",
325					tbl[i].compat, fdt_strerror(off));
326		}
327	}
328}
329
330#ifdef CONFIG_SYS_DPAA_FMAN
331static void fdt_fixup_liodn_tbl_fman(void *blob,
332				     struct fman_liodn_id_table *tbl,
333				     int sz)
334{
335	int i;
336
337	for (i = 0; i < sz; i++) {
338		int off;
339
340		/* Try the new compatible first.
341		 * If the node is missing, try the old.
342		 */
343		off = fdt_node_offset_by_compat_reg(blob,
344				tbl[i].compat[0], tbl[i].compat_offset);
345		if (off < 0)
346			off = fdt_node_offset_by_compat_reg(blob,
347					tbl[i].compat[1], tbl[i].compat_offset);
348
349		if (off >= 0) {
350			off = fdt_setprop(blob, off, "fsl,liodn",
351				&tbl[i].id[0],
352				sizeof(u32) * tbl[i].num_ids);
353			if (off > 0)
354				printf("WARNING unable to set fsl,liodn for FMan Port: %s\n",
355				       fdt_strerror(off));
356		} else {
357			debug("WARNING: could not set fsl,liodn for FMan Portport: %s.\n",
358			      fdt_strerror(off));
359		}
360	}
361}
362#endif
363
364void fdt_fixup_liodn(void *blob)
365{
366#ifdef CONFIG_SYS_SRIO
367	fdt_fixup_srio_liodn(blob, srio_liodn_tbl);
368#endif
369
370	fdt_fixup_liodn_tbl(blob, liodn_tbl, liodn_tbl_sz);
371#ifdef CONFIG_SYS_DPAA_FMAN
372	fdt_fixup_liodn_tbl_fman(blob, fman1_liodn_tbl, fman1_liodn_tbl_sz);
373#if (CFG_SYS_NUM_FMAN == 2)
374	fdt_fixup_liodn_tbl_fman(blob, fman2_liodn_tbl, fman2_liodn_tbl_sz);
375#endif
376#endif
377	fdt_fixup_liodn_tbl(blob, sec_liodn_tbl, sec_liodn_tbl_sz);
378
379#ifdef CONFIG_SYS_FSL_RAID_ENGINE
380	fdt_fixup_liodn_tbl(blob, raide_liodn_tbl, raide_liodn_tbl_sz);
381#endif
382
383#ifdef CONFIG_SYS_DPAA_RMAN
384	fdt_fixup_liodn_tbl(blob, rman_liodn_tbl, rman_liodn_tbl_sz);
385#endif
386
387	ccsr_pcix_t *pcix = (ccsr_pcix_t *)CFG_SYS_PCIE1_ADDR;
388	int pci_ver = pcix->ipver1 & 0xffff, liodn_base = 0;
389
390	if (pci_ver >= 0x0204) {
391		if (pci_ver >= 0x0300)
392			liodn_base = 1024;
393		else
394			liodn_base = 256;
395	}
396
397	if (liodn_base) {
398		char compat[32];
399
400		sprintf(compat, "fsl,qoriq-pcie-v%d.%d",
401			(pci_ver & 0xff00) >> 8, pci_ver & 0xff);
402		fdt_fixup_pci_liodn_offsets(blob, compat, liodn_base);
403		fdt_fixup_pci_liodn_offsets(blob, "fsl,qoriq-pcie", liodn_base);
404	}
405}
406