Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-spi
[oweals/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                 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
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
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
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
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
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
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
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
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
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 }