1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2018 NXP
4  */
5 
6 #include <common.h>
7 #include <linux/libfdt.h>
8 #include <fdt_support.h>
9 
10 #include <asm/io.h>
11 #include <asm/processor.h>
12 #include <asm/arch-fsl-layerscape/fsl_icid.h>
13 #include <fsl_fman.h>
14 
set_icid(struct icid_id_table * tbl,int size)15 static void set_icid(struct icid_id_table *tbl, int size)
16 {
17 	int i;
18 
19 	for (i = 0; i < size; i++)
20 		out_be32((u32 *)(tbl[i].reg_addr), tbl[i].reg);
21 }
22 
23 #ifdef CONFIG_SYS_DPAA_FMAN
set_fman_icids(struct fman_icid_id_table * tbl,int size)24 void set_fman_icids(struct fman_icid_id_table *tbl, int size)
25 {
26 	int i;
27 	ccsr_fman_t *fm = (void *)CONFIG_SYS_FSL_FM1_ADDR;
28 
29 	for (i = 0; i < size; i++) {
30 		out_be32(&fm->fm_bmi_common.fmbm_ppid[tbl[i].port_id - 1],
31 			 tbl[i].icid);
32 	}
33 }
34 #endif
35 
set_icids(void)36 void set_icids(void)
37 {
38 	/* setup general icid offsets */
39 	set_icid(icid_tbl, icid_tbl_sz);
40 
41 #ifdef CONFIG_SYS_DPAA_FMAN
42 	set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz);
43 #endif
44 }
45 
fdt_set_iommu_prop(void * blob,int off,int smmu_ph,u32 * ids,int num_ids)46 int fdt_set_iommu_prop(void *blob, int off, int smmu_ph, u32 *ids, int num_ids)
47 {
48 	int i, ret;
49 	u32 prop[8];
50 
51 	/*
52 	 * Note: The "iommus" property definition mentions Stream IDs while
53 	 * this code handles ICIDs. The current implementation assumes that
54 	 * ICIDs and Stream IDs are equal.
55 	 */
56 	for (i = 0; i < num_ids; i++) {
57 		prop[i * 2] = cpu_to_fdt32(smmu_ph);
58 		prop[i * 2 + 1] = cpu_to_fdt32(ids[i]);
59 	}
60 	ret = fdt_setprop(blob, off, "iommus",
61 			  prop, sizeof(u32) * num_ids * 2);
62 	if (ret) {
63 		printf("WARNING unable to set iommus: %s\n", fdt_strerror(ret));
64 		return ret;
65 	}
66 
67 	return 0;
68 }
69 
fdt_fixup_icid_tbl(void * blob,int smmu_ph,struct icid_id_table * tbl,int size)70 int fdt_fixup_icid_tbl(void *blob, int smmu_ph,
71 		       struct icid_id_table *tbl, int size)
72 {
73 	int i, err, off;
74 
75 	for (i = 0; i < size; i++) {
76 		if (!tbl[i].compat)
77 			continue;
78 
79 		off = fdt_node_offset_by_compat_reg(blob,
80 						    tbl[i].compat,
81 						    tbl[i].compat_addr);
82 		if (off > 0) {
83 			err = fdt_set_iommu_prop(blob, off, smmu_ph,
84 						 &tbl[i].id, 1);
85 			if (err)
86 				return err;
87 		} else {
88 			printf("WARNING could not find node %s: %s.\n",
89 			       tbl[i].compat, fdt_strerror(off));
90 		}
91 	}
92 
93 	return 0;
94 }
95 
96 #ifdef CONFIG_SYS_DPAA_FMAN
get_fman_port_icid(int port_id,struct fman_icid_id_table * tbl,const int size)97 int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl,
98 		       const int size)
99 {
100 	int i;
101 
102 	for (i = 0; i < size; i++) {
103 		if (tbl[i].port_id == port_id)
104 			return tbl[i].icid;
105 	}
106 
107 	return -1;
108 }
109 
fdt_fixup_fman_port_icid_by_compat(void * blob,int smmu_ph,const char * compat)110 void fdt_fixup_fman_port_icid_by_compat(void *blob, int smmu_ph,
111 					const char *compat)
112 {
113 	int noff, len, icid;
114 	const u32 *prop;
115 
116 	noff = fdt_node_offset_by_compatible(blob, -1, compat);
117 	while (noff > 0) {
118 		prop = fdt_getprop(blob, noff, "cell-index", &len);
119 		if (!prop) {
120 			printf("WARNING missing cell-index for fman port\n");
121 			continue;
122 		}
123 		if (len != 4) {
124 			printf("WARNING bad cell-index size for fman port\n");
125 			continue;
126 		}
127 
128 		icid = get_fman_port_icid(fdt32_to_cpu(*prop),
129 					  fman_icid_tbl, fman_icid_tbl_sz);
130 		if (icid < 0) {
131 			printf("WARNING unknown ICID for fman port %d\n",
132 			       *prop);
133 			continue;
134 		}
135 
136 		fdt_set_iommu_prop(blob, noff, smmu_ph, (u32 *)&icid, 1);
137 
138 		noff = fdt_node_offset_by_compatible(blob, noff, compat);
139 	}
140 }
141 
fdt_fixup_fman_icids(void * blob,int smmu_ph)142 void fdt_fixup_fman_icids(void *blob, int smmu_ph)
143 {
144 	static const char * const compats[] = {
145 		"fsl,fman-v3-port-oh",
146 		"fsl,fman-v3-port-rx",
147 		"fsl,fman-v3-port-tx",
148 	};
149 	int i;
150 
151 	for (i = 0; i < ARRAY_SIZE(compats); i++)
152 		fdt_fixup_fman_port_icid_by_compat(blob, smmu_ph, compats[i]);
153 }
154 #endif
155 
fdt_get_smmu_phandle(void * blob)156 int fdt_get_smmu_phandle(void *blob)
157 {
158 	int noff, smmu_ph;
159 
160 	noff = fdt_node_offset_by_compatible(blob, -1, "arm,mmu-500");
161 	if (noff < 0) {
162 		printf("WARNING failed to get smmu node: %s\n",
163 		       fdt_strerror(noff));
164 		return noff;
165 	}
166 
167 	smmu_ph = fdt_get_phandle(blob, noff);
168 	if (!smmu_ph) {
169 		smmu_ph = fdt_create_phandle(blob, noff);
170 		if (!smmu_ph) {
171 			printf("WARNING failed to get smmu phandle\n");
172 			return -1;
173 		}
174 	}
175 
176 	return smmu_ph;
177 }
178 
fdt_fixup_icid(void * blob)179 void fdt_fixup_icid(void *blob)
180 {
181 	int smmu_ph;
182 
183 	smmu_ph = fdt_get_smmu_phandle(blob);
184 	if (smmu_ph < 0)
185 		return;
186 
187 	fdt_fixup_icid_tbl(blob, smmu_ph, icid_tbl, icid_tbl_sz);
188 
189 #ifdef CONFIG_SYS_DPAA_FMAN
190 	fdt_fixup_fman_icids(blob, smmu_ph);
191 #endif
192 }
193