]>
Commit | Line | Data |
---|---|---|
3cb4fe65 LT |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2018 NXP | |
4 | */ | |
5 | ||
d678a59d | 6 | #include <common.h> |
3cb4fe65 LT |
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> | |
b50ff5e1 | 13 | #include <fsl_fman.h> |
3cb4fe65 LT |
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++) | |
aef654a2 LT |
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); | |
3cb4fe65 LT |
24 | } |
25 | ||
b9112cdf LT |
26 | #if defined(CONFIG_SYS_DPAA_FMAN) && !defined(CONFIG_SPL_BUILD) |
27 | static void set_fman_icids(struct fman_icid_id_table *tbl, int size) | |
b50ff5e1 LT |
28 | { |
29 | int i; | |
6cc04547 | 30 | ccsr_fman_t *fm = (void *)CFG_SYS_FSL_FM1_ADDR; |
b50ff5e1 LT |
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 | ||
3cb4fe65 LT |
39 | void set_icids(void) |
40 | { | |
41 | /* setup general icid offsets */ | |
42 | set_icid(icid_tbl, icid_tbl_sz); | |
b50ff5e1 | 43 | |
2db82bf2 | 44 | #if defined(CONFIG_SYS_DPAA_FMAN) && !defined(CONFIG_SPL_BUILD) |
b50ff5e1 LT |
45 | set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz); |
46 | #endif | |
3cb4fe65 LT |
47 | } |
48 | ||
3ed84e73 | 49 | #ifndef CONFIG_SPL_BUILD |
3cb4fe65 LT |
50 | int fdt_set_iommu_prop(void *blob, int off, int smmu_ph, u32 *ids, int num_ids) |
51 | { | |
52 | int i, ret; | |
53 | u32 prop[8]; | |
54 | ||
55 | /* | |
56 | * Note: The "iommus" property definition mentions Stream IDs while | |
57 | * this code handles ICIDs. The current implementation assumes that | |
58 | * ICIDs and Stream IDs are equal. | |
59 | */ | |
60 | for (i = 0; i < num_ids; i++) { | |
61 | prop[i * 2] = cpu_to_fdt32(smmu_ph); | |
62 | prop[i * 2 + 1] = cpu_to_fdt32(ids[i]); | |
63 | } | |
64 | ret = fdt_setprop(blob, off, "iommus", | |
65 | prop, sizeof(u32) * num_ids * 2); | |
66 | if (ret) { | |
67 | printf("WARNING unable to set iommus: %s\n", fdt_strerror(ret)); | |
68 | return ret; | |
69 | } | |
70 | ||
71 | return 0; | |
72 | } | |
73 | ||
b9112cdf | 74 | static int fdt_fixup_icid_tbl(void *blob, int smmu_ph, |
3cb4fe65 LT |
75 | struct icid_id_table *tbl, int size) |
76 | { | |
77 | int i, err, off; | |
78 | ||
79 | for (i = 0; i < size; i++) { | |
80 | if (!tbl[i].compat) | |
81 | continue; | |
82 | ||
83 | off = fdt_node_offset_by_compat_reg(blob, | |
84 | tbl[i].compat, | |
85 | tbl[i].compat_addr); | |
86 | if (off > 0) { | |
87 | err = fdt_set_iommu_prop(blob, off, smmu_ph, | |
88 | &tbl[i].id, 1); | |
89 | if (err) | |
90 | return err; | |
91 | } else { | |
92 | printf("WARNING could not find node %s: %s.\n", | |
93 | tbl[i].compat, fdt_strerror(off)); | |
94 | } | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
b50ff5e1 | 100 | #ifdef CONFIG_SYS_DPAA_FMAN |
b9112cdf | 101 | static int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl, |
b50ff5e1 LT |
102 | const int size) |
103 | { | |
104 | int i; | |
105 | ||
106 | for (i = 0; i < size; i++) { | |
107 | if (tbl[i].port_id == port_id) | |
108 | return tbl[i].icid; | |
109 | } | |
110 | ||
111 | return -1; | |
112 | } | |
113 | ||
b9112cdf | 114 | static void fdt_fixup_fman_port_icid_by_compat(void *blob, int smmu_ph, |
b50ff5e1 LT |
115 | const char *compat) |
116 | { | |
117 | int noff, len, icid; | |
118 | const u32 *prop; | |
119 | ||
3058e283 | 120 | fdt_for_each_node_by_compatible(noff, blob, -1, compat) { |
b50ff5e1 LT |
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); | |
b50ff5e1 LT |
140 | } |
141 | } | |
142 | ||
b9112cdf | 143 | static void fdt_fixup_fman_icids(void *blob, int smmu_ph) |
b50ff5e1 LT |
144 | { |
145 | static const char * const compats[] = { | |
146 | "fsl,fman-v3-port-oh", | |
147 | "fsl,fman-v3-port-rx", | |
148 | "fsl,fman-v3-port-tx", | |
149 | }; | |
150 | int i; | |
151 | ||
152 | for (i = 0; i < ARRAY_SIZE(compats); i++) | |
153 | fdt_fixup_fman_port_icid_by_compat(blob, smmu_ph, compats[i]); | |
154 | } | |
155 | #endif | |
156 | ||
3cb4fe65 LT |
157 | int fdt_get_smmu_phandle(void *blob) |
158 | { | |
159 | int noff, smmu_ph; | |
160 | ||
161 | noff = fdt_node_offset_by_compatible(blob, -1, "arm,mmu-500"); | |
162 | if (noff < 0) { | |
163 | printf("WARNING failed to get smmu node: %s\n", | |
164 | fdt_strerror(noff)); | |
165 | return noff; | |
166 | } | |
167 | ||
168 | smmu_ph = fdt_get_phandle(blob, noff); | |
169 | if (!smmu_ph) { | |
170 | smmu_ph = fdt_create_phandle(blob, noff); | |
171 | if (!smmu_ph) { | |
172 | printf("WARNING failed to get smmu phandle\n"); | |
173 | return -1; | |
174 | } | |
175 | } | |
176 | ||
177 | return smmu_ph; | |
178 | } | |
179 | ||
180 | void fdt_fixup_icid(void *blob) | |
181 | { | |
182 | int smmu_ph; | |
183 | ||
184 | smmu_ph = fdt_get_smmu_phandle(blob); | |
185 | if (smmu_ph < 0) | |
186 | return; | |
187 | ||
188 | fdt_fixup_icid_tbl(blob, smmu_ph, icid_tbl, icid_tbl_sz); | |
b50ff5e1 LT |
189 | |
190 | #ifdef CONFIG_SYS_DPAA_FMAN | |
191 | fdt_fixup_fman_icids(blob, smmu_ph); | |
192 | #endif | |
3cb4fe65 | 193 | } |
3ed84e73 | 194 | #endif |