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