blob: 82c5a8b123a12125b1bfcfa9bc5faabcf8aa6c39 [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++)
Laurentiu Tudor7c326ac2019-07-30 17:29:57 +030020 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);
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030024}
25
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030026#ifdef CONFIG_SYS_DPAA_FMAN
27void 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
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030039void set_icids(void)
40{
41 /* setup general icid offsets */
42 set_icid(icid_tbl, icid_tbl_sz);
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030043
44#ifdef CONFIG_SYS_DPAA_FMAN
45 set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz);
46#endif
Laurentiu Tudor512d13e2018-08-09 15:19:46 +030047}
48
49int 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
73int 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
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +030099#ifdef CONFIG_SYS_DPAA_FMAN
100int 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
113void 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
145void 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
Laurentiu Tudor512d13e2018-08-09 15:19:46 +0300159int 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
182void 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);
Laurentiu Tudordcb7f3d2018-08-09 15:19:48 +0300191
192#ifdef CONFIG_SYS_DPAA_FMAN
193 fdt_fixup_fman_icids(blob, smmu_ph);
194#endif
Laurentiu Tudor512d13e2018-08-09 15:19:46 +0300195}