xref: /freebsd/sys/dev/dpaa/fman_port_tx.c (revision 5d884fc07662760a2090928e98e51dc8162389a3)
1 /*
2  * Copyright (c) 2026 Justin Hibbits
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * FMan TX port driver.
7  */
8 
9 #include <sys/param.h>
10 #include <sys/bus.h>
11 #include <sys/kernel.h>
12 #include <sys/module.h>
13 
14 #include <dev/ofw/ofw_bus.h>
15 #include <dev/ofw/ofw_bus_subr.h>
16 #include <machine/bus.h>
17 
18 #include "fman.h"
19 #include "fman_parser.h"
20 #include "fman_port.h"
21 #include "fman_port_var.h"
22 #include "fman_if.h"
23 #include "fman_port_if.h"
24 
25 #define	TX_10G_PORT_BASE	0x30
26 
27 /* BMI Tx registers. */
28 #define	FMBM_TCFG		0x000
29 #define	FMBM_TST		0x004
30 #define	FMBM_TDA		0x008
31 #define	FMBM_TFP		0x00c
32 #define	  BMI_FIFO_PIPELINE_DEPTH_SHIFT	12
33 #define	FMBM_TFED		0x010
34 #define	FMBM_TICP		0x014
35 #define	  TICP_ICEOF_M		  0x001f0000
36 #define	  TICP_ICEOF_S		  16
37 #define	  TICP_ICIOF_M		  0x00000f00
38 #define	  TICP_ICIOF_S		  8
39 #define	  TICP_ICSZ_S		  0x0000001f
40 #define	FMBM_TFDNE		0x018
41 #define	FMBM_TFCA		0x01c
42 #define	  TFCA_MR_DEF		  0
43 #define	  TFCA_ATTR_ORDER	  0x80000000
44 #define	FMBM_TCFQID		0x020
45 #define	FMBM_TEFQID		0x024
46 #define	FMBM_TFENE		0x028
47 #define	FMBM_TFNE		0x070
48 #define	  TFNE_EBD		  0x80000000
49 
50 /* QMI dequeue-config (FMQM_PNDC) field layout: TX-only consumer. */
51 #define	QMI_DEQ_CFG_PRI			0x80000000
52 #define	QMI_DEQ_CFG_TYPE1		0x10000000
53 #define	QMI_DEQ_CFG_TYPE2		0x20000000
54 #define	QMI_DEQ_CFG_TYPE3		0x30000000
55 #define	QMI_DEQ_CFG_PREFETCH_PARTIAL	0x01000000
56 #define	QMI_DEQ_CFG_PREFETCH_FULL	0x03000000
57 #define	QMI_DEQ_CFG_SP_MASK		0xf
58 #define	QMI_DEQ_CFG_SP_SHIFT		20
59 
60 struct fman_port_tx_softc {
61 	struct fman_port_softc sc_base;
62 
63 	int sc_deq_byte_count;
64 	int sc_deq_high_priority;
65 	int sc_tx_deq_pipeline_depth;
66 	int sc_qman_channel_id;
67 };
68 
69 static struct ofw_compat_data tx_compats[] = {
70 	{ "fsl,fman-v2-port-tx", 0 },
71 	{ "fsl,fman-v3-port-tx", PORT_V3 },
72 	{ NULL, 0 }
73 };
74 
75 static int
fman_port_tx_probe(device_t dev)76 fman_port_tx_probe(device_t dev)
77 {
78 
79 	if (ofw_bus_search_compatible(dev, tx_compats)->ocd_str == NULL)
80 		return (ENXIO);
81 
82 	device_set_desc(dev, "FMan TX port");
83 	return (BUS_PROBE_DEFAULT);
84 }
85 
86 static int
fman_port_tx_attach(device_t dev)87 fman_port_tx_attach(device_t dev)
88 {
89 	struct fman_port_tx_softc *sc;
90 	uintptr_t compat_data;
91 	int port_speed;
92 	int err;
93 
94 	sc = device_get_softc(dev);
95 	compat_data = ofw_bus_search_compatible(dev, tx_compats)->ocd_data;
96 
97 	port_speed = 1000;
98 	if ((compat_data & PORT_V3) == PORT_V3) {
99 		if (OF_hasprop(ofw_bus_get_node(dev), "fsl,fman-10g-port"))
100 			port_speed = 10000;
101 	} else {
102 		int cell = 0;
103 		OF_getencprop(ofw_bus_get_node(dev), "cell-index", &cell,
104 		    sizeof(cell));
105 		if (cell > TX_10G_PORT_BASE)
106 			port_speed = 10000;
107 	}
108 
109 	err = fman_port_attach_common(dev, &sc->sc_base, port_speed);
110 	if (err != 0)
111 		return (err);
112 
113 	if (port_speed == 10000) {
114 		sc->sc_deq_high_priority = true;
115 		sc->sc_deq_byte_count = 0x1400;
116 	} else {
117 		sc->sc_deq_high_priority = false;
118 		sc->sc_deq_byte_count = 0x0400;
119 	}
120 
121 	sc->sc_qman_channel_id = FMAN_GET_QMAN_CHANNEL_ID(
122 	    device_get_parent(dev), sc->sc_base.sc_port_id);
123 
124 	return (0);
125 }
126 
127 static int
fman_port_tx_detach(device_t dev)128 fman_port_tx_detach(device_t dev)
129 {
130 	struct fman_port_tx_softc *sc = device_get_softc(dev);
131 
132 	return (fman_port_detach_common(dev, &sc->sc_base));
133 }
134 
135 static int
fman_port_tx_config(device_t dev,struct fman_port_params * params)136 fman_port_tx_config(device_t dev, struct fman_port_params *params)
137 {
138 	struct fman_port_tx_softc *sc = device_get_softc(dev);
139 	struct fman_port_softc *base = &sc->sc_base;
140 
141 	fman_port_config_common(base, params);
142 
143 	if (base->sc_revision_major >= 6 && base->sc_port_speed == 1000)
144 		/* Errata A005127 workaround */
145 		bus_write_4(base->sc_mem, FMBM_TFP, 0x00001013);
146 
147 	base->sc_tasks.extra = 0;
148 	switch (base->sc_port_speed) {
149 	case 10000:
150 		base->sc_tasks.num = (base->sc_revision_major < 6) ? 16 : 14;
151 		break;
152 	case 1000:
153 		base->sc_tasks.num = (base->sc_revision_major >= 6) ? 4 : 3;
154 		break;
155 	default:
156 		base->sc_tasks.num = 0;
157 		break;
158 	}
159 
160 	if (base->sc_revision_major >= 6) {
161 		base->sc_open_dmas.extra = 0;
162 		base->sc_open_dmas.num =
163 		    (base->sc_port_speed == 10000) ? 12 : 3;
164 	} else if (base->sc_port_speed == 10000) {
165 		base->sc_open_dmas.num = 8;
166 		base->sc_open_dmas.extra = 8;
167 	} else {
168 		base->sc_open_dmas.num = 1;
169 		base->sc_open_dmas.extra = 1;
170 	}
171 
172 	if (base->sc_revision_major >= 6)
173 		base->sc_fifo_bufs.num =
174 		    (base->sc_port_speed == 10000) ? 64 : 50;
175 	else
176 		base->sc_fifo_bufs.num =
177 		    (base->sc_port_speed == 10000) ? 48 : 44;
178 	base->sc_fifo_bufs.extra = 0;
179 	base->sc_fifo_bufs.num *= FMAN_BMI_FIFO_UNITS;
180 
181 	/* TODO: buf_margins?  See fman_sp_build_buffer_struct */
182 	return (0);
183 }
184 
185 static int
fman_port_tx_init_bmi(struct fman_port_tx_softc * sc)186 fman_port_tx_init_bmi(struct fman_port_tx_softc *sc)
187 {
188 	struct fman_port_softc *base = &sc->sc_base;
189 	uint32_t reg;
190 	int depth;
191 
192 	bus_write_4(base->sc_mem, FMBM_TCFG, 0);
193 	bus_write_4(base->sc_mem, FMBM_TDA, 0);
194 	bus_write_4(base->sc_mem, FMBM_TFED, 0);
195 
196 	if (base->sc_port_speed == 10000)
197 		depth = 4;
198 	else if (base->sc_revision_major >= 6)
199 		depth = 2;
200 	else
201 		depth = 1;
202 	sc->sc_tx_deq_pipeline_depth = depth;
203 	reg = ((depth - 1) << BMI_FIFO_PIPELINE_DEPTH_SHIFT) | 0x13;
204 	bus_write_4(base->sc_mem, FMBM_TFP, reg);
205 
206 	/* Default color: green */
207 	bus_write_4(base->sc_mem, FMBM_TFCA, TFCA_MR_DEF | TFCA_ATTR_ORDER);
208 
209 	bus_write_4(base->sc_mem, FMBM_TFDNE, NIA_ENG_QMI_DEQ);
210 	bus_write_4(base->sc_mem, FMBM_TFENE,
211 	    NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE);
212 
213 	/* Insert internal context ahead of the frame */
214 	reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << TICP_ICIOF_S;
215 	reg |= howmany(sizeof(struct fman_internal_context), 0x10);
216 	bus_write_4(base->sc_mem, FMBM_TICP, reg);
217 
218 	if (base->sc_revision_major >= 6)
219 		bus_write_4(base->sc_mem, FMBM_TFNE,
220 		    (base->sc_default_fqid == 0 ? TFNE_EBD : 0) |
221 		    NIA_BMI_AC_FETCH_ALLFRAME);
222 	bus_write_4(base->sc_mem, FMBM_TCFQID, base->sc_default_fqid);
223 	bus_write_4(base->sc_mem, FMBM_TEFQID, base->sc_err_fqid);
224 
225 	return (0);
226 }
227 
228 static int
fman_port_tx_init_qmi(struct fman_port_tx_softc * sc)229 fman_port_tx_init_qmi(struct fman_port_tx_softc *sc)
230 {
231 	struct fman_port_softc *base = &sc->sc_base;
232 	uint32_t reg;
233 
234 	bus_write_4(base->sc_mem, FMQM_PNDN, NIA_ENG_BMI | NIA_BMI_AC_TX);
235 	bus_write_4(base->sc_mem, FMQM_PNEN,
236 	    NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE);
237 
238 	reg = 0;
239 	if (sc->sc_deq_high_priority)
240 		reg |= QMI_DEQ_CFG_PRI;
241 	reg |= QMI_DEQ_CFG_TYPE1;
242 	reg |= QMI_DEQ_CFG_PREFETCH_FULL;
243 	reg |= (sc->sc_qman_channel_id & QMI_DEQ_CFG_SP_MASK) <<
244 	    QMI_DEQ_CFG_SP_SHIFT;
245 	reg |= sc->sc_deq_byte_count;
246 	bus_write_4(base->sc_mem, FMQM_PNDC, reg);
247 
248 	return (0);
249 }
250 
251 static int
fman_port_tx_init(device_t dev)252 fman_port_tx_init(device_t dev)
253 {
254 	struct fman_port_tx_softc *sc = device_get_softc(dev);
255 	struct fman_port_softc *base = &sc->sc_base;
256 	struct fman_port_init_params params;
257 	int err;
258 
259 	params.port_id = base->sc_port_id;
260 	params.is_rx_port = false;
261 	params.num_tasks = base->sc_tasks.num;
262 	params.extra_tasks = base->sc_tasks.extra;
263 	params.open_dmas = base->sc_open_dmas.num;
264 	params.extra_dmas = base->sc_open_dmas.extra;
265 	params.fifo_size = base->sc_fifo_bufs.num;
266 	params.extra_fifo_size = base->sc_fifo_bufs.extra;
267 	params.max_frame_length = base->sc_max_frame_length;
268 	params.deq_pipeline_size = sc->sc_tx_deq_pipeline_depth;
269 
270 	/* TODO: verify_size_of_fifo() from Linux driver */
271 	err = FMAN_SET_PORT_PARAMS(device_get_parent(dev), &params);
272 	if (err != 0)
273 		return (err);
274 
275 	err = fman_port_tx_init_bmi(sc);
276 	if (err != 0)
277 		return (err);
278 
279 	return (fman_port_tx_init_qmi(sc));
280 }
281 
282 static int
fman_port_tx_disable(device_t dev)283 fman_port_tx_disable(device_t dev)
284 {
285 	struct fman_port_tx_softc *sc = device_get_softc(dev);
286 	struct fman_port_softc *base = &sc->sc_base;
287 	uint32_t reg;
288 	int count;
289 
290 	reg = bus_read_4(base->sc_mem, FMQM_PNC);
291 	bus_write_4(base->sc_mem, FMQM_PNC, reg & ~PNC_EN);
292 	for (count = 0; count < 100; count++) {
293 		DELAY(10);
294 		reg = bus_read_4(base->sc_mem, FMQM_PNS);
295 		if (!(reg & PNS_DEQ_FD_BSY))
296 			break;
297 	}
298 	if (count == 100)
299 		device_printf(base->sc_dev, "Timeout stopping QMI\n");
300 
301 	reg = bus_read_4(base->sc_mem, FMBM_TCFG);
302 	bus_write_4(base->sc_mem, FMBM_TCFG, reg & ~BMI_PORT_CFG_EN);
303 	for (count = 0; count < 100; count++) {
304 		DELAY(10);
305 		reg = bus_read_4(base->sc_mem, FMBM_TST);
306 		if (!(reg & PNS_DEQ_FD_BSY))
307 			break;
308 	}
309 	if (count == 100)
310 		device_printf(base->sc_dev, "Timeout stopping BMI\n");
311 
312 	return (0);
313 }
314 
315 static int
fman_port_tx_enable(device_t dev)316 fman_port_tx_enable(device_t dev)
317 {
318 	struct fman_port_tx_softc *sc = device_get_softc(dev);
319 	struct fman_port_softc *base = &sc->sc_base;
320 	uint32_t reg;
321 
322 	reg = bus_read_4(base->sc_mem, FMQM_PNC);
323 	bus_write_4(base->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN);
324 
325 	reg = bus_read_4(base->sc_mem, FMBM_TCFG);
326 	bus_write_4(base->sc_mem, FMBM_TCFG, reg | BMI_PORT_CFG_EN);
327 
328 	return (0);
329 }
330 
331 static device_method_t fman_port_tx_methods[] = {
332 	DEVMETHOD(device_probe,		fman_port_tx_probe),
333 	DEVMETHOD(device_attach,	fman_port_tx_attach),
334 	DEVMETHOD(device_detach,	fman_port_tx_detach),
335 
336 	DEVMETHOD(fman_port_config,	fman_port_tx_config),
337 	DEVMETHOD(fman_port_init,	fman_port_tx_init),
338 	DEVMETHOD(fman_port_enable,	fman_port_tx_enable),
339 	DEVMETHOD(fman_port_disable,	fman_port_tx_disable),
340 
341 	DEVMETHOD_END
342 };
343 
344 DEFINE_CLASS_0(fman_port_tx, fman_port_tx_driver, fman_port_tx_methods,
345     sizeof(struct fman_port_tx_softc));
346 EARLY_DRIVER_MODULE(fman_port_tx, fman, fman_port_tx_driver, 0, 0,
347     BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
348