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 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 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 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 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 bool fman_v3 = (base->sc_revision_major >= 6); 141 142 fman_port_config_common(base, params); 143 144 if (base->sc_revision_major >= 6 && base->sc_port_speed == 1000) 145 /* Errata A005127 workaround */ 146 bus_write_4(base->sc_mem, FMBM_TFP, 0x00001013); 147 148 base->sc_tasks.extra = 0; 149 base->sc_open_dmas.extra = 0; 150 base->sc_fifo_bufs.extra = 0; 151 switch (base->sc_port_speed) { 152 case 10000: 153 base->sc_tasks.num = fman_v3 ? 14 : 16; 154 base->sc_open_dmas.num = fman_v3 ? 12 : 8; 155 base->sc_fifo_bufs.num = fman_v3 ? 64 : 48; 156 break; 157 case 1000: 158 base->sc_tasks.num = fman_v3 ? 4 : 3; 159 base->sc_open_dmas.num = fman_v3 ? 3 : 1; 160 base->sc_fifo_bufs.num = fman_v3 ? 50 : 44; 161 break; 162 default: 163 base->sc_tasks.num = 0; 164 break; 165 } 166 167 base->sc_fifo_bufs.num *= FMAN_BMI_FIFO_UNITS; 168 169 /* TODO: buf_margins? See fman_sp_build_buffer_struct */ 170 return (0); 171 } 172 173 static int 174 fman_port_tx_init_bmi(struct fman_port_tx_softc *sc) 175 { 176 struct fman_port_softc *base = &sc->sc_base; 177 uint32_t reg; 178 int depth; 179 180 bus_write_4(base->sc_mem, FMBM_TCFG, 0); 181 bus_write_4(base->sc_mem, FMBM_TDA, 0); 182 bus_write_4(base->sc_mem, FMBM_TFED, 0); 183 184 if (base->sc_port_speed == 10000) 185 depth = 4; 186 else if (base->sc_revision_major >= 6) 187 depth = 2; 188 else 189 depth = 1; 190 sc->sc_tx_deq_pipeline_depth = depth; 191 reg = ((depth - 1) << BMI_FIFO_PIPELINE_DEPTH_SHIFT) | 0x13; 192 bus_write_4(base->sc_mem, FMBM_TFP, reg); 193 194 /* Default color: green */ 195 bus_write_4(base->sc_mem, FMBM_TFCA, TFCA_MR_DEF | TFCA_ATTR_ORDER); 196 197 bus_write_4(base->sc_mem, FMBM_TFDNE, NIA_ENG_QMI_DEQ); 198 bus_write_4(base->sc_mem, FMBM_TFENE, 199 NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE); 200 201 /* Insert internal context ahead of the frame */ 202 reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << TICP_ICIOF_S; 203 reg |= howmany(sizeof(struct fman_internal_context), 0x10); 204 bus_write_4(base->sc_mem, FMBM_TICP, reg); 205 206 if (base->sc_revision_major >= 6) 207 bus_write_4(base->sc_mem, FMBM_TFNE, 208 (base->sc_default_fqid == 0 ? TFNE_EBD : 0) | 209 NIA_BMI_AC_FETCH_ALLFRAME); 210 bus_write_4(base->sc_mem, FMBM_TCFQID, base->sc_default_fqid); 211 bus_write_4(base->sc_mem, FMBM_TEFQID, base->sc_err_fqid); 212 213 return (0); 214 } 215 216 static int 217 fman_port_tx_init_qmi(struct fman_port_tx_softc *sc) 218 { 219 struct fman_port_softc *base = &sc->sc_base; 220 uint32_t reg; 221 222 bus_write_4(base->sc_mem, FMQM_PNDN, NIA_ENG_BMI | NIA_BMI_AC_TX); 223 bus_write_4(base->sc_mem, FMQM_PNEN, 224 NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); 225 226 reg = 0; 227 if (sc->sc_deq_high_priority) 228 reg |= QMI_DEQ_CFG_PRI; 229 reg |= QMI_DEQ_CFG_TYPE1; 230 reg |= QMI_DEQ_CFG_PREFETCH_FULL; 231 reg |= (sc->sc_qman_channel_id & QMI_DEQ_CFG_SP_MASK) << 232 QMI_DEQ_CFG_SP_SHIFT; 233 reg |= sc->sc_deq_byte_count; 234 bus_write_4(base->sc_mem, FMQM_PNDC, reg); 235 236 return (0); 237 } 238 239 static int 240 fman_port_tx_init(device_t dev) 241 { 242 struct fman_port_tx_softc *sc = device_get_softc(dev); 243 struct fman_port_softc *base = &sc->sc_base; 244 struct fman_port_init_params params; 245 int err; 246 247 params.port_id = base->sc_port_id; 248 params.is_rx_port = false; 249 params.num_tasks = base->sc_tasks.num; 250 params.extra_tasks = base->sc_tasks.extra; 251 params.open_dmas = base->sc_open_dmas.num; 252 params.extra_dmas = base->sc_open_dmas.extra; 253 params.fifo_size = base->sc_fifo_bufs.num; 254 params.extra_fifo_size = base->sc_fifo_bufs.extra; 255 params.max_frame_length = base->sc_max_frame_length; 256 params.deq_pipeline_size = sc->sc_tx_deq_pipeline_depth; 257 258 /* TODO: verify_size_of_fifo() from Linux driver */ 259 err = FMAN_SET_PORT_PARAMS(device_get_parent(dev), ¶ms); 260 if (err != 0) 261 return (err); 262 263 err = fman_port_tx_init_bmi(sc); 264 if (err != 0) 265 return (err); 266 267 return (fman_port_tx_init_qmi(sc)); 268 } 269 270 static int 271 fman_port_tx_disable(device_t dev) 272 { 273 struct fman_port_tx_softc *sc = device_get_softc(dev); 274 struct fman_port_softc *base = &sc->sc_base; 275 uint32_t reg; 276 int count; 277 278 reg = bus_read_4(base->sc_mem, FMQM_PNC); 279 bus_write_4(base->sc_mem, FMQM_PNC, reg & ~PNC_EN); 280 for (count = 0; count < 100; count++) { 281 DELAY(10); 282 reg = bus_read_4(base->sc_mem, FMQM_PNS); 283 if (!(reg & PNS_DEQ_FD_BSY)) 284 break; 285 } 286 if (count == 100) 287 device_printf(base->sc_dev, "Timeout stopping QMI\n"); 288 289 reg = bus_read_4(base->sc_mem, FMBM_TCFG); 290 bus_write_4(base->sc_mem, FMBM_TCFG, reg & ~BMI_PORT_CFG_EN); 291 for (count = 0; count < 100; count++) { 292 DELAY(10); 293 reg = bus_read_4(base->sc_mem, FMBM_TST); 294 if (!(reg & PNS_DEQ_FD_BSY)) 295 break; 296 } 297 if (count == 100) 298 device_printf(base->sc_dev, "Timeout stopping BMI\n"); 299 300 return (0); 301 } 302 303 static int 304 fman_port_tx_enable(device_t dev) 305 { 306 struct fman_port_tx_softc *sc = device_get_softc(dev); 307 struct fman_port_softc *base = &sc->sc_base; 308 uint32_t reg; 309 310 reg = bus_read_4(base->sc_mem, FMQM_PNC); 311 bus_write_4(base->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN); 312 313 reg = bus_read_4(base->sc_mem, FMBM_TCFG); 314 bus_write_4(base->sc_mem, FMBM_TCFG, reg | BMI_PORT_CFG_EN); 315 316 return (0); 317 } 318 319 static device_method_t fman_port_tx_methods[] = { 320 DEVMETHOD(device_probe, fman_port_tx_probe), 321 DEVMETHOD(device_attach, fman_port_tx_attach), 322 DEVMETHOD(device_detach, fman_port_tx_detach), 323 324 DEVMETHOD(fman_port_config, fman_port_tx_config), 325 DEVMETHOD(fman_port_init, fman_port_tx_init), 326 DEVMETHOD(fman_port_enable, fman_port_tx_enable), 327 DEVMETHOD(fman_port_disable, fman_port_tx_disable), 328 329 DEVMETHOD_END 330 }; 331 332 DEFINE_CLASS_0(fman_port_tx, fman_port_tx_driver, fman_port_tx_methods, 333 sizeof(struct fman_port_tx_softc)); 334 EARLY_DRIVER_MODULE(fman_port_tx, fman, fman_port_tx_driver, 0, 0, 335 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 336