blob: b1a950e7f9c01c0c1c4edb656a64f9519389adcc [file] [log] [blame]
Laurentiu Tudor512d13e2018-08-09 15:19:46 +03001// 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>
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030013#include <fsl_fman.h>
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030014
15static 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
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030023#ifdef CONFIG_SYS_DPAA_FMAN
24void 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
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030036void set_icids(void)
37{
38 /* setup general icid offsets */
39 set_icid(icid_tbl, icid_tbl_sz);
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030040
41#ifdef CONFIG_SYS_DPAA_FMAN
42 set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz);
43#endif
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030044}
45
46int 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
70int 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
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030096#ifdef CONFIG_SYS_DPAA_FMAN
97int 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
110void 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
142void 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
Laurentiu Tudor512d13e2018-08-09 15:19:46 +0300156int 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
179void 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);
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +0300188
189#ifdef CONFIG_SYS_DPAA_FMAN
190 fdt_fixup_fman_icids(blob, smmu_ph);
191#endif
Laurentiu Tudor512d13e2018-08-09 15:19:46 +0300192}