Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[platform/kernel/u-boot.git] / arch / arm / cpu / armv8 / fsl-layerscape / icid.c
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
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
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
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
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
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
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
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
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
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
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 }