1 /*-
2 * Copyright (c) 2011-2012 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/module.h>
31 #include <sys/bus.h>
32 #include <sys/rman.h>
33 #include <sys/malloc.h>
34
35 #include <dev/fdt/simplebus.h>
36 #include <dev/ofw/ofw_bus.h>
37 #include <dev/ofw/ofw_bus_subr.h>
38
39 #include <machine/bus.h>
40
41 #include "opt_platform.h"
42
43 #include <contrib/ncsw/inc/Peripherals/fm_ext.h>
44 #include <contrib/ncsw/inc/Peripherals/fm_muram_ext.h>
45 #include <contrib/ncsw/inc/ncsw_ext.h>
46 #include <contrib/ncsw/integrations/fman_ucode.h>
47
48 #include "fman.h"
49
50
51 static MALLOC_DEFINE(M_FMAN, "fman", "fman devices information");
52
53 /**
54 * @group FMan private defines.
55 * @{
56 */
57 enum fman_irq_enum {
58 FMAN_IRQ_NUM = 0,
59 FMAN_ERR_IRQ_NUM = 1
60 };
61
62 enum fman_mu_ram_map {
63 FMAN_MURAM_OFF = 0x0,
64 FMAN_MURAM_SIZE = 0x28000
65 };
66
67 struct fman_config {
68 device_t fman_device;
69 uintptr_t mem_base_addr;
70 uintptr_t irq_num;
71 uintptr_t err_irq_num;
72 uint8_t fm_id;
73 t_FmExceptionsCallback *exception_callback;
74 t_FmBusErrorCallback *bus_error_callback;
75 };
76
77 /**
78 * @group FMan private methods/members.
79 * @{
80 */
81 /**
82 * Frame Manager firmware.
83 * We use the same firmware for both P3041 and P2041 devices.
84 */
85 const uint32_t fman_firmware[] = FMAN_UC_IMG;
86 const uint32_t fman_firmware_size = sizeof(fman_firmware);
87
88 int
fman_activate_resource(device_t bus,device_t child,struct resource * res)89 fman_activate_resource(device_t bus, device_t child, struct resource *res)
90 {
91 struct fman_softc *sc;
92 bus_space_tag_t bt;
93 bus_space_handle_t bh;
94 int i, rv;
95
96 sc = device_get_softc(bus);
97 if (rman_get_type(res) != SYS_RES_IRQ) {
98 for (i = 0; i < sc->sc_base.nranges; i++) {
99 if (rman_is_region_manager(res, &sc->rman) != 0) {
100 bt = rman_get_bustag(sc->mem_res);
101 rv = bus_space_subregion(bt,
102 rman_get_bushandle(sc->mem_res),
103 rman_get_start(res) -
104 rman_get_start(sc->mem_res),
105 rman_get_size(res), &bh);
106 if (rv != 0)
107 return (rv);
108 rman_set_bustag(res, bt);
109 rman_set_bushandle(res, bh);
110 return (rman_activate_resource(res));
111 }
112 }
113 return (EINVAL);
114 }
115 return (bus_generic_activate_resource(bus, child, res));
116 }
117
118 int
fman_release_resource(device_t bus,device_t child,struct resource * res)119 fman_release_resource(device_t bus, device_t child, struct resource *res)
120 {
121 struct resource_list *rl;
122 struct resource_list_entry *rle;
123 int passthrough, rv;
124
125 passthrough = (device_get_parent(child) != bus);
126 rl = BUS_GET_RESOURCE_LIST(bus, child);
127 if (rman_get_type(res) != SYS_RES_IRQ) {
128 if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){
129 rv = bus_deactivate_resource(child, res);
130 if (rv != 0)
131 return (rv);
132 }
133 rv = rman_release_resource(res);
134 if (rv != 0)
135 return (rv);
136 if (!passthrough) {
137 rle = resource_list_find(rl, rman_get_type(res),
138 rman_get_rid(res));
139 KASSERT(rle != NULL,
140 ("%s: resource entry not found!", __func__));
141 KASSERT(rle->res != NULL,
142 ("%s: resource entry is not busy", __func__));
143 rle->res = NULL;
144 }
145 return (0);
146 }
147 return (resource_list_release(rl, bus, child, res));
148 }
149
150 struct resource *
fman_alloc_resource(device_t bus,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)151 fman_alloc_resource(device_t bus, device_t child, int type, int *rid,
152 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
153 {
154 struct fman_softc *sc;
155 struct resource_list *rl;
156 struct resource_list_entry *rle = NULL;
157 struct resource *res;
158 int i, isdefault, passthrough;
159
160 isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
161 passthrough = (device_get_parent(child) != bus);
162 sc = device_get_softc(bus);
163 rl = BUS_GET_RESOURCE_LIST(bus, child);
164 switch (type) {
165 case SYS_RES_MEMORY:
166 KASSERT(!(isdefault && passthrough),
167 ("%s: passthrough of default allocation", __func__));
168 if (!passthrough) {
169 rle = resource_list_find(rl, type, *rid);
170 if (rle == NULL)
171 return (NULL);
172 KASSERT(rle->res == NULL,
173 ("%s: resource entry is busy", __func__));
174 if (isdefault) {
175 start = rle->start;
176 count = ulmax(count, rle->count);
177 end = ulmax(rle->end, start + count - 1);
178 }
179 }
180
181 res = NULL;
182 /* Map fman ranges to nexus ranges. */
183 for (i = 0; i < sc->sc_base.nranges; i++) {
184 if (start >= sc->sc_base.ranges[i].bus && end <
185 sc->sc_base.ranges[i].bus + sc->sc_base.ranges[i].size) {
186 start += rman_get_start(sc->mem_res);
187 end += rman_get_start(sc->mem_res);
188 res = rman_reserve_resource(&sc->rman, start,
189 end, count, flags & ~RF_ACTIVE, child);
190 if (res == NULL)
191 return (NULL);
192 rman_set_rid(res, *rid);
193 rman_set_type(res, type);
194 if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(
195 child, type, *rid, res) != 0) {
196 rman_release_resource(res);
197 return (NULL);
198 }
199 break;
200 }
201 }
202 if (!passthrough)
203 rle->res = res;
204 return (res);
205 case SYS_RES_IRQ:
206 return (resource_list_alloc(rl, bus, child, type, rid, start,
207 end, count, flags));
208 }
209 return (NULL);
210 }
211
212 static int
fman_fill_ranges(phandle_t node,struct simplebus_softc * sc)213 fman_fill_ranges(phandle_t node, struct simplebus_softc *sc)
214 {
215 int host_address_cells;
216 cell_t *base_ranges;
217 ssize_t nbase_ranges;
218 int err;
219 int i, j, k;
220
221 err = OF_searchencprop(OF_parent(node), "#address-cells",
222 &host_address_cells, sizeof(host_address_cells));
223 if (err <= 0)
224 return (-1);
225
226 nbase_ranges = OF_getproplen(node, "ranges");
227 if (nbase_ranges < 0)
228 return (-1);
229 sc->nranges = nbase_ranges / sizeof(cell_t) /
230 (sc->acells + host_address_cells + sc->scells);
231 if (sc->nranges == 0)
232 return (0);
233
234 sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
235 M_DEVBUF, M_WAITOK);
236 base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
237 OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
238
239 for (i = 0, j = 0; i < sc->nranges; i++) {
240 sc->ranges[i].bus = 0;
241 for (k = 0; k < sc->acells; k++) {
242 sc->ranges[i].bus <<= 32;
243 sc->ranges[i].bus |= base_ranges[j++];
244 }
245 sc->ranges[i].host = 0;
246 for (k = 0; k < host_address_cells; k++) {
247 sc->ranges[i].host <<= 32;
248 sc->ranges[i].host |= base_ranges[j++];
249 }
250 sc->ranges[i].size = 0;
251 for (k = 0; k < sc->scells; k++) {
252 sc->ranges[i].size <<= 32;
253 sc->ranges[i].size |= base_ranges[j++];
254 }
255 }
256
257 free(base_ranges, M_DEVBUF);
258 return (sc->nranges);
259 }
260
261 static t_Handle
fman_init(struct fman_softc * sc,struct fman_config * cfg)262 fman_init(struct fman_softc *sc, struct fman_config *cfg)
263 {
264 phandle_t node;
265 t_FmParams fm_params;
266 t_Handle muram_handle, fm_handle;
267 t_Error error;
268 t_FmRevisionInfo revision_info;
269 uint16_t clock;
270 uint32_t tmp, mod;
271
272 /* MURAM configuration */
273 muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr +
274 FMAN_MURAM_OFF, FMAN_MURAM_SIZE);
275 if (muram_handle == NULL) {
276 device_printf(cfg->fman_device, "couldn't init FM MURAM module"
277 "\n");
278 return (NULL);
279 }
280 sc->muram_handle = muram_handle;
281
282 /* Fill in FM configuration */
283 fm_params.fmId = cfg->fm_id;
284 /* XXX we support only one partition thus each fman has master id */
285 fm_params.guestId = NCSW_MASTER_ID;
286
287 fm_params.baseAddr = cfg->mem_base_addr;
288 fm_params.h_FmMuram = muram_handle;
289
290 /* Get FMan clock in Hz */
291 if ((tmp = fman_get_clock(sc)) == 0)
292 return (NULL);
293
294 /* Convert FMan clock to MHz */
295 clock = (uint16_t)(tmp / 1000000);
296 mod = tmp % 1000000;
297
298 if (mod >= 500000)
299 ++clock;
300
301 fm_params.fmClkFreq = clock;
302 fm_params.f_Exception = cfg->exception_callback;
303 fm_params.f_BusError = cfg->bus_error_callback;
304 fm_params.h_App = cfg->fman_device;
305 fm_params.irq = cfg->irq_num;
306 fm_params.errIrq = cfg->err_irq_num;
307
308 fm_params.firmware.size = fman_firmware_size;
309 fm_params.firmware.p_Code = (uint32_t*)fman_firmware;
310
311 fm_handle = FM_Config(&fm_params);
312 if (fm_handle == NULL) {
313 device_printf(cfg->fman_device, "couldn't configure FM "
314 "module\n");
315 goto err;
316 }
317
318 FM_ConfigResetOnInit(fm_handle, TRUE);
319
320 error = FM_Init(fm_handle);
321 if (error != E_OK) {
322 device_printf(cfg->fman_device, "couldn't init FM module\n");
323 goto err2;
324 }
325
326 error = FM_GetRevision(fm_handle, &revision_info);
327 if (error != E_OK) {
328 device_printf(cfg->fman_device, "couldn't get FM revision\n");
329 goto err2;
330 }
331
332 device_printf(cfg->fman_device, "Hardware version: %d.%d.\n",
333 revision_info.majorRev, revision_info.minorRev);
334
335 /* Initialize the simplebus part of things */
336 simplebus_init(sc->sc_base.dev, 0);
337
338 node = ofw_bus_get_node(sc->sc_base.dev);
339 fman_fill_ranges(node, &sc->sc_base);
340 sc->rman.rm_type = RMAN_ARRAY;
341 sc->rman.rm_descr = "FMan range";
342 rman_init_from_resource(&sc->rman, sc->mem_res);
343 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
344 simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL);
345 }
346
347 return (fm_handle);
348
349 err2:
350 FM_Free(fm_handle);
351 err:
352 FM_MURAM_Free(muram_handle);
353 return (NULL);
354 }
355
356 static void
fman_exception_callback(t_Handle app_handle,e_FmExceptions exception)357 fman_exception_callback(t_Handle app_handle, e_FmExceptions exception)
358 {
359 struct fman_softc *sc;
360
361 sc = app_handle;
362 device_printf(sc->sc_base.dev, "FMan exception occurred.\n");
363 }
364
365 static void
fman_error_callback(t_Handle app_handle,e_FmPortType port_type,uint8_t port_id,uint64_t addr,uint8_t tnum,uint16_t liodn)366 fman_error_callback(t_Handle app_handle, e_FmPortType port_type,
367 uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn)
368 {
369 struct fman_softc *sc;
370
371 sc = app_handle;
372 device_printf(sc->sc_base.dev, "FMan error occurred.\n");
373 }
374 /** @} */
375
376
377 /**
378 * @group FMan driver interface.
379 * @{
380 */
381
382 int
fman_get_handle(device_t dev,t_Handle * fmh)383 fman_get_handle(device_t dev, t_Handle *fmh)
384 {
385 struct fman_softc *sc = device_get_softc(dev);
386
387 *fmh = sc->fm_handle;
388
389 return (0);
390 }
391
392 int
fman_get_muram_handle(device_t dev,t_Handle * muramh)393 fman_get_muram_handle(device_t dev, t_Handle *muramh)
394 {
395 struct fman_softc *sc = device_get_softc(dev);
396
397 *muramh = sc->muram_handle;
398
399 return (0);
400 }
401
402 int
fman_get_bushandle(device_t dev,vm_offset_t * fm_base)403 fman_get_bushandle(device_t dev, vm_offset_t *fm_base)
404 {
405 struct fman_softc *sc = device_get_softc(dev);
406
407 *fm_base = rman_get_bushandle(sc->mem_res);
408
409 return (0);
410 }
411
412 int
fman_attach(device_t dev)413 fman_attach(device_t dev)
414 {
415 struct fman_softc *sc;
416 struct fman_config cfg;
417 pcell_t qchan_range[2];
418 phandle_t node;
419
420 sc = device_get_softc(dev);
421 sc->sc_base.dev = dev;
422
423 /* Check if MallocSmart allocator is ready */
424 if (XX_MallocSmartInit() != E_OK) {
425 device_printf(dev, "could not initialize smart allocator.\n");
426 return (ENXIO);
427 }
428
429 node = ofw_bus_get_node(dev);
430 if (OF_getencprop(node, "fsl,qman-channel-range", qchan_range,
431 sizeof(qchan_range)) <= 0) {
432 device_printf(dev, "Missing QMan channel range property!\n");
433 return (ENXIO);
434 }
435 sc->qman_chan_base = qchan_range[0];
436 sc->qman_chan_count = qchan_range[1];
437 sc->mem_rid = 0;
438 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
439 RF_ACTIVE | RF_SHAREABLE);
440 if (!sc->mem_res) {
441 device_printf(dev, "could not allocate memory.\n");
442 return (ENXIO);
443 }
444
445 sc->irq_rid = 0;
446 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
447 RF_ACTIVE);
448 if (!sc->irq_res) {
449 device_printf(dev, "could not allocate interrupt.\n");
450 goto err;
451 }
452
453 sc->err_irq_rid = 1;
454 sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
455 &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE);
456 if (!sc->err_irq_res) {
457 device_printf(dev, "could not allocate error interrupt.\n");
458 goto err;
459 }
460
461 /* Set FMan configuration */
462 cfg.fman_device = dev;
463 cfg.fm_id = device_get_unit(dev);
464 cfg.mem_base_addr = rman_get_bushandle(sc->mem_res);
465 cfg.irq_num = (uintptr_t)sc->irq_res;
466 cfg.err_irq_num = (uintptr_t)sc->err_irq_res;
467 cfg.exception_callback = fman_exception_callback;
468 cfg.bus_error_callback = fman_error_callback;
469
470 sc->fm_handle = fman_init(sc, &cfg);
471 if (sc->fm_handle == NULL) {
472 device_printf(dev, "could not be configured\n");
473 goto err;
474 }
475
476 return (bus_generic_attach(dev));
477
478 err:
479 fman_detach(dev);
480 return (ENXIO);
481 }
482
483 int
fman_detach(device_t dev)484 fman_detach(device_t dev)
485 {
486 struct fman_softc *sc;
487
488 sc = device_get_softc(dev);
489
490 if (sc->muram_handle) {
491 FM_MURAM_Free(sc->muram_handle);
492 }
493
494 if (sc->fm_handle) {
495 FM_Free(sc->fm_handle);
496 }
497
498 if (sc->mem_res) {
499 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
500 sc->mem_res);
501 }
502
503 if (sc->irq_res) {
504 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
505 sc->irq_res);
506 }
507
508 if (sc->irq_res) {
509 bus_release_resource(dev, SYS_RES_IRQ, sc->err_irq_rid,
510 sc->err_irq_res);
511 }
512
513 return (0);
514 }
515
516 int
fman_suspend(device_t dev)517 fman_suspend(device_t dev)
518 {
519
520 return (0);
521 }
522
523 int
fman_resume_dev(device_t dev)524 fman_resume_dev(device_t dev)
525 {
526
527 return (0);
528 }
529
530 int
fman_shutdown(device_t dev)531 fman_shutdown(device_t dev)
532 {
533
534 return (0);
535 }
536
537 int
fman_qman_channel_id(device_t dev,int port)538 fman_qman_channel_id(device_t dev, int port)
539 {
540 struct fman_softc *sc;
541 int qman_port_id[] = {0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
542 0x2f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
543 int i;
544
545 sc = device_get_softc(dev);
546 for (i = 0; i < sc->qman_chan_count; i++) {
547 if (qman_port_id[i] == port)
548 return (sc->qman_chan_base + i);
549 }
550
551 return (0);
552 }
553
554 /** @} */
555